DATAJDBC-637 - Fix tests for all databases.

Adds SQL scripts for all databases.
Separates tests for all databases vs. those that actually support nanosecond precision.

Original pull request: #255.
This commit is contained in:
Jens Schauder
2020-12-09 09:03:46 +01:00
parent 9f0f930e80
commit 71b6a79cab
9 changed files with 519 additions and 2 deletions

View File

@@ -853,11 +853,26 @@ public class JdbcAggregateTemplateIntegrationTests {
}
@Test // DATAJDBC-637
@EnabledOnFeature(SUPPORTS_NANOSECOND_PRECISION)
public void saveAndLoadDateTimeWithFullPrecision() {
WithLocalDateTime entity = new WithLocalDateTime();
entity.id = 23L;
entity.testTime = LocalDateTime.of(5, 5, 5, 5, 5, 5, 123456789);
entity.testTime = LocalDateTime.of(2005, 5, 5, 5, 5, 5, 123456789);
template.insert(entity);
WithLocalDateTime loaded = template.findById(23L, WithLocalDateTime.class);
assertThat(loaded.testTime).isEqualTo(entity.testTime);
}
@Test // DATAJDBC-637
public void saveAndLoadDateTimeWithMicrosecondPrecision() {
WithLocalDateTime entity = new WithLocalDateTime();
entity.id = 23L;
entity.testTime = LocalDateTime.of(2005, 5, 5, 5, 5, 5, 123456000);
template.insert(entity);

View File

@@ -0,0 +1,130 @@
/*
* Copyright 2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.jdbc.testing;
import static org.assertj.core.api.Assumptions.*;
import java.util.Arrays;
import java.util.Locale;
import java.util.function.Consumer;
import org.springframework.jdbc.core.ConnectionCallback;
import org.springframework.jdbc.core.JdbcOperations;
/**
* This class provides information about which features a database integration supports in order to react on the
* presence or absence of features in tests.
*
* @author Jens Schauder
*/
public class TestDatabaseFeatures {
private final Database database;
public TestDatabaseFeatures(JdbcOperations jdbcTemplate) {
String productName = jdbcTemplate.execute(
(ConnectionCallback<String>) c -> c.getMetaData().getDatabaseProductName().toLowerCase(Locale.ENGLISH));
database = Arrays.stream(Database.values()).filter(db -> db.matches(productName)).findFirst().get();
}
/**
* Not all databases support really huge numbers as represented by {@link java.math.BigDecimal} and similar.
*/
private void supportsHugeNumbers() {
assumeThat(database).isNotIn(Database.Oracle, Database.SqlServer);
}
/**
* Oracles JDBC driver seems to have a bug that makes it impossible to acquire generated keys when the column is
* quoted. See
* https://stackoverflow.com/questions/62263576/how-to-get-the-generated-key-for-a-column-with-lowercase-characters-from-oracle
*/
private void supportsQuotedIds() {
assumeThat(database).isNotEqualTo(Database.Oracle);
}
/**
* Microsoft SqlServer does not allow explicitly setting ids in columns where the value gets generated by the
* database. Such columns therefore must not be used in referenced entities, since we do a delete and insert, which
* must not recreate an id. See https://jira.spring.io/browse/DATAJDBC-210
*/
private void supportsGeneratedIdsInReferencedEntities() {
assumeThat(database).isNotEqualTo(Database.SqlServer);
}
private void supportsArrays() {
assumeThat(database).isNotIn(Database.MySql, Database.MariaDb, Database.SqlServer, Database.Db2, Database.Oracle);
}
private void supportsNanosecondPrecision() {
assumeThat(database).isNotIn(Database.MySql, Database.PostgreSql, Database.MariaDb, Database.SqlServer);
}
private void supportsMultiDimensionalArrays() {
supportsArrays();
assumeThat(database).isNotIn(Database.H2, Database.Hsql);
}
public void databaseIs(Database database) {
assumeThat(this.database).isEqualTo(database);
}
public enum Database {
Hsql, H2, MySql, MariaDb, PostgreSql, SqlServer("microsoft"), Db2, Oracle;
private final String identification;
Database(String identification) {
this.identification = identification;
}
Database() {
this.identification = null;
}
boolean matches(String productName) {
String identification = this.identification == null ? name().toLowerCase() : this.identification;
return productName.contains(identification);
}
}
public enum Feature {
SUPPORTS_MULTIDIMENSIONAL_ARRAYS(TestDatabaseFeatures::supportsMultiDimensionalArrays), //
SUPPORTS_QUOTED_IDS(TestDatabaseFeatures::supportsQuotedIds), //
SUPPORTS_HUGE_NUMBERS(TestDatabaseFeatures::supportsHugeNumbers), //
SUPPORTS_ARRAYS(TestDatabaseFeatures::supportsArrays), //
SUPPORTS_GENERATED_IDS_IN_REFERENCED_ENTITIES(TestDatabaseFeatures::supportsGeneratedIdsInReferencedEntities), //
SUPPORTS_NANOSECOND_PRECISION(TestDatabaseFeatures::supportsNanosecondPrecision), //
IS_HSQL(f -> f.databaseIs(Database.Hsql));
private final Consumer<TestDatabaseFeatures> featureMethod;
Feature(Consumer<TestDatabaseFeatures> featureMethod) {
this.featureMethod = featureMethod;
}
void test(TestDatabaseFeatures features) {
featureMethod.accept(features);
}
}
}

View File

@@ -35,6 +35,7 @@ DROP TABLE NO_ID_LIST_CHAIN4;
DROP TABLE WITH_READ_ONLY;
DROP TABLE VERSIONED_AGGREGATE;
DROP TABLE WITH_LOCAL_DATE_TIME;
CREATE TABLE LEGO_SET
(
@@ -343,3 +344,10 @@ CREATE TABLE VERSIONED_AGGREGATE
ID BIGINT GENERATED BY DEFAULT AS IDENTITY (START WITH 1) PRIMARY KEY,
VERSION BIGINT
);
CREATE TABLE WITH_LOCAL_DATE_TIME
(
ID BIGINT NOT NULL PRIMARY KEY,
TEST_TIME TIMESTAMP(9)
);

View File

@@ -307,6 +307,6 @@ CREATE TABLE WITH_READ_ONLY
CREATE TABLE WITH_LOCAL_DATE_TIME
(
ID SERIAL PRIMARY KEY,
ID BIGINT PRIMARY KEY,
TEST_TIME TIMESTAMP(9) WITHOUT TIME ZONE
);

View File

@@ -290,3 +290,10 @@ CREATE TABLE VERSIONED_AGGREGATE
ID BIGINT AUTO_INCREMENT PRIMARY KEY,
VERSION BIGINT
);
CREATE TABLE WITH_LOCAL_DATE_TIME
(
ID BIGINT PRIMARY KEY,
TEST_TIME TIMESTAMP(6)
);

View File

@@ -298,3 +298,12 @@ CREATE TABLE VERSIONED_AGGREGATE
ID BIGINT IDENTITY PRIMARY KEY,
VERSION BIGINT
);
DROP TABLE IF EXISTS WITH_LOCAL_DATE_TIME;
CREATE TABLE WITH_LOCAL_DATE_TIME
(
ID BIGINT PRIMARY KEY,
TEST_TIME datetime2(7)
);

View File

@@ -295,3 +295,10 @@ CREATE TABLE WITH_READ_ONLY
NAME VARCHAR(200),
READ_ONLY VARCHAR(200) DEFAULT 'from-db'
);
CREATE TABLE WITH_LOCAL_DATE_TIME
(
ID BIGINT PRIMARY KEY,
TEST_TIME TIMESTAMP(6)
);

View File

@@ -0,0 +1,335 @@
DROP TABLE MANUAL CASCADE CONSTRAINTS PURGE;
DROP TABLE LEGO_SET CASCADE CONSTRAINTS PURGE;
DROP TABLE CHILD_NO_ID CASCADE CONSTRAINTS PURGE;
DROP TABLE ONE_TO_ONE_PARENT CASCADE CONSTRAINTS PURGE;
DROP TABLE ELEMENT_NO_ID CASCADE CONSTRAINTS PURGE;
DROP TABLE LIST_PARENT CASCADE CONSTRAINTS PURGE;
DROP TABLE BYTE_ARRAY_OWNER CASCADE CONSTRAINTS PURGE;
DROP TABLE CHAIN0 CASCADE CONSTRAINTS PURGE;
DROP TABLE CHAIN1 CASCADE CONSTRAINTS PURGE;
DROP TABLE CHAIN2 CASCADE CONSTRAINTS PURGE;
DROP TABLE CHAIN3 CASCADE CONSTRAINTS PURGE;
DROP TABLE CHAIN4 CASCADE CONSTRAINTS PURGE;
DROP TABLE NO_ID_CHAIN0 CASCADE CONSTRAINTS PURGE;
DROP TABLE NO_ID_CHAIN1 CASCADE CONSTRAINTS PURGE;
DROP TABLE NO_ID_CHAIN2 CASCADE CONSTRAINTS PURGE;
DROP TABLE NO_ID_CHAIN3 CASCADE CONSTRAINTS PURGE;
DROP TABLE NO_ID_CHAIN4 CASCADE CONSTRAINTS PURGE;
DROP TABLE NO_ID_LIST_CHAIN0 CASCADE CONSTRAINTS PURGE;
DROP TABLE NO_ID_LIST_CHAIN1 CASCADE CONSTRAINTS PURGE;
DROP TABLE NO_ID_LIST_CHAIN2 CASCADE CONSTRAINTS PURGE;
DROP TABLE NO_ID_LIST_CHAIN3 CASCADE CONSTRAINTS PURGE;
DROP TABLE NO_ID_LIST_CHAIN4 CASCADE CONSTRAINTS PURGE;
DROP TABLE NO_ID_MAP_CHAIN0 CASCADE CONSTRAINTS PURGE;
DROP TABLE NO_ID_MAP_CHAIN1 CASCADE CONSTRAINTS PURGE;
DROP TABLE NO_ID_MAP_CHAIN2 CASCADE CONSTRAINTS PURGE;
DROP TABLE NO_ID_MAP_CHAIN3 CASCADE CONSTRAINTS PURGE;
DROP TABLE NO_ID_MAP_CHAIN4 CASCADE CONSTRAINTS PURGE;
DROP TABLE VERSIONED_AGGREGATE CASCADE CONSTRAINTS PURGE;
DROP TABLE WITH_READ_ONLY CASCADE CONSTRAINTS PURGE;
DROP TABLE WITH_LOCAL_DATE_TIME CASCADE CONSTRAINTS PURGE;
CREATE TABLE LEGO_SET
(
"id1" NUMBER GENERATED by default on null as IDENTITY PRIMARY KEY,
NAME VARCHAR(30)
);
CREATE TABLE MANUAL
(
"id2" NUMBER GENERATED by default on null as IDENTITY PRIMARY KEY,
LEGO_SET NUMBER,
ALTERNATIVE NUMBER,
CONTENT VARCHAR(2000)
);
ALTER TABLE MANUAL
ADD FOREIGN KEY (LEGO_SET)
REFERENCES LEGO_SET ("id1");
CREATE TABLE ONE_TO_ONE_PARENT
(
"id3" NUMBER GENERATED by default on null as IDENTITY PRIMARY KEY,
content VARCHAR(30)
);
CREATE TABLE Child_No_Id
(
ONE_TO_ONE_PARENT INTEGER PRIMARY KEY,
"content" VARCHAR(30)
);
CREATE TABLE LIST_PARENT
(
"id4" NUMBER GENERATED by default on null as IDENTITY PRIMARY KEY,
NAME VARCHAR(100)
);
CREATE TABLE element_no_id
(
CONTENT VARCHAR(100),
LIST_PARENT_key NUMBER,
LIST_PARENT NUMBER
);
CREATE TABLE BYTE_ARRAY_OWNER
(
ID NUMBER GENERATED by default on null as IDENTITY PRIMARY KEY,
BINARY_DATA RAW(100) NOT NULL
);
CREATE TABLE CHAIN4
(
FOUR NUMBER GENERATED by default on null as IDENTITY PRIMARY KEY,
FOUR_VALUE VARCHAR(20)
);
CREATE TABLE CHAIN3
(
THREE NUMBER GENERATED by default on null as IDENTITY PRIMARY KEY,
THREE_VALUE VARCHAR(20),
CHAIN4 NUMBER,
FOREIGN KEY (CHAIN4) REFERENCES CHAIN4 (FOUR)
);
CREATE TABLE CHAIN2
(
TWO NUMBER GENERATED by default on null as IDENTITY PRIMARY KEY,
TWO_VALUE VARCHAR(20),
CHAIN3 NUMBER,
FOREIGN KEY (CHAIN3) REFERENCES CHAIN3 (THREE)
);
CREATE TABLE CHAIN1
(
ONE NUMBER GENERATED by default on null as IDENTITY PRIMARY KEY,
ONE_VALUE VARCHAR(20),
CHAIN2 NUMBER,
FOREIGN KEY (CHAIN2) REFERENCES CHAIN2 (TWO)
);
CREATE TABLE CHAIN0
(
ZERO NUMBER GENERATED by default on null as IDENTITY PRIMARY KEY,
ZERO_VALUE VARCHAR(20),
CHAIN1 NUMBER,
FOREIGN KEY (CHAIN1) REFERENCES CHAIN1 (ONE)
);
CREATE TABLE NO_ID_CHAIN4
(
FOUR NUMBER GENERATED by default on null as IDENTITY PRIMARY KEY,
FOUR_VALUE VARCHAR(20)
);
CREATE TABLE NO_ID_CHAIN3
(
THREE_VALUE VARCHAR(20),
NO_ID_CHAIN4 NUMBER,
FOREIGN KEY (NO_ID_CHAIN4) REFERENCES NO_ID_CHAIN4 (FOUR)
);
CREATE TABLE NO_ID_CHAIN2
(
TWO_VALUE VARCHAR(20),
NO_ID_CHAIN4 NUMBER,
FOREIGN KEY (NO_ID_CHAIN4) REFERENCES NO_ID_CHAIN4 (FOUR)
);
CREATE TABLE NO_ID_CHAIN1
(
ONE_VALUE VARCHAR(20),
NO_ID_CHAIN4 NUMBER,
FOREIGN KEY (NO_ID_CHAIN4) REFERENCES NO_ID_CHAIN4 (FOUR)
);
CREATE TABLE NO_ID_CHAIN0
(
ZERO_VALUE VARCHAR(20),
NO_ID_CHAIN4 NUMBER,
FOREIGN KEY (NO_ID_CHAIN4) REFERENCES NO_ID_CHAIN4 (FOUR)
);
CREATE TABLE NO_ID_LIST_CHAIN4
(
FOUR NUMBER GENERATED by default on null as IDENTITY PRIMARY KEY,
FOUR_VALUE VARCHAR(20)
);
CREATE TABLE NO_ID_LIST_CHAIN3
(
THREE_VALUE VARCHAR(20),
NO_ID_LIST_CHAIN4 NUMBER,
NO_ID_LIST_CHAIN4_KEY NUMBER,
PRIMARY KEY (NO_ID_LIST_CHAIN4,
NO_ID_LIST_CHAIN4_KEY),
FOREIGN KEY (NO_ID_LIST_CHAIN4) REFERENCES NO_ID_LIST_CHAIN4 (FOUR)
);
CREATE TABLE NO_ID_LIST_CHAIN2
(
TWO_VALUE VARCHAR(20),
NO_ID_LIST_CHAIN4 NUMBER,
NO_ID_LIST_CHAIN4_KEY NUMBER,
NO_ID_LIST_CHAIN3_KEY NUMBER,
PRIMARY KEY (NO_ID_LIST_CHAIN4,
NO_ID_LIST_CHAIN4_KEY,
NO_ID_LIST_CHAIN3_KEY),
FOREIGN KEY (
NO_ID_LIST_CHAIN4,
NO_ID_LIST_CHAIN4_KEY
) REFERENCES NO_ID_LIST_CHAIN3 (
NO_ID_LIST_CHAIN4,
NO_ID_LIST_CHAIN4_KEY
)
);
CREATE TABLE NO_ID_LIST_CHAIN1
(
ONE_VALUE VARCHAR(20),
NO_ID_LIST_CHAIN4 NUMBER,
NO_ID_LIST_CHAIN4_KEY NUMBER,
NO_ID_LIST_CHAIN3_KEY NUMBER,
NO_ID_LIST_CHAIN2_KEY NUMBER,
PRIMARY KEY (NO_ID_LIST_CHAIN4,
NO_ID_LIST_CHAIN4_KEY,
NO_ID_LIST_CHAIN3_KEY,
NO_ID_LIST_CHAIN2_KEY),
FOREIGN KEY (
NO_ID_LIST_CHAIN4,
NO_ID_LIST_CHAIN4_KEY,
NO_ID_LIST_CHAIN3_KEY
) REFERENCES NO_ID_LIST_CHAIN2 (
NO_ID_LIST_CHAIN4,
NO_ID_LIST_CHAIN4_KEY,
NO_ID_LIST_CHAIN3_KEY
)
);
CREATE TABLE NO_ID_LIST_CHAIN0
(
ZERO_VALUE VARCHAR(20),
NO_ID_LIST_CHAIN4 NUMBER,
NO_ID_LIST_CHAIN4_KEY NUMBER,
NO_ID_LIST_CHAIN3_KEY NUMBER,
NO_ID_LIST_CHAIN2_KEY NUMBER,
NO_ID_LIST_CHAIN1_KEY NUMBER,
PRIMARY KEY (NO_ID_LIST_CHAIN4,
NO_ID_LIST_CHAIN4_KEY,
NO_ID_LIST_CHAIN3_KEY,
NO_ID_LIST_CHAIN2_KEY,
NO_ID_LIST_CHAIN1_KEY),
FOREIGN KEY (
NO_ID_LIST_CHAIN4,
NO_ID_LIST_CHAIN4_KEY,
NO_ID_LIST_CHAIN3_KEY,
NO_ID_LIST_CHAIN2_KEY
) REFERENCES NO_ID_LIST_CHAIN1 (
NO_ID_LIST_CHAIN4,
NO_ID_LIST_CHAIN4_KEY,
NO_ID_LIST_CHAIN3_KEY,
NO_ID_LIST_CHAIN2_KEY
)
);
CREATE TABLE NO_ID_MAP_CHAIN4
(
FOUR NUMBER GENERATED by default on null as IDENTITY PRIMARY KEY,
FOUR_VALUE VARCHAR(20)
);
CREATE TABLE NO_ID_MAP_CHAIN3
(
THREE_VALUE VARCHAR(20),
NO_ID_MAP_CHAIN4 NUMBER,
NO_ID_MAP_CHAIN4_KEY VARCHAR(20),
PRIMARY KEY (NO_ID_MAP_CHAIN4,
NO_ID_MAP_CHAIN4_KEY),
FOREIGN KEY (NO_ID_MAP_CHAIN4) REFERENCES NO_ID_MAP_CHAIN4 (FOUR)
);
CREATE TABLE NO_ID_MAP_CHAIN2
(
TWO_VALUE VARCHAR(20),
NO_ID_MAP_CHAIN4 NUMBER,
NO_ID_MAP_CHAIN4_KEY VARCHAR(20),
NO_ID_MAP_CHAIN3_KEY VARCHAR(20),
PRIMARY KEY (NO_ID_MAP_CHAIN4,
NO_ID_MAP_CHAIN4_KEY,
NO_ID_MAP_CHAIN3_KEY),
FOREIGN KEY (
NO_ID_MAP_CHAIN4,
NO_ID_MAP_CHAIN4_KEY
) REFERENCES NO_ID_MAP_CHAIN3 (
NO_ID_MAP_CHAIN4,
NO_ID_MAP_CHAIN4_KEY
)
);
CREATE TABLE NO_ID_MAP_CHAIN1
(
ONE_VALUE VARCHAR(20),
NO_ID_MAP_CHAIN4 NUMBER,
NO_ID_MAP_CHAIN4_KEY VARCHAR(20),
NO_ID_MAP_CHAIN3_KEY VARCHAR(20),
NO_ID_MAP_CHAIN2_KEY VARCHAR(20),
PRIMARY KEY (NO_ID_MAP_CHAIN4,
NO_ID_MAP_CHAIN4_KEY,
NO_ID_MAP_CHAIN3_KEY,
NO_ID_MAP_CHAIN2_KEY),
FOREIGN KEY (
NO_ID_MAP_CHAIN4,
NO_ID_MAP_CHAIN4_KEY,
NO_ID_MAP_CHAIN3_KEY
) REFERENCES NO_ID_MAP_CHAIN2 (
NO_ID_MAP_CHAIN4,
NO_ID_MAP_CHAIN4_KEY,
NO_ID_MAP_CHAIN3_KEY
)
);
CREATE TABLE NO_ID_MAP_CHAIN0
(
ZERO_VALUE VARCHAR(20),
NO_ID_MAP_CHAIN4 NUMBER,
NO_ID_MAP_CHAIN4_KEY VARCHAR(20),
NO_ID_MAP_CHAIN3_KEY VARCHAR(20),
NO_ID_MAP_CHAIN2_KEY VARCHAR(20),
NO_ID_MAP_CHAIN1_KEY VARCHAR(20),
PRIMARY KEY (NO_ID_MAP_CHAIN4,
NO_ID_MAP_CHAIN4_KEY,
NO_ID_MAP_CHAIN3_KEY,
NO_ID_MAP_CHAIN2_KEY,
NO_ID_MAP_CHAIN1_KEY),
FOREIGN KEY (
NO_ID_MAP_CHAIN4,
NO_ID_MAP_CHAIN4_KEY,
NO_ID_MAP_CHAIN3_KEY,
NO_ID_MAP_CHAIN2_KEY
) REFERENCES NO_ID_MAP_CHAIN1 (
NO_ID_MAP_CHAIN4,
NO_ID_MAP_CHAIN4_KEY,
NO_ID_MAP_CHAIN3_KEY,
NO_ID_MAP_CHAIN2_KEY
)
);
CREATE TABLE VERSIONED_AGGREGATE
(
ID NUMBER GENERATED by default on null as IDENTITY PRIMARY KEY,
VERSION NUMBER
);
CREATE TABLE WITH_READ_ONLY
(
ID NUMBER GENERATED by default on null as IDENTITY PRIMARY KEY,
NAME VARCHAR(200),
READ_ONLY VARCHAR(200) DEFAULT 'from-db'
);
CREATE TABLE WITH_LOCAL_DATE_TIME
(
ID NUMBER PRIMARY KEY,
TEST_TIME TIMESTAMP(9)
);

View File

@@ -318,3 +318,9 @@ CREATE TABLE WITH_READ_ONLY
NAME VARCHAR(200),
READ_ONLY VARCHAR(200) DEFAULT 'from-db'
);
CREATE TABLE WITH_LOCAL_DATE_TIME
(
ID BIGINT PRIMARY KEY,
TEST_TIME TIMESTAMP(9) WITHOUT TIME ZONE
);