From 44e9eac4acda9dd81269c874dcc3760c7acf4cfa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Prante?= <joergprante@gmail.com> Date: Tue, 18 Mar 2025 17:28:43 +0100 Subject: [PATCH] add more date/time routines with java.time where possible --- gradle.properties | 2 +- .../java/org/xbib/jdbc/mariadb/MariaDB.java | 18 +- .../xbib/jdbc/mariadb/test/MariaDBTest.java | 14 +- .../java/org/xbib/jdbc/oracle/Oracle.java | 39 ++-- .../org/xbib/jdbc/oracle/test/OracleTest.java | 6 +- .../org/xbib/jdbc/postgresql/Postgresql.java | 16 +- .../jdbc/postgresql/test/PostgresqlTest.java | 13 +- .../org/xbib/jdbc/query/DatabaseImpl.java | 42 ++-- .../org/xbib/jdbc/query/DatabaseProvider.java | 2 +- .../main/java/org/xbib/jdbc/query/Flavor.java | 6 +- .../java/org/xbib/jdbc/query/Options.java | 2 +- .../org/xbib/jdbc/query/OptionsDefault.java | 2 +- .../org/xbib/jdbc/query/OptionsOverride.java | 4 +- .../main/java/org/xbib/jdbc/query/Row.java | 23 +- .../java/org/xbib/jdbc/query/RowsAdapter.java | 147 ++++++++---- .../main/java/org/xbib/jdbc/query/Schema.java | 41 +++- .../java/org/xbib/jdbc/query/SqlInsert.java | 17 +- .../org/xbib/jdbc/query/SqlInsertImpl.java | 45 +++- .../java/org/xbib/jdbc/query/SqlSelect.java | 32 ++- .../org/xbib/jdbc/query/SqlSelectImpl.java | 125 ++++++++-- .../org/xbib/jdbc/query/SqlUpdateImpl.java | 4 +- .../org/xbib/jdbc/query/StatementAdapter.java | 27 ++- .../org/xbib/jdbc/query/flavor/Derby.java | 14 +- .../java/org/xbib/jdbc/query/flavor/H2.java | 14 +- .../java/org/xbib/jdbc/query/flavor/Hsql.java | 14 +- .../org/xbib/jdbc/query/test/HsqldbTest.java | 20 +- .../org/xbib/jdbc/query/test/RowStub.java | 126 ++++++++--- jdbc-sqlserver/build.gradle | 10 - jdbc-sqlserver/src/main/java/module-info.java | 10 - .../org/xbib/jdbc/sqlserver/SqlServer.java | 214 ------------------ .../services/org.xbib.jdbc.query.Flavor | 1 - .../jdbc/sqlserver/test/SqlServerTest.java | 87 ------- .../src/test/resources/logging.properties | 10 - .../java/org/xbib/jdbc/test/CommonTest.java | 162 ++++++++----- settings.gradle | 13 +- 35 files changed, 703 insertions(+), 619 deletions(-) delete mode 100644 jdbc-sqlserver/build.gradle delete mode 100644 jdbc-sqlserver/src/main/java/module-info.java delete mode 100644 jdbc-sqlserver/src/main/java/org/xbib/jdbc/sqlserver/SqlServer.java delete mode 100644 jdbc-sqlserver/src/main/resources/META-INF/services/org.xbib.jdbc.query.Flavor delete mode 100644 jdbc-sqlserver/src/test/java/org/xbib/jdbc/sqlserver/test/SqlServerTest.java delete mode 100644 jdbc-sqlserver/src/test/resources/logging.properties diff --git a/gradle.properties b/gradle.properties index 2593a86..4759c74 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,3 +1,3 @@ group = org.xbib name = database -version = 2.3.3 +version = 2.4.0 diff --git a/jdbc-mariadb/src/main/java/org/xbib/jdbc/mariadb/MariaDB.java b/jdbc-mariadb/src/main/java/org/xbib/jdbc/mariadb/MariaDB.java index 01b60c1..202c803 100644 --- a/jdbc-mariadb/src/main/java/org/xbib/jdbc/mariadb/MariaDB.java +++ b/jdbc-mariadb/src/main/java/org/xbib/jdbc/mariadb/MariaDB.java @@ -103,13 +103,23 @@ public class MariaDB implements Flavor { } @Override - public String typeLocalDateTime() { - return "datetime(3)"; + public String typeInstant() { + return "timestamp(3)"; // 3 = millisecond resolution } @Override - public String columnTypeLocalDateTime() { - return "DATETIME"; + public String typeLocalDateTime() { + return "timestamp(3)"; // 3 = millisecond resolution + } + + @Override + public String typeOffsetDateTime() { + return "datetime(3)"; // 3 = millisecond resolution + } + + @Override + public String typeZonedDateTime() { + return "datetime(3)"; // 3 = millisecond resolution } @Override diff --git a/jdbc-mariadb/src/test/java/org/xbib/jdbc/mariadb/test/MariaDBTest.java b/jdbc-mariadb/src/test/java/org/xbib/jdbc/mariadb/test/MariaDBTest.java index 068a720..f7183bc 100644 --- a/jdbc-mariadb/src/test/java/org/xbib/jdbc/mariadb/test/MariaDBTest.java +++ b/jdbc-mariadb/src/test/java/org/xbib/jdbc/mariadb/test/MariaDBTest.java @@ -44,7 +44,11 @@ public class MariaDBTest extends CommonTest { @Override protected DatabaseProvider createDatabaseProvider(OptionsOverride options) { return DatabaseProvider.builder(getClass().getClassLoader(), - mariaDBContainer.getJdbcUrl(), null, null, "testUser", "testPassword") + mariaDBContainer.getJdbcUrl(), + null, + null, + "testUser", + "testPassword") .withSqlParameterLogging() .withSqlInExceptionMessages() .withOptions(options) @@ -154,7 +158,7 @@ public class MariaDBTest extends CommonTest { .argClobString("hello again") .argBlobBytes(new byte[]{'1', '2'}) .argBoolean(true) - .argLocalDateTime(now) + .argLocalDateTime(localDateTimeNow) .argLocalDate(localDateNow) .insert(1); @@ -170,7 +174,7 @@ public class MariaDBTest extends CommonTest { .argClobString("bye again") .argBlobBytes(new byte[]{'3', '4'}) .argBoolean(false) - .argLocalDateTime(now) + .argLocalDateTime(localDateTimeNow) .argLocalDate(localDateNow) .insert(1); @@ -227,7 +231,7 @@ public class MariaDBTest extends CommonTest { .argString("str_lob", "bye again") .argBlobBytes("bin_blob", new byte[]{'3', '4'}) .argString("boolean_flag", "N")//.argBoolean("boolean_flag", false) - .argLocalDateTime("date_millis", now) + .argLocalDateTime("date_millis", localDateTimeNow) .argLocalDate("local_date", localDateNow), new SqlArgs() .argInteger("nbr_integer", Integer.MAX_VALUE) @@ -240,7 +244,7 @@ public class MariaDBTest extends CommonTest { .argString("str_lob", "hello again") .argBlobBytes("bin_blob", new byte[]{'1', '2'}) .argString("boolean_flag", "Y")//.argBoolean("boolean_flag", true) - .argLocalDateTime("date_millis", now) + .argLocalDateTime("date_millis", localDateTimeNow) .argLocalDate("local_date", localDateNow)), db.toSelect("select nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal," + " str_varchar, str_fixed, str_lob, bin_blob, boolean_flag, date_millis, local_date from dbtest2 order by 1") diff --git a/jdbc-oracle/src/main/java/org/xbib/jdbc/oracle/Oracle.java b/jdbc-oracle/src/main/java/org/xbib/jdbc/oracle/Oracle.java index 8210322..b84a28a 100644 --- a/jdbc-oracle/src/main/java/org/xbib/jdbc/oracle/Oracle.java +++ b/jdbc-oracle/src/main/java/org/xbib/jdbc/oracle/Oracle.java @@ -50,16 +50,6 @@ public class Oracle implements Flavor { } } - /*@Override - public void setFloat(PreparedStatement preparedStatement, int i, Float floatValue) throws SQLException { - if (preparedStatement instanceof ProxyPreparedStatement) { - ProxyPreparedStatement proxyPreparedStatement = (ProxyPreparedStatement) preparedStatement; - ((OraclePreparedStatement) proxyPreparedStatement.getDelegate()).setBinaryFloat(i, floatValue); - } else { - ((OraclePreparedStatement) preparedStatement).setBinaryFloat(i, floatValue); - } - }*/ - @Override public String typeDouble() { return "binary_double"; @@ -71,16 +61,6 @@ public class Oracle implements Flavor { } } - /*@Override - public void setDouble(PreparedStatement preparedStatement, int i, Double doubleValue) throws SQLException { - if (preparedStatement instanceof ProxyPreparedStatement) { - ProxyPreparedStatement proxyPreparedStatement = (ProxyPreparedStatement) preparedStatement; - ((OraclePreparedStatement) proxyPreparedStatement.getDelegate()).setBinaryDouble(i, doubleValue); - } else { - ((OraclePreparedStatement) preparedStatement).setBinaryDouble(i, doubleValue); - } - }*/ - @Override public String typeBigDecimal(int size, int precision) { return "numeric(" + size + "," + precision + ")"; @@ -102,17 +82,28 @@ public class Oracle implements Flavor { } @Override - public String typeLocalDateTime() { - return "timestamp(3)"; + public String typeInstant() { + return "timestamp"; } @Override - public String columnTypeLocalDateTime() { - return "TIMESTAMP"; + public String typeLocalDateTime() { + return "timestamp"; + } + + @Override + public String typeOffsetDateTime() { + return "timestamp with time zone"; + } + + @Override + public String typeZonedDateTime() { + return "timestamp with time zone"; } @Override public String typeLocalDate() { + // well, this is a full blown timestamp in Oracle return "date"; } diff --git a/jdbc-oracle/src/test/java/org/xbib/jdbc/oracle/test/OracleTest.java b/jdbc-oracle/src/test/java/org/xbib/jdbc/oracle/test/OracleTest.java index 08f6ca9..85a7f52 100644 --- a/jdbc-oracle/src/test/java/org/xbib/jdbc/oracle/test/OracleTest.java +++ b/jdbc-oracle/src/test/java/org/xbib/jdbc/oracle/test/OracleTest.java @@ -45,7 +45,11 @@ public class OracleTest extends CommonTest { @Override protected DatabaseProvider createDatabaseProvider(OptionsOverride options) throws Exception { return DatabaseProvider.builder(getClass().getClassLoader(), - oracleContainer.getJdbcUrl(), null, null, "testUser", "testPassword") + oracleContainer.getJdbcUrl(), + null, + null, + "testUser", + "testPassword") .withSqlParameterLogging() .withSqlInExceptionMessages() .withOptions(options) diff --git a/jdbc-postgresql/src/main/java/org/xbib/jdbc/postgresql/Postgresql.java b/jdbc-postgresql/src/main/java/org/xbib/jdbc/postgresql/Postgresql.java index 2b0bb08..7b6eaa5 100644 --- a/jdbc-postgresql/src/main/java/org/xbib/jdbc/postgresql/Postgresql.java +++ b/jdbc-postgresql/src/main/java/org/xbib/jdbc/postgresql/Postgresql.java @@ -100,15 +100,25 @@ public class Postgresql implements Flavor { } @Override - public String typeLocalDateTime() { - return "timestamp(3)"; + public String typeInstant() { + return "timestamp"; } @Override - public String columnTypeLocalDateTime() { + public String typeLocalDateTime() { return "timestamp"; } + @Override + public String typeOffsetDateTime() { + return "timestamp with time zone"; + } + + @Override + public String typeZonedDateTime() { + return "timestamp with time zone"; + } + @Override public String typeLocalDate() { return "date"; diff --git a/jdbc-postgresql/src/test/java/org/xbib/jdbc/postgresql/test/PostgresqlTest.java b/jdbc-postgresql/src/test/java/org/xbib/jdbc/postgresql/test/PostgresqlTest.java index df0e2f1..327c924 100644 --- a/jdbc-postgresql/src/test/java/org/xbib/jdbc/postgresql/test/PostgresqlTest.java +++ b/jdbc-postgresql/src/test/java/org/xbib/jdbc/postgresql/test/PostgresqlTest.java @@ -20,7 +20,6 @@ public class PostgresqlTest extends CommonTest { static PostgreSQLContainer<?> postgreSQLContainer; static { - // postgresql 9.6.12 postgreSQLContainer = new PostgreSQLContainer<>("postgres") .withDatabaseName("testDB") .withUsername("testUser") @@ -39,12 +38,12 @@ public class PostgresqlTest extends CommonTest { @Override protected DatabaseProvider createDatabaseProvider(OptionsOverride options) throws Exception { - Config config = ConfigSupplier.of() - .property("database.url", postgreSQLContainer.getJdbcUrl()) - .property("database.user", "testUser") - .property("database.password", "testPassword") - .get(); - return DatabaseProvider.builder(config) + return DatabaseProvider.builder(getClass().getClassLoader(), + postgreSQLContainer.getJdbcUrl(), + null, + null, + "testUser", + "testPassword") .withSqlParameterLogging() .withSqlInExceptionMessages() .withOptions(options) diff --git a/jdbc-query/src/main/java/org/xbib/jdbc/query/DatabaseImpl.java b/jdbc-query/src/main/java/org/xbib/jdbc/query/DatabaseImpl.java index 8c9f5fb..9be55fc 100644 --- a/jdbc-query/src/main/java/org/xbib/jdbc/query/DatabaseImpl.java +++ b/jdbc-query/src/main/java/org/xbib/jdbc/query/DatabaseImpl.java @@ -25,7 +25,7 @@ import java.util.logging.Logger; */ public class DatabaseImpl implements Database { - private static final Logger logger = Logger.getLogger(Database.class.getName()); + private static final Logger logger = Logger.getLogger(DatabaseImpl.class.getName()); private final Connection connection; @@ -354,15 +354,17 @@ public class DatabaseImpl implements Database { ResultSetMetaData md = rows.getMetadata(); List<Object> columnLabels = new ArrayList<>(); List<Object> classNames = new ArrayList<>(); + List<Object> columnTypeNames = new ArrayList<>(); for (int i = 1; i <= md.getColumnCount(); i++) { columnLabels.add(md.getColumnLabel(i)); classNames.add(md.getColumnClassName(i)); + columnTypeNames.add(md.getColumnTypeName(i)); } table.add(columnLabels); table.add(classNames); int i = 0; while (rows.next() && (limit <= 0 || i++ < limit)) { - table.add(getRow(rows, classNames)); + table.add(getRow(rows, classNames, columnTypeNames)); } table.setTotal(rows.rowCount()); return true; @@ -382,15 +384,17 @@ public class DatabaseImpl implements Database { ResultSetMetaData md = rows.getMetadata(); List<Object> columnLabels = new ArrayList<>(); List<Object> classNames = new ArrayList<>(); + List<Object> columnTypeNames = new ArrayList<>(); for (int i = 1; i <= md.getColumnCount(); i++) { columnLabels.add(md.getColumnLabel(i)); classNames.add(md.getColumnClassName(i)); + columnTypeNames.add(md.getColumnTypeName(i)); } consumer.accept(columnLabels); consumer.accept(classNames); int i = 0; while (rows.next() && (limit <= 0 || i++ < limit)) { - consumer.accept(getRow(rows, classNames)); + consumer.accept(getRow(rows, classNames, columnTypeNames)); } return true; }); @@ -517,20 +521,28 @@ public class DatabaseImpl implements Database { }); } - private List<Object> getRow(Rows rows, List<Object> classNames) { + private List<Object> getRow(Rows rows, List<Object> classNames, List<Object> columnTypeNames) { List<Object> row = new ArrayList<>(); + // we may have some column type names that need special treatment + for (int i = 0; i < classNames.size(); i++) { - String className = classNames.get(i).toString(); - switch (className) { - case "java.lang.Character", "java.lang.String" -> row.add(rows.getStringOrEmpty(i + 1)); - case "java.lang.Integer" -> row.add(rows.getIntegerOrNull(i + 1)); - case "java.lang.Long" -> row.add(rows.getLongOrNull(i + 1)); - case "java.lang.Boolean" -> row.add(rows.getBooleanOrFalse(i + 1)); - case "java.sql.Clob", "oracle.jdbc.OracleClob" -> row.add(rows.getClobStringOrEmpty(i + 1)); - case "java.sql.Date" -> row.add(rows.getLocalDateOrNull(i + 1)); - case "java.sql.Timestamp", "oracle.sql.TIMESTAMP" -> row.add(rows.getLocalDateTimeOrNull(i + 1)); - case "java.math.BigDecimal" -> row.add(rows.getBigDecimalOrNull(i + 1)); - default -> throw new DatabaseException("unexpected column class name: " + className); + String columnTypeName = columnTypeNames.get(i).toString(); + if ("TIMESTAMPTZ".equals(columnTypeName)) { + row.add(rows.getOffsetDateTimeOrNull(i + 1)); + } else { + String className = classNames.get(i).toString(); + switch (className) { + case "java.lang.Character", "java.lang.String" -> row.add(rows.getStringOrEmpty(i + 1)); + case "java.lang.Integer" -> row.add(rows.getIntegerOrNull(i + 1)); + case "java.lang.Long" -> row.add(rows.getLongOrNull(i + 1)); + case "java.lang.Boolean" -> row.add(rows.getBooleanOrFalse(i + 1)); + case "java.sql.Clob", "oracle.jdbc.OracleClob" -> row.add(rows.getClobStringOrEmpty(i + 1)); + case "java.sql.Date" -> row.add(rows.getLocalDateOrNull(i + 1)); + case "oracle.sql.TIMESTAMPTZ" -> row.add(rows.getOffsetDateTimeOrNull(i + 1)); + case "java.sql.Timestamp", "oracle.sql.TIMESTAMP" -> row.add(rows.getLocalDateTimeOrNull(i + 1)); + case "java.math.BigDecimal" -> row.add(rows.getBigDecimalOrNull(i + 1)); + default -> throw new DatabaseException("unexpected column class name: " + className); + } } } return row; diff --git a/jdbc-query/src/main/java/org/xbib/jdbc/query/DatabaseProvider.java b/jdbc-query/src/main/java/org/xbib/jdbc/query/DatabaseProvider.java index 4887719..33a30ba 100644 --- a/jdbc-query/src/main/java/org/xbib/jdbc/query/DatabaseProvider.java +++ b/jdbc-query/src/main/java/org/xbib/jdbc/query/DatabaseProvider.java @@ -384,7 +384,7 @@ public final class DatabaseProvider implements Supplier<Database> { public DatabaseProviderBuilder withDatePerAppOnly() { return new DatabaseProviderBuilderImpl(dataSource, connectionProvider, new OptionsOverride() { @Override - public boolean useLocalDateTimeOnly() { + public boolean useClientClock() { return true; } }.withParent(this.options)); diff --git a/jdbc-query/src/main/java/org/xbib/jdbc/query/Flavor.java b/jdbc-query/src/main/java/org/xbib/jdbc/query/Flavor.java index df2b073..798c2bd 100644 --- a/jdbc-query/src/main/java/org/xbib/jdbc/query/Flavor.java +++ b/jdbc-query/src/main/java/org/xbib/jdbc/query/Flavor.java @@ -38,9 +38,13 @@ public interface Flavor { String typeBlob(); + String typeInstant(); + String typeLocalDateTime(); - String columnTypeLocalDateTime(); + String typeOffsetDateTime(); + + String typeZonedDateTime(); String typeLocalDate(); diff --git a/jdbc-query/src/main/java/org/xbib/jdbc/query/Options.java b/jdbc-query/src/main/java/org/xbib/jdbc/query/Options.java index 353a6d5..9439cc3 100644 --- a/jdbc-query/src/main/java/org/xbib/jdbc/query/Options.java +++ b/jdbc-query/src/main/java/org/xbib/jdbc/query/Options.java @@ -100,7 +100,7 @@ public interface Options { * This is useful for testing purposes as you can use OptionsOverride to provide your * own clock that will be used. */ - boolean useLocalDateTimeOnly(); + boolean useClientClock(); /** * The maximum number of characters to print in debug SQL for a given String type diff --git a/jdbc-query/src/main/java/org/xbib/jdbc/query/OptionsDefault.java b/jdbc-query/src/main/java/org/xbib/jdbc/query/OptionsDefault.java index 4e6f0fd..a918de5 100644 --- a/jdbc-query/src/main/java/org/xbib/jdbc/query/OptionsDefault.java +++ b/jdbc-query/src/main/java/org/xbib/jdbc/query/OptionsDefault.java @@ -69,7 +69,7 @@ public class OptionsDefault implements Options { } @Override - public boolean useLocalDateTimeOnly() { + public boolean useClientClock() { return false; } diff --git a/jdbc-query/src/main/java/org/xbib/jdbc/query/OptionsOverride.java b/jdbc-query/src/main/java/org/xbib/jdbc/query/OptionsOverride.java index 1f031a0..2b461dc 100644 --- a/jdbc-query/src/main/java/org/xbib/jdbc/query/OptionsOverride.java +++ b/jdbc-query/src/main/java/org/xbib/jdbc/query/OptionsOverride.java @@ -96,8 +96,8 @@ public class OptionsOverride implements Options { } @Override - public boolean useLocalDateTimeOnly() { - return parent.useLocalDateTimeOnly(); + public boolean useClientClock() { + return parent.useClientClock(); } @Override diff --git a/jdbc-query/src/main/java/org/xbib/jdbc/query/Row.java b/jdbc-query/src/main/java/org/xbib/jdbc/query/Row.java index 002e84a..e3ca351 100644 --- a/jdbc-query/src/main/java/org/xbib/jdbc/query/Row.java +++ b/jdbc-query/src/main/java/org/xbib/jdbc/query/Row.java @@ -4,9 +4,12 @@ import java.io.InputStream; import java.io.Reader; import java.math.BigDecimal; import java.sql.ResultSetMetaData; +import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.OffsetDateTime; import java.time.ZoneId; +import java.time.ZonedDateTime; /** * Interface for reading results from a database query. @@ -355,15 +358,29 @@ public interface Row { InputStream getBlobInputStreamOrEmpty(String columnName); + Instant getInstantOrNull(); + + Instant getInstantOrNull(int columnOneBased); + + Instant getInstantOrNull(String columnName); + LocalDateTime getLocalDateTimeOrNull(); LocalDateTime getLocalDateTimeOrNull(int columnOneBased); - LocalDateTime getLocalDateTimeOrNull(int columnOneBased, ZoneId zoneId); - LocalDateTime getLocalDateTimeOrNull(String columnName); - LocalDateTime getLocalDateTimeOrNull(String columnName, ZoneId zoneId); + OffsetDateTime getOffsetDateTimeOrNull(); + + OffsetDateTime getOffsetDateTimeOrNull(int columnOneBase); + + OffsetDateTime getOffsetDateTimeOrNull(String columnName); + + ZonedDateTime getZonedDateTimeOrNull(); + + ZonedDateTime getZonedDateTimeOrNull(int columnOneBase); + + ZonedDateTime getZonedDateTimeOrNull(String columnName); /** * Retrieve column as LocalDate, .i.e, date with no time. diff --git a/jdbc-query/src/main/java/org/xbib/jdbc/query/RowsAdapter.java b/jdbc-query/src/main/java/org/xbib/jdbc/query/RowsAdapter.java index b09428a..8851934 100644 --- a/jdbc-query/src/main/java/org/xbib/jdbc/query/RowsAdapter.java +++ b/jdbc-query/src/main/java/org/xbib/jdbc/query/RowsAdapter.java @@ -5,13 +5,15 @@ import java.io.InputStream; import java.io.Reader; import java.io.StringReader; import java.math.BigDecimal; +import java.math.RoundingMode; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; -import java.sql.Timestamp; +import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; -import java.time.ZoneId; +import java.time.OffsetDateTime; +import java.time.ZonedDateTime; /** * Safely wrap a ResultSet and provide access to the data it contains. @@ -20,13 +22,10 @@ class RowsAdapter implements Rows { private final ResultSet rs; - private final Options options; - private int column = 1; - public RowsAdapter(ResultSet rs, Options options) { + public RowsAdapter(ResultSet rs) { this.rs = rs; - this.options = options; } @Override @@ -39,6 +38,15 @@ class RowsAdapter implements Rows { } } + @Override + public ResultSetMetaData getMetadata() { + try { + return rs.getMetaData(); + } catch (SQLException e) { + throw new DatabaseException("Unable to retrieve metadata from ResultSet", e); + } + } + @Override public String[] getColumnLabels() { try { @@ -52,16 +60,7 @@ class RowsAdapter implements Rows { throw new DatabaseException("Unable to retrieve metadata from ResultSet", e); } } - - @Override - public ResultSetMetaData getMetadata() { - try { - return rs.getMetaData(); - } catch (SQLException e) { - throw new DatabaseException("Unable to retrieve metadata from ResultSet", e); - } - } - + @Override public Boolean getBooleanOrNull() { return getBooleanOrNull(column++); @@ -200,7 +199,7 @@ class RowsAdapter implements Rows { } return result; } - + @Override public Long getLongOrNull() { return getLongOrNull(column++); @@ -411,7 +410,7 @@ class RowsAdapter implements Rows { try { column = columnOneBased + 1; String result = rs.getString(columnOneBased); - if (result != null && result.length() == 0) { + if (result != null && result.isEmpty()) { result = null; } return result; @@ -425,7 +424,7 @@ class RowsAdapter implements Rows { try { column = rs.findColumn(columnName) + 1; String result = rs.getString(columnName); - if (result != null && result.length() == 0) { + if (result != null && result.isEmpty()) { result = null; } return result; @@ -467,7 +466,7 @@ class RowsAdapter implements Rows { try { column = columnOneBased + 1; String result = rs.getString(columnOneBased); - if (result != null && result.length() == 0) { + if (result != null && result.isEmpty()) { result = null; } return result; @@ -481,7 +480,7 @@ class RowsAdapter implements Rows { try { column = rs.findColumn(columnName) + 1; String result = rs.getString(columnName); - if (result != null && result.length() == 0) { + if (result != null && result.isEmpty()) { result = null; } return result; @@ -656,7 +655,32 @@ class RowsAdapter implements Rows { } return result; } - + + @Override + public Instant getInstantOrNull() { + return getInstantOrNull(column++); + } + + @Override + public Instant getInstantOrNull(int columnOneBased) { + try { + column = columnOneBased + 1; + return rs.getObject(columnOneBased, Instant.class); + } catch (SQLException e) { + throw new DatabaseException(e); + } + } + + @Override + public Instant getInstantOrNull(String columnName) { + try { + column = rs.findColumn(columnName) + 1; + return rs.getObject(columnName, Instant.class); + } catch (SQLException e) { + throw new DatabaseException(e); + } + } + @Override public LocalDateTime getLocalDateTimeOrNull() { return getLocalDateTimeOrNull(column++); @@ -672,22 +696,6 @@ class RowsAdapter implements Rows { } } - @Override - public LocalDateTime getLocalDateTimeOrNull(int columnOneBased, ZoneId zoneId) { - try { - column = columnOneBased + 1; - LocalDateTime localDateTime = rs.getObject(columnOneBased, LocalDateTime.class); - Timestamp timestamp = rs.getTimestamp(columnOneBased); - if (zoneId != null) { - return localDateTime != null ? localDateTime.atZone(zoneId).toLocalDateTime() : null; - } else { - return localDateTime; - } - } catch (SQLException e) { - throw new DatabaseException(e); - } - } - @Override public LocalDateTime getLocalDateTimeOrNull(String columnName) { try { @@ -698,17 +706,6 @@ class RowsAdapter implements Rows { } } - @Override - public LocalDateTime getLocalDateTimeOrNull(String columnName, ZoneId zoneId) { - try { - column = rs.findColumn(columnName) + 1; - LocalDateTime localDateTime = rs.getObject(columnName, LocalDateTime.class); - return localDateTime != null ? localDateTime.atZone(zoneId).toLocalDateTime() : null; - } catch (SQLException e) { - throw new DatabaseException(e); - } - } - @Override public LocalDate getLocalDateOrNull() { return getLocalDateOrNull(column++); @@ -736,6 +733,56 @@ class RowsAdapter implements Rows { } } + @Override + public OffsetDateTime getOffsetDateTimeOrNull() { + return getOffsetDateTimeOrNull(column++); + } + + @Override + public OffsetDateTime getOffsetDateTimeOrNull(int columnOneBased) { + try { + column = columnOneBased + 1; + return rs.getObject(columnOneBased, OffsetDateTime.class); + } catch (SQLException e) { + throw new DatabaseException(e); + } + } + + @Override + public OffsetDateTime getOffsetDateTimeOrNull(String columnName) { + try { + column = rs.findColumn(columnName) + 1; + return rs.getObject(columnName, OffsetDateTime.class); + } catch (SQLException e) { + throw new DatabaseException(e); + } + } + + @Override + public ZonedDateTime getZonedDateTimeOrNull() { + return getZonedDateTimeOrNull(column++); + } + + @Override + public ZonedDateTime getZonedDateTimeOrNull(int columnOneBased) { + try { + column = columnOneBased + 1; + return rs.getObject(columnOneBased, ZonedDateTime.class); + } catch (SQLException e) { + throw new DatabaseException(e); + } + } + + @Override + public ZonedDateTime getZonedDateTimeOrNull(String columnName) { + try { + column = rs.findColumn(columnName) + 1; + return rs.getObject(columnName, ZonedDateTime.class); + } catch (SQLException e) { + throw new DatabaseException(e); + } + } + @Override public Integer rowCount() { try { @@ -750,7 +797,7 @@ class RowsAdapter implements Rows { if (val.scale() > 0) { val = val.stripTrailingZeros(); if (val.scale() < 0) { - val = val.setScale(0); + val = val.setScale(0, RoundingMode.FLOOR); } } return val; diff --git a/jdbc-query/src/main/java/org/xbib/jdbc/query/Schema.java b/jdbc-query/src/main/java/org/xbib/jdbc/query/Schema.java index bafa851..1103d66 100644 --- a/jdbc-query/src/main/java/org/xbib/jdbc/query/Schema.java +++ b/jdbc-query/src/main/java/org/xbib/jdbc/query/Schema.java @@ -141,7 +141,6 @@ public class Schema { // This is the type dates and times with time and time zone associated. // Note that Oracle dates are always really Timestamps. case Types.TIMESTAMP: - case Types.TIMESTAMP_WITH_TIMEZONE: // Check if we really have a LocalDate implemented by the DB as a timestamp if (metadata.getScale(i + 1) == 0) { // If the scale is 0, this is a LocalDate (no time/timezone). @@ -151,6 +150,9 @@ public class Schema { table.addColumn(names[i]).asLocalDateTime(); } break; + case Types.TIMESTAMP_WITH_TIMEZONE: + table.addColumn(names[i]).asOffsetDateTime(); + break; case Types.NVARCHAR: case Types.VARCHAR: case Types.LONGVARCHAR: @@ -227,9 +229,18 @@ public class Schema { case StringFixed: sql.append(flavor.typeStringFixed(column.scale)); break; + case Instant: + sql.append(flavor.typeInstant()); + break; case LocalDateTime: sql.append(flavor.typeLocalDateTime()); break; + case OffsetDateTime: + sql.append(flavor.typeOffsetDateTime()); + break; + case ZonedDateTime: + sql.append(flavor.typeZonedDateTime()); + break; case LocalDate: sql.append(flavor.typeLocalDate()); break; @@ -395,7 +406,21 @@ public class Schema { } public enum ColumnType { - Integer, Long, Float, Double, BigDecimal, StringVar, StringFixed, Clob, Blob, LocalDateTime, LocalDate, Boolean + Integer, + Long, + Float, + Double, + BigDecimal, + StringVar, + StringFixed, + Clob, + Blob, + Instant, + LocalDateTime, + OffsetDateTime, + ZonedDateTime, + LocalDate, + Boolean } public class Sequence { @@ -902,10 +927,22 @@ public class Schema { return asType(ColumnType.StringFixed); } + public Column asInstant() { + return asType(ColumnType.Instant); + } + public Column asLocalDateTime() { return asType(ColumnType.LocalDateTime); } + public Column asOffsetDateTime() { + return asType(ColumnType.OffsetDateTime); + } + + public Column asZonedateTime() { + return asType(ColumnType.ZonedDateTime); + } + public Column asLocalDate() { return asType(ColumnType.LocalDate); } diff --git a/jdbc-query/src/main/java/org/xbib/jdbc/query/SqlInsert.java b/jdbc-query/src/main/java/org/xbib/jdbc/query/SqlInsert.java index 0d68f15..6299380 100644 --- a/jdbc-query/src/main/java/org/xbib/jdbc/query/SqlInsert.java +++ b/jdbc-query/src/main/java/org/xbib/jdbc/query/SqlInsert.java @@ -3,9 +3,12 @@ package org.xbib.jdbc.query; import java.io.InputStream; import java.io.Reader; import java.math.BigDecimal; +import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.OffsetDateTime; import java.time.ZoneId; +import java.time.ZonedDateTime; /** * Interface for configuring (setting parameters) and executing a chunk of SQL. @@ -40,12 +43,22 @@ public interface SqlInsert { SqlInsert argString( String argName, String arg); + SqlInsert argInstant(Instant arg); + + SqlInsert argInstant(String argName, Instant arg); + SqlInsert argLocalDateTime(LocalDateTime arg); - SqlInsert argLocalDateTime(LocalDateTime arg, ZoneId zoneId); - SqlInsert argLocalDateTime(String argName, LocalDateTime arg); + SqlInsert argOffsetDateTime(OffsetDateTime arg); + + SqlInsert argOffsetDateTime(String argName, OffsetDateTime arg); + + SqlInsert argZonedDateTime(ZonedDateTime arg); + + SqlInsert argZonedDateTime(String argName, ZonedDateTime arg); + SqlInsert argLocalDate(LocalDate arg); SqlInsert argLocalDate( String argName, LocalDate arg); diff --git a/jdbc-query/src/main/java/org/xbib/jdbc/query/SqlInsertImpl.java b/jdbc-query/src/main/java/org/xbib/jdbc/query/SqlInsertImpl.java index 94f1b4a..2621820 100644 --- a/jdbc-query/src/main/java/org/xbib/jdbc/query/SqlInsertImpl.java +++ b/jdbc-query/src/main/java/org/xbib/jdbc/query/SqlInsertImpl.java @@ -13,9 +13,11 @@ import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.Statement; +import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; -import java.time.ZoneId; +import java.time.OffsetDateTime; +import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -142,13 +144,18 @@ public class SqlInsertImpl implements SqlInsert { } @Override - public SqlInsert argLocalDateTime(LocalDateTime arg) { - return positionalArg(adaptor.nullLocalDateTime(arg)); + public SqlInsert argInstant(Instant arg) { + return positionalArg(adaptor.nullInstant(arg)); } @Override - public SqlInsert argLocalDateTime(LocalDateTime arg, ZoneId zoneId) { - return positionalArg(adaptor.nullLocalDateTime(arg, zoneId)); + public SqlInsert argInstant(String argName, Instant arg) { + return namedArg(argName, adaptor.nullInstant(arg)); + } + + @Override + public SqlInsert argLocalDateTime(LocalDateTime arg) { + return positionalArg(adaptor.nullLocalDateTime(arg)); } @Override @@ -165,10 +172,30 @@ public class SqlInsertImpl implements SqlInsert { public SqlInsert argLocalDate(LocalDate arg) { return positionalArg(adaptor.nullLocalDate(arg)); } - + + @Override + public SqlInsert argOffsetDateTime(OffsetDateTime arg) { + return positionalArg(adaptor.nullOffsetDateTime(arg)); + } + + @Override + public SqlInsert argOffsetDateTime(String argName, OffsetDateTime arg) { + return namedArg(argName, adaptor.nullOffsetDateTime(arg)); + } + + @Override + public SqlInsert argZonedDateTime(ZonedDateTime arg) { + return positionalArg(adaptor.nullZonedDateTime(arg)); + } + + @Override + public SqlInsert argZonedDateTime(String argName, ZonedDateTime arg) { + return namedArg(argName, adaptor.nullZonedDateTime(arg)); + } + @Override public SqlInsert argLocalDateTimeNowPerDb() { - if (options.useLocalDateTimeOnly()) { + if (options.useClientClock()) { return positionalArg(adaptor.nullLocalDateTime(LocalDateTime.now())); } return positionalArg(new RewriteArg(options.flavor().dbTimeMillis())); @@ -176,7 +203,7 @@ public class SqlInsertImpl implements SqlInsert { @Override public SqlInsert argLocalDateTimeNowPerDb(String argName) { - if (options.useLocalDateTimeOnly()) { + if (options.useClientClock()) { return namedArg(argName, adaptor.nullLocalDateTime(LocalDateTime.now())); } return namedArg(argName, new RewriteArg(options.flavor().dbTimeMillis())); @@ -602,7 +629,7 @@ public class SqlInsertImpl implements SqlInsert { } rs = ps.getGeneratedKeys(); final ResultSet finalRs = rs; - T result = handler.process(new RowsAdapter(finalRs, options)); + T result = handler.process(new RowsAdapter(finalRs)); metric.checkpoint("read"); isSuccess = true; return result; diff --git a/jdbc-query/src/main/java/org/xbib/jdbc/query/SqlSelect.java b/jdbc-query/src/main/java/org/xbib/jdbc/query/SqlSelect.java index e97c8a3..9fc950d 100644 --- a/jdbc-query/src/main/java/org/xbib/jdbc/query/SqlSelect.java +++ b/jdbc-query/src/main/java/org/xbib/jdbc/query/SqlSelect.java @@ -1,9 +1,11 @@ package org.xbib.jdbc.query; import java.math.BigDecimal; +import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; -import java.time.ZoneId; +import java.time.OffsetDateTime; +import java.time.ZonedDateTime; import java.util.List; /** @@ -39,13 +41,29 @@ public interface SqlSelect { SqlSelect argString( String argName, String arg); + SqlSelect argInstant(Instant arg); + + SqlSelect argInstant(String argName, Instant arg); + SqlSelect argLocalDateTime(LocalDateTime arg); SqlSelect argLocalDateTime(String argName, LocalDateTime arg); + SqlSelect argOffsetDateTime(OffsetDateTime arg); + + SqlSelect argOffsetDateTime(String argName, OffsetDateTime arg); + + SqlSelect argZonedDateTime(ZonedDateTime arg); + + SqlSelect argZonedDateTime(String argName, ZonedDateTime arg); + SqlSelect argLocalDate(LocalDate arg); - SqlSelect argLocalDate( String argName, LocalDate arg); + SqlSelect argLocalDate(String argName, LocalDate arg); + + SqlSelect argInstantNowPerDb(); + + SqlSelect argInstantNowPerDb(String argName); SqlSelect argLocalDateTimeNowPerDb(); @@ -113,13 +131,17 @@ public interface SqlSelect { */ List<String> queryStrings(); - LocalDateTime queryLocalDateTimeOrNull(); + Instant queryInstantOrNull(); - LocalDateTime queryLocalDateTimeOrNull(ZoneId zoneId); + List<Instant> queryInstants(); + + LocalDateTime queryLocalDateTimeOrNull(); List<LocalDateTime> queryLocalDateTimes(); - List<LocalDateTime> queryLocalDateTimes(ZoneId zoneId); + ZonedDateTime queryZonedDateTimeOrNull(); + + List<ZonedDateTime> queryZonedDateTimes(); LocalDate queryLocalDateOrNull(); diff --git a/jdbc-query/src/main/java/org/xbib/jdbc/query/SqlSelectImpl.java b/jdbc-query/src/main/java/org/xbib/jdbc/query/SqlSelectImpl.java index ea3267a..91d47ce 100644 --- a/jdbc-query/src/main/java/org/xbib/jdbc/query/SqlSelectImpl.java +++ b/jdbc-query/src/main/java/org/xbib/jdbc/query/SqlSelectImpl.java @@ -9,9 +9,11 @@ import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; -import java.time.ZoneId; +import java.time.OffsetDateTime; +import java.time.ZonedDateTime; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -24,7 +26,7 @@ import java.util.logging.Logger; */ public class SqlSelectImpl implements SqlSelect { - private static final Logger logger = Logger.getLogger(Database.class.getName()); + private static final Logger logger = Logger.getLogger(SqlSelectImpl.class.getName()); private final Connection connection; @@ -134,7 +136,17 @@ public class SqlSelectImpl implements SqlSelect { public SqlSelect argString(String argName, String arg) { return namedArg(argName, adaptor.nullString(arg)); } - + + @Override + public SqlSelect argInstant(Instant arg) { + return positionalArg(adaptor.nullInstant(arg)); + } + + @Override + public SqlSelect argInstant(String argName, Instant arg) { + return namedArg(argName, adaptor.nullInstant(arg)); + } + @Override public SqlSelect argLocalDateTime(LocalDateTime arg) { return positionalArg(adaptor.nullLocalDateTime(arg)); @@ -144,7 +156,27 @@ public class SqlSelectImpl implements SqlSelect { public SqlSelect argLocalDateTime(String argName, LocalDateTime arg) { return namedArg(argName, adaptor.nullLocalDateTime(arg)); } - + + @Override + public SqlSelect argOffsetDateTime(OffsetDateTime arg) { + return positionalArg(adaptor.nullOffsetDateTime(arg)); + } + + @Override + public SqlSelect argOffsetDateTime(String argName, OffsetDateTime arg) { + return namedArg(argName, adaptor.nullOffsetDateTime(arg)); + } + + @Override + public SqlSelect argZonedDateTime(ZonedDateTime arg) { + return positionalArg(adaptor.nullZonedDateTime(arg)); + } + + @Override + public SqlSelect argZonedDateTime(String argName, ZonedDateTime arg) { + return namedArg(argName, adaptor.nullZonedDateTime(arg)); + } + @Override public SqlSelect argLocalDate(LocalDate arg) { return positionalArg(adaptor.nullLocalDate(arg)); @@ -155,9 +187,25 @@ public class SqlSelectImpl implements SqlSelect { return namedArg(argName, adaptor.nullLocalDate(arg)); } + @Override + public SqlSelect argInstantNowPerDb() { + if (options.useClientClock()) { + return positionalArg(adaptor.nullInstant(Instant.now())); + } + return positionalArg(new RewriteArg(options.flavor().dbTimeMillis())); + } + + @Override + public SqlSelect argInstantNowPerDb(String argName) { + if (options.useClientClock()) { + return namedArg(argName, adaptor.nullInstant(Instant.now())); + } + return namedArg(argName, new RewriteArg(options.flavor().dbTimeMillis())); + } + @Override public SqlSelect argLocalDateTimeNowPerDb() { - if (options.useLocalDateTimeOnly()) { + if (options.useClientClock()) { return positionalArg(adaptor.nullLocalDateTime(LocalDateTime.now())); } return positionalArg(new RewriteArg(options.flavor().dbTimeMillis())); @@ -165,7 +213,7 @@ public class SqlSelectImpl implements SqlSelect { @Override public SqlSelect argLocalDateTimeNowPerDb(String argName) { - if (options.useLocalDateTimeOnly()) { + if (options.useClientClock()) { return namedArg(argName, adaptor.nullLocalDateTime(LocalDateTime.now())); } return namedArg(argName, new RewriteArg(options.flavor().dbTimeMillis())); @@ -429,17 +477,37 @@ public class SqlSelectImpl implements SqlSelect { return result; }); } - + @Override - public LocalDateTime queryLocalDateTimeOrNull() { - return queryLocalDateTimeOrNull(null); + public Instant queryInstantOrNull() { + return queryWithTimeout(rs -> { + if (rs.next()) { + return rs.getInstantOrNull(1); + } + return null; + }); } @Override - public LocalDateTime queryLocalDateTimeOrNull(ZoneId zoneId) { + public List<Instant> queryInstants() { + return queryWithTimeout(rs -> { + List<Instant> result = new ArrayList<>(); + while (rs.next()) { + Instant value = rs.getInstantOrNull(1); + if (value != null) { + result.add(value); + } + } + return result; + }); + } + + + @Override + public LocalDateTime queryLocalDateTimeOrNull() { return queryWithTimeout(rs -> { if (rs.next()) { - return rs.getLocalDateTimeOrNull(1, zoneId); + return rs.getLocalDateTimeOrNull(1); } return null; }); @@ -447,15 +515,34 @@ public class SqlSelectImpl implements SqlSelect { @Override public List<LocalDateTime> queryLocalDateTimes() { - return queryLocalDateTimes(null); - } - - @Override - public List<LocalDateTime> queryLocalDateTimes(ZoneId zoneId) { return queryWithTimeout(rs -> { List<LocalDateTime> result = new ArrayList<>(); while (rs.next()) { - LocalDateTime value = rs.getLocalDateTimeOrNull(1, zoneId); + LocalDateTime value = rs.getLocalDateTimeOrNull(1); + if (value != null) { + result.add(value); + } + } + return result; + }); + } + + @Override + public ZonedDateTime queryZonedDateTimeOrNull() { + return queryWithTimeout(rs -> { + if (rs.next()) { + return rs.getZonedDateTimeOrNull(1); + } + return null; + }); + } + + @Override + public List<ZonedDateTime> queryZonedDateTimes() { + return queryWithTimeout(rs -> { + List<ZonedDateTime> result = new ArrayList<>(); + while (rs.next()) { + ZonedDateTime value = rs.getZonedDateTimeOrNull(1); if (value != null) { result.add(value); } @@ -605,9 +692,9 @@ public class SqlSelectImpl implements SqlSelect { adaptor.addParameters(ps, parameters); metric.checkpoint("prep"); rs = ps.executeQuery(); + final ResultSet resultSet = rs; metric.checkpoint("exec"); - final ResultSet finalRs = rs; - T result = handler.process(new RowsAdapter(finalRs, options)); + T result = handler.process(new RowsAdapter(resultSet)); metric.checkpoint("read"); isSuccess = true; return result; diff --git a/jdbc-query/src/main/java/org/xbib/jdbc/query/SqlUpdateImpl.java b/jdbc-query/src/main/java/org/xbib/jdbc/query/SqlUpdateImpl.java index 2512072..f1bfe12 100644 --- a/jdbc-query/src/main/java/org/xbib/jdbc/query/SqlUpdateImpl.java +++ b/jdbc-query/src/main/java/org/xbib/jdbc/query/SqlUpdateImpl.java @@ -142,7 +142,7 @@ public class SqlUpdateImpl implements SqlUpdate { @Override public SqlUpdate argLocalDateTimeNowPerDb() { - if (options.useLocalDateTimeOnly()) { + if (options.useClientClock()) { return positionalArg(adaptor.nullLocalDateTime(LocalDateTime.now())); } return positionalArg(new RewriteArg(options.flavor().dbTimeMillis())); @@ -150,7 +150,7 @@ public class SqlUpdateImpl implements SqlUpdate { @Override public SqlUpdate argLocalDateTimeNowPerDb(String argName) { - if (options.useLocalDateTimeOnly()) { + if (options.useClientClock()) { return namedArg(argName, adaptor.nullLocalDateTime(LocalDateTime.now())); } return namedArg(argName, new RewriteArg(options.flavor().dbTimeMillis())); diff --git a/jdbc-query/src/main/java/org/xbib/jdbc/query/StatementAdapter.java b/jdbc-query/src/main/java/org/xbib/jdbc/query/StatementAdapter.java index f7109c2..40a8f98 100644 --- a/jdbc-query/src/main/java/org/xbib/jdbc/query/StatementAdapter.java +++ b/jdbc-query/src/main/java/org/xbib/jdbc/query/StatementAdapter.java @@ -11,9 +11,13 @@ import java.sql.SQLException; import java.sql.Statement; import java.sql.Timestamp; import java.sql.Types; +import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.OffsetDateTime; import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; import java.util.Date; import java.util.List; import java.util.logging.Level; @@ -25,8 +29,6 @@ import java.util.stream.Collectors; */ public class StatementAdapter { - private static final Logger logger = Logger.getLogger(StatementAdapter.class.getName()); - private final Options options; public StatementAdapter(Options options) { @@ -53,8 +55,7 @@ public class StatementAdapter { + " or use SqlNull in place of null values to this query.", e); } ps.setNull(i + 1, parameterType); - } else if (parameter instanceof SqlNull) { - SqlNull sqlNull = (SqlNull) parameter; + } else if (parameter instanceof SqlNull sqlNull) { if (options.useBytesForBlob() && sqlNull.getType() == Types.BLOB) { // The setNull() seems more correct, but PostgreSQL chokes on it ps.setBytes(i + 1, null); @@ -63,13 +64,9 @@ public class StatementAdapter { } } else if (parameter instanceof java.sql.Date) { ps.setDate(i + 1, (java.sql.Date) parameter); - } else if (parameter instanceof Date) { - Date date = (Date) parameter; + } else if (parameter instanceof Date date) { LocalDateTime localDateTime = LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()); ps.setTimestamp(i + 1, Timestamp.valueOf(localDateTime)); - // this will correct the millis and nanos according to the JDBC spec - // if a correct Timestamp is passed in, this will detect that and leave it alone - //ps.setTimestamp(i + 1, toSqlTimestamp((Date) parameter), options.calendarForTimestamps()); } else if (parameter instanceof Reader) { if (options.useStringForClob()) { try (BufferedReader reader = new BufferedReader((Reader) parameter)) { @@ -100,12 +97,20 @@ public class StatementAdapter { } } + public Object nullInstant(Instant arg) { + return arg == null ? new SqlNull(Types.TIMESTAMP) : Timestamp.valueOf(arg.atOffset(ZoneOffset.UTC).toLocalDateTime()); + } + public Object nullLocalDateTime(LocalDateTime arg) { return arg == null ? new SqlNull(Types.TIMESTAMP) : Timestamp.valueOf(arg); } - public Object nullLocalDateTime(LocalDateTime arg, ZoneId zoneId) { - return arg == null ? new SqlNull(Types.TIMESTAMP) : Timestamp.valueOf(arg.atZone(zoneId).toLocalDateTime()); + public Object nullZonedDateTime(ZonedDateTime arg) { + return arg == null ? new SqlNull(Types.TIMESTAMP) : Timestamp.valueOf(arg.toLocalDateTime()); + } + + public Object nullOffsetDateTime(OffsetDateTime arg) { + return arg == null ? new SqlNull(Types.TIMESTAMP) : Timestamp.valueOf(arg.toLocalDateTime()); } public Object nullLocalDate(LocalDate arg) { diff --git a/jdbc-query/src/main/java/org/xbib/jdbc/query/flavor/Derby.java b/jdbc-query/src/main/java/org/xbib/jdbc/query/flavor/Derby.java index 50f05ff..9628aa6 100644 --- a/jdbc-query/src/main/java/org/xbib/jdbc/query/flavor/Derby.java +++ b/jdbc-query/src/main/java/org/xbib/jdbc/query/flavor/Derby.java @@ -95,14 +95,24 @@ public class Derby implements Flavor { return "blob"; } + @Override + public String typeInstant() { + return "timestamp"; + } + @Override public String typeLocalDateTime() { return "timestamp"; } @Override - public String columnTypeLocalDateTime() { - return "timestamp"; + public String typeOffsetDateTime() { + return "timestamptz"; + } + + @Override + public String typeZonedDateTime() { + return "timestamptz"; } @Override diff --git a/jdbc-query/src/main/java/org/xbib/jdbc/query/flavor/H2.java b/jdbc-query/src/main/java/org/xbib/jdbc/query/flavor/H2.java index 352e74f..9897b1b 100644 --- a/jdbc-query/src/main/java/org/xbib/jdbc/query/flavor/H2.java +++ b/jdbc-query/src/main/java/org/xbib/jdbc/query/flavor/H2.java @@ -95,14 +95,24 @@ public class H2 implements Flavor { return "blob(2G)"; } + @Override + public String typeInstant() { + return "timestamp"; + } + @Override public String typeLocalDateTime() { return "timestamp(3)"; } @Override - public String columnTypeLocalDateTime() { - return "timestamp"; + public String typeOffsetDateTime() { + return "timestamptz"; + } + + @Override + public String typeZonedDateTime() { + return "timestamptz"; } @Override diff --git a/jdbc-query/src/main/java/org/xbib/jdbc/query/flavor/Hsql.java b/jdbc-query/src/main/java/org/xbib/jdbc/query/flavor/Hsql.java index e05de29..84b0196 100644 --- a/jdbc-query/src/main/java/org/xbib/jdbc/query/flavor/Hsql.java +++ b/jdbc-query/src/main/java/org/xbib/jdbc/query/flavor/Hsql.java @@ -95,14 +95,24 @@ public class Hsql implements Flavor { return "blob(2G)"; } + @Override + public String typeInstant() { + return "timestamp"; + } + @Override public String typeLocalDateTime() { + return "timestamp"; + } + + @Override + public String typeOffsetDateTime() { return "timestamp with time zone"; } @Override - public String columnTypeLocalDateTime() { - return "TIMESTAMP WITH TIME ZONE"; + public String typeZonedDateTime() { + return "timestamp with time zone"; } @Override diff --git a/jdbc-query/src/test/java/org/xbib/jdbc/query/test/HsqldbTest.java b/jdbc-query/src/test/java/org/xbib/jdbc/query/test/HsqldbTest.java index 73b565e..075a03c 100644 --- a/jdbc-query/src/test/java/org/xbib/jdbc/query/test/HsqldbTest.java +++ b/jdbc-query/src/test/java/org/xbib/jdbc/query/test/HsqldbTest.java @@ -1,6 +1,5 @@ package org.xbib.jdbc.query.test; -import java.util.logging.Logger; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.xbib.jdbc.query.Config; @@ -24,15 +23,18 @@ import static org.junit.jupiter.api.Assertions.assertEquals; */ public class HsqldbTest extends CommonTest { - private static final Logger logger = Logger.getLogger(HsqldbTest.class.getName()); - @Override - protected DatabaseProvider createDatabaseProvider(OptionsOverride options) throws Exception { + protected DatabaseProvider createDatabaseProvider(OptionsOverride options) { String propertiesFile = "hsqldb.properties"; Config config = ConfigSupplier.of() .properties(getClass().getResourceAsStream(propertiesFile)) .get(); - return DatabaseProvider.builder(config) + return DatabaseProvider.builder(getClass().getClassLoader(), + config.getString("database.url"), + null, + null, + config.getString("database.user"), + config.getString("database.password")) .withSqlParameterLogging() .withSqlInExceptionMessages() .withOptions(options) @@ -79,7 +81,7 @@ public class HsqldbTest extends CommonTest { .argClobString("hello again") .argBlobBytes(new byte[]{'1', '2'}) .argBoolean(true) - .argLocalDateTime(now) + .argLocalDateTime(localDateTimeNow) .argLocalDate(localDateNow) .insert(1); @@ -95,7 +97,7 @@ public class HsqldbTest extends CommonTest { .argClobString("bye again") .argBlobBytes(new byte[]{'3', '4'}) .argBoolean(false) - .argLocalDateTime(now) + .argLocalDateTime(localDateTimeNow) .argLocalDate(localDateNow) .insert(1); @@ -150,7 +152,7 @@ public class HsqldbTest extends CommonTest { .argClobString("str_lob", "bye again") .argBlobBytes("bin_blob", new byte[]{'3', '4'}) .argString("boolean_flag", "N")//.argBoolean("boolean_flag", false) - .argLocalDateTime("date_millis", now) + .argLocalDateTime("date_millis", localDateTimeNow) .argLocalDate("local_date", localDateNow), new SqlArgs() .argInteger("nbr_integer", Integer.MAX_VALUE) @@ -163,7 +165,7 @@ public class HsqldbTest extends CommonTest { .argClobString("str_lob", "hello again") .argBlobBytes("bin_blob", new byte[]{'1', '2'}) .argString("boolean_flag", "Y")//.argBoolean("boolean_flag", true) - .argLocalDateTime("date_millis", now) + .argLocalDateTime("date_millis", localDateTimeNow) .argLocalDate("local_date", localDateNow)), db.toSelect("select nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal," + " str_varchar, str_fixed, str_lob, bin_blob, boolean_flag, date_millis, local_date from dbtest2 order by 1") diff --git a/jdbc-query/src/test/java/org/xbib/jdbc/query/test/RowStub.java b/jdbc-query/src/test/java/org/xbib/jdbc/query/test/RowStub.java index 0023d2b..09b7b32 100644 --- a/jdbc-query/src/test/java/org/xbib/jdbc/query/test/RowStub.java +++ b/jdbc-query/src/test/java/org/xbib/jdbc/query/test/RowStub.java @@ -10,9 +10,12 @@ import java.io.StringReader; import java.math.BigDecimal; import java.sql.ResultSetMetaData; import java.sql.Types; +import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.OffsetDateTime; import java.time.ZoneId; +import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.List; @@ -578,6 +581,23 @@ public class RowStub { return new ByteArrayInputStream(getBlobBytesOrZeroLen(columnName)); } + @Override + public Instant getInstantOrNull() { + return toInstant(rows.get(row)[++col]); + } + + @Override + public Instant getInstantOrNull(int columnOneBased) { + col = columnOneBased; + return toInstant(rows.get(row)[columnOneBased - 1]); + } + + @Override + public Instant getInstantOrNull(String columnName) { + col = columnIndexByName(columnName) + 1; + return toInstant(rows.get(row)[columnIndexByName(columnName)]); + } + @Override public LocalDateTime getLocalDateTimeOrNull() { return toLocalDateTime(rows.get(row)[++col]); @@ -589,12 +609,6 @@ public class RowStub { return toLocalDateTime(rows.get(row)[columnOneBased - 1]); } - @Override - public LocalDateTime getLocalDateTimeOrNull(int columnOneBased, ZoneId zoneId) { - col = columnOneBased; - return toLocalDateTime(rows.get(row)[columnOneBased - 1], zoneId); - } - @Override public LocalDateTime getLocalDateTimeOrNull(String columnName) { col = columnIndexByName(columnName) + 1; @@ -602,36 +616,50 @@ public class RowStub { } @Override - public LocalDateTime getLocalDateTimeOrNull(String columnName, ZoneId zoneId) { - return null; + public OffsetDateTime getOffsetDateTimeOrNull() { + return toOffsetDateTime(rows.get(row)[++col]); } - /** - * Returns a java.time.LocalDate. It will have no timezone or other time data. - * If you require time, use the Date APIs instead. - */ + @Override + public OffsetDateTime getOffsetDateTimeOrNull(int columnOneBased) { + col = columnOneBased; + return toOffsetDateTime(rows.get(row)[columnOneBased - 1]); + } + + @Override + public OffsetDateTime getOffsetDateTimeOrNull(String columnName) { + col = columnIndexByName(columnName) + 1; + return toOffsetDateTime(rows.get(row)[columnIndexByName(columnName)]); + } + + @Override + public ZonedDateTime getZonedDateTimeOrNull() { + return toZonedDateTime(rows.get(row)[++col]); + } + + @Override + public ZonedDateTime getZonedDateTimeOrNull(int columnOneBased) { + col = columnOneBased; + return toZonedDateTime(rows.get(row)[columnOneBased - 1]); + } + + @Override + public ZonedDateTime getZonedDateTimeOrNull(String columnName) { + col = columnIndexByName(columnName) + 1; + return toZonedDateTime(rows.get(row)[columnIndexByName(columnName)]); + } @Override public LocalDate getLocalDateOrNull() { return toLocalDate(rows.get(row)[++col]); } - /** - * Returns a java.time.LocalDate. It will have no timezone or other time data. - * If you require time, use the Date APIs instead. - */ - @Override public LocalDate getLocalDateOrNull(int columnOneBased) { col = columnOneBased; return toLocalDate(rows.get(row)[columnOneBased - 1]); } - /** - * Returns a java.time.LocalDate. It will have no timezone or other time data. - * If you require time, use the Date APIs instead. - */ - @Override public LocalDate getLocalDateOrNull(String columnName) { col = columnIndexByName(columnName) + 1; @@ -707,32 +735,60 @@ public class RowStub { return (BigDecimal) o; } - private LocalDateTime toLocalDateTime(Object o) { - return toLocalDateTime(o, ZoneId.systemDefault()); + private Instant toInstant(Object o) { + if (o instanceof String s) { + if (s.length() == "yyyy-MM-dd".length()) { + return Instant.parse(s); + } + if (s.length() == "yyyy-MM-ddThh:mm:ss".length()) { + return Instant.parse(s); + } + throw new DatabaseException("Didn't understand date string: " + s); + } + return (Instant) o; } - private LocalDateTime toLocalDateTime(Object o, ZoneId zoneId) { - if (o instanceof String) { - String s = (String) o; + private LocalDateTime toLocalDateTime(Object o) { + if (o instanceof String s) { if (s.length() == "yyyy-MM-dd".length()) { return LocalDateTime.parse(s, DateTimeFormatter.ofPattern("yyyy-MM-dd")) - .atZone(zoneId).toLocalDateTime(); + .atZone(ZoneId.systemDefault()).toLocalDateTime(); } if (s.length() == "yyyy-MM-ddThh:mm:ss".length()) { return LocalDateTime.parse(s, DateTimeFormatter.ofPattern("yyyy-MM-ddThh:mm:ss")) - .atZone(zoneId).toLocalDateTime(); + .atZone(ZoneId.systemDefault()).toLocalDateTime(); } throw new DatabaseException("Didn't understand date string: " + s); } return (LocalDateTime) o; } - /** - * Returns a LocalDate (no time). - * If the object is a String, it should be in ISO 8601 format. - * - * @return a LocalDate representation of the object - */ + private OffsetDateTime toOffsetDateTime(Object o) { + if (o instanceof String s) { + if (s.length() == "yyyy-MM-dd".length()) { + return OffsetDateTime.parse(s, DateTimeFormatter.ofPattern("yyyy-MM-dd")); + } + if (s.length() == "yyyy-MM-ddThh:mm:ss".length()) { + return OffsetDateTime.parse(s, DateTimeFormatter.ofPattern("yyyy-MM-ddThh:mm:ss")); + } + throw new DatabaseException("Didn't understand date string: " + s); + } + return (OffsetDateTime) o; + } + + private ZonedDateTime toZonedDateTime(Object o) { + if (o instanceof String s) { + if (s.length() == "yyyy-MM-dd".length()) { + return ZonedDateTime.parse(s, DateTimeFormatter.ofPattern("yyyy-MM-dd")); + } + if (s.length() == "yyyy-MM-ddThh:mm:ss".length()) { + return ZonedDateTime.parse(s, DateTimeFormatter.ofPattern("yyyy-MM-ddThh:mm:ss")); + } + throw new DatabaseException("Didn't understand date string: " + s); + } + return (ZonedDateTime) o; + } + private LocalDate toLocalDate(Object o) { if (o instanceof String) { return LocalDate.parse((String) o); diff --git a/jdbc-sqlserver/build.gradle b/jdbc-sqlserver/build.gradle deleted file mode 100644 index 749572c..0000000 --- a/jdbc-sqlserver/build.gradle +++ /dev/null @@ -1,10 +0,0 @@ -dependencies { - api project(':jdbc-query') - testImplementation project(':jdbc-test') - testImplementation testLibs.testcontainers - testImplementation testLibs.testcontainers.junit.jupiter -} - -test { - systemProperty 'user.timezone', 'GMT' -} diff --git a/jdbc-sqlserver/src/main/java/module-info.java b/jdbc-sqlserver/src/main/java/module-info.java deleted file mode 100644 index e3555d2..0000000 --- a/jdbc-sqlserver/src/main/java/module-info.java +++ /dev/null @@ -1,10 +0,0 @@ -import org.xbib.jdbc.query.Flavor; -import org.xbib.jdbc.sqlserver.SqlServer; - -module org.xbib.jdbc.sqlserver { - requires org.xbib.jdbc.query; - requires java.sql; - uses Flavor; - exports org.xbib.jdbc.sqlserver; - provides Flavor with SqlServer; -} diff --git a/jdbc-sqlserver/src/main/java/org/xbib/jdbc/sqlserver/SqlServer.java b/jdbc-sqlserver/src/main/java/org/xbib/jdbc/sqlserver/SqlServer.java deleted file mode 100644 index 2d47540..0000000 --- a/jdbc-sqlserver/src/main/java/org/xbib/jdbc/sqlserver/SqlServer.java +++ /dev/null @@ -1,214 +0,0 @@ -package org.xbib.jdbc.sqlserver; - -import org.xbib.jdbc.query.Flavor; - -import java.sql.PreparedStatement; -import java.sql.SQLException; - -public class SqlServer implements Flavor { - - public SqlServer() { - } - - @Override - public String getName() { - return "sqlServer"; - } - - @Override - public boolean supports(String url) { - return url.startsWith("jdbc:sqlserver:"); - } - - @Override - public String driverClass() { - return "com.microsoft.sqlserver.jdbc.SQLServerDriver"; - } - - @Override - public String normalizeTableName(String tableName) { - if (tableName == null) { - return tableName; - } - if (tableName.length() > 2) { - if (tableName.startsWith("\"") && tableName.endsWith("\"")) { - return tableName.substring(1, tableName.length() - 1); - } - } - return tableName; - } - - @Override - public String typeFloat() { - return "float(24)"; - } - - @Override - public void setFloat(PreparedStatement preparedStatement, int i, Float floatValue) throws SQLException { - preparedStatement.setFloat(i, floatValue); - } - - @Override - public String typeDouble() { - return "float(53)"; - } - - @Override - public void setDouble(PreparedStatement preparedStatement, int i, Double doubleValue) throws SQLException { - preparedStatement.setDouble(i, doubleValue); - } - - @Override - public String typeBigDecimal(int size, int precision) { - return "numeric(" + size + "," + precision + ")"; - } - - @Override - public String typeInteger() { - return "numeric(10)"; - } - - @Override - public String typeBoolean() { - return "char(1)"; - } - - @Override - public String typeLong() { - return "numeric(19)"; - } - - @Override - public String typeLocalDateTime() { - return "datetime2(3)"; - } - - @Override - public String columnTypeLocalDateTime() { - return "datetime2"; - } - - @Override - public String typeLocalDate() { - return "date"; - } - - @Override - public boolean useStringForClob() { - return false; - } - - @Override - public boolean useBytesForBlob() { - return false; - } - - @Override - public String sequenceNextVal(String sequenceName) { - return "next value for " + sequenceName; - } - - @Override - public String sequenceSelectNextVal(String sequenceName) { - return "select next value for " + sequenceName; - } - - @Override - public String sequenceDrop(String dbtestSeq) { - return "drop sequence " + dbtestSeq; - } - - @Override - public String tableDrop(String table) { - return "drop table " + table; - } - - @Override - public String typeStringVar(int length) { - return "varchar(" + length + ")"; - } - - @Override - public String typeStringFixed(int length) { - return "char(" + length + ")"; - } - - @Override - public String typeClob() { - return "varchar(max)"; - } - - @Override - public String typeBlob() { - return "varbinary(max)"; - } - - @Override - public String sequenceOrderClause(boolean order) { - // Not supported - return ""; - } - - @Override - public String sequenceCycleClause(boolean cycle) { - return cycle ? " cycle" : " no cycle"; - } - - @Override - public boolean supportsInsertReturning() { - return true; - } - - @Override - public String dbTimeMillis() { - return "current_timestamp"; - } - - @Override - public String sequenceCacheClause(int nbrValuesToCache) { - if (nbrValuesToCache < 2) { - return " no cache"; - } - return " cache " + nbrValuesToCache; - } - - @Override - public String fromAny() { - return ""; - } - - @Override - public String sequenceOptions() { - return ""; - } - - @Override - public boolean isAutoCommitOnly() { - return false; - } - - @Override - public String queueLength(String table) { - throw new UnsupportedOperationException(); - } - - @Override - public String writeNextIntoQueue(String table) { - throw new UnsupportedOperationException(); - } - - @Override - public String readNextFromQueue(String table) { - throw new UnsupportedOperationException(); - } - - @Override - public String succeedInQueue(String table) { - throw new UnsupportedOperationException(); - } - - @Override - public String failInQueue(String table) { - throw new UnsupportedOperationException(); - } -} diff --git a/jdbc-sqlserver/src/main/resources/META-INF/services/org.xbib.jdbc.query.Flavor b/jdbc-sqlserver/src/main/resources/META-INF/services/org.xbib.jdbc.query.Flavor deleted file mode 100644 index a1e1dec..0000000 --- a/jdbc-sqlserver/src/main/resources/META-INF/services/org.xbib.jdbc.query.Flavor +++ /dev/null @@ -1 +0,0 @@ -org.xbib.jdbc.sqlserver.SqlServer \ No newline at end of file diff --git a/jdbc-sqlserver/src/test/java/org/xbib/jdbc/sqlserver/test/SqlServerTest.java b/jdbc-sqlserver/src/test/java/org/xbib/jdbc/sqlserver/test/SqlServerTest.java deleted file mode 100644 index a8e28d9..0000000 --- a/jdbc-sqlserver/src/test/java/org/xbib/jdbc/sqlserver/test/SqlServerTest.java +++ /dev/null @@ -1,87 +0,0 @@ -package org.xbib.jdbc.sqlserver.test; - -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import org.xbib.jdbc.query.Config; -import org.xbib.jdbc.query.ConfigSupplier; -import org.xbib.jdbc.query.DatabaseProvider; -import org.xbib.jdbc.query.OptionsOverride; -import org.xbib.jdbc.query.Schema; -import org.xbib.jdbc.test.CommonTest; - -import static org.junit.jupiter.api.Assertions.assertArrayEquals; - -/** - * Exercise Database functionality with a real SQL server database. - */ -@Disabled -public class SqlServerTest extends CommonTest { - @Override - protected DatabaseProvider createDatabaseProvider(OptionsOverride options) throws Exception { - String propertiesFile = System.getProperty("local.properties", "local.properties"); - Config config = ConfigSupplier.of() - .systemProperties() - .properties(propertiesFile) - .excludePrefix("database.") - .removePrefix("sqlserver.") - .get(); - return DatabaseProvider.builder(config) - .withSqlParameterLogging() - .withSqlInExceptionMessages() - .withOptions(options).build(); - } - - @Disabled("SQL Server prohibits NaN and Infinity") - @Test - public void argFloatNaN() { - super.argFloatNaN(); - } - - @Disabled("SQL Server prohibits NaN and Infinity") - @Test - public void argFloatInfinity() { - super.argFloatInfinity(); - } - - @Disabled("SQL Server prohibits NaN and Infinity") - @Test - public void argDoubleNaN() { - super.argDoubleNaN(); - } - - @Disabled("SQL Server prohibits NaN and Infinity") - @Test - public void argDoubleInfinity() { - super.argDoubleInfinity(); - } - - @Disabled("SQL Server seems to have incorrect min value for float (rounds to zero)") - @Test - public void argFloatMinMax() { - super.argFloatMinMax(); - } - - @Disabled("SQL Server doesn't support the interval syntax for date arithmetic") - @Test - public void intervals() { - super.intervals(); - } - - /** - * SQL Server seems to have different behavior in that is does not convert - * column names to uppercase (it preserves the case). - * I haven't figured out how to smooth over this difference, since all databases - * seem to respect the provided case when it is inside quotes, but don't provide - * a way to tell whether a particular parameter was quoted. - */ - @Override - @Test - public void metadataColumnNames() { - db.dropTableQuietly("dbtest"); - new Schema().addTable("dbtest").addColumn("pk").primaryKey().schema().execute(db); - db.toSelect("select Pk, Pk as Foo, Pk as \"Foo\" from dbtest").query(rs -> { - assertArrayEquals(new String[]{"Pk", "Foo", "Foo"}, rs.getColumnLabels()); - return null; - }); - } -} diff --git a/jdbc-sqlserver/src/test/resources/logging.properties b/jdbc-sqlserver/src/test/resources/logging.properties deleted file mode 100644 index 5885e4d..0000000 --- a/jdbc-sqlserver/src/test/resources/logging.properties +++ /dev/null @@ -1,10 +0,0 @@ -handlers=java.util.logging.FileHandler, java.util.logging.ConsoleHandler -.level=ALL -java.util.logging.SimpleFormatter.format=%1$tY-%1$tm-%1$td %1$tH:%1$tM:%1$tS.%1$tL %4$-7s [%3$s] %5$s %6$s%n -java.util.logging.ConsoleHandler.level=ALL -java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter -java.util.logging.FileHandler.level=ALL -java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter -java.util.logging.FileHandler.pattern=build/database.log -jdk.event.security.level=INFO -javax.management.level=INFO diff --git a/jdbc-test/src/main/java/org/xbib/jdbc/test/CommonTest.java b/jdbc-test/src/main/java/org/xbib/jdbc/test/CommonTest.java index 6c5d084..1195c53 100644 --- a/jdbc-test/src/main/java/org/xbib/jdbc/test/CommonTest.java +++ b/jdbc-test/src/main/java/org/xbib/jdbc/test/CommonTest.java @@ -29,8 +29,10 @@ import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.Month; +import java.time.OffsetDateTime; import java.time.ZoneId; import java.time.ZoneOffset; +import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.ArrayList; @@ -58,29 +60,33 @@ public abstract class CommonTest { private static final Logger logger = Logger.getLogger(CommonTest.class.getName()); - final static String TEST_TABLE_NAME = "dbtest"; - protected static DatabaseProvider dbp; protected Database db; - protected LocalDateTime now; + protected LocalDateTime localDateTimeNow; protected LocalDate localDateNow; + protected OffsetDateTime offsetDateTimeNow; + + protected ZonedDateTime zonedDateTimeNow; + protected abstract DatabaseProvider createDatabaseProvider(OptionsOverride options) throws Exception; @BeforeEach public void setupJdbc() throws Exception { - now = LocalDateTime.now().truncatedTo(ChronoUnit.MILLIS); + localDateTimeNow = LocalDateTime.now().truncatedTo(ChronoUnit.MILLIS); localDateNow = LocalDate.now(); + offsetDateTimeNow = OffsetDateTime.now(); + zonedDateTimeNow = ZonedDateTime.now(); dbp = createDatabaseProvider(new OptionsOverride() { }); db = dbp.get(); if (!db.probe(15)) { fail(); } - db.dropTableQuietly(TEST_TABLE_NAME); + db.dropTableQuietly("dbtest"); } @AfterEach @@ -99,12 +105,12 @@ public abstract class CommonTest { @Test public void tableExists() { - // Verify dbtest table does not exist - String lowercaseTable = TEST_TABLE_NAME.toLowerCase(); + // Verify table does not exist + String lowercaseTable = "dbtest"; testTableLookup(lowercaseTable); db.dropTableQuietly(lowercaseTable); // Let's try creating a table with an upper case name and verify it works - String uppercaseTable = TEST_TABLE_NAME.toUpperCase(); + String uppercaseTable = "DBTEST"; testTableLookup(uppercaseTable); db.dropTableQuietly(uppercaseTable); // Verify that null or empty name is handled gracefully @@ -127,8 +133,8 @@ public abstract class CommonTest { String camelCaseTableName = "\"DbTest\""; assertEquals(camelCaseTableName.substring(1, camelCaseTableName.length() - 1), db.flavor().normalizeTableName(camelCaseTableName)); - assertEquals(TEST_TABLE_NAME.toUpperCase(Locale.ENGLISH), - db.flavor().normalizeTableName(TEST_TABLE_NAME).toUpperCase(Locale.ENGLISH)); + assertEquals("DBTEST", + db.flavor().normalizeTableName("dbtest").toUpperCase(Locale.ENGLISH)); } @Test @@ -145,13 +151,29 @@ public abstract class CommonTest { .addColumn("str_lob").asClob().table() .addColumn("bin_blob").asBlob().table() .addColumn("date_millis").asLocalDateTime().table() - .addColumn("local_date").asLocalDate().table().schema().execute(db); + .addColumn("local_date").asLocalDate().table() + .addColumn("offset_date_time").asOffsetDateTime().table() + .addColumn("tz_date_time").asZonedateTime().table() + .schema() + .execute(db); BigDecimal bigDecimal = new BigDecimal("5.3"); - db.toInsert("insert into dbtest values (?,?,?,?,?,?,?,?,?,?,?)").argInteger(1).argLong(2L).argFloat(3.2f).argDouble(4.2) - .argBigDecimal(bigDecimal).argString("Hello").argString("T").argClobString("World") - .argBlobBytes("More".getBytes()).argLocalDateTime(now).argLocalDate(localDateNow).insert(1); + db.toInsert("insert into dbtest values (?,?,?,?,?,?,?,?,?,?,?,?,?)") + .argInteger(1) + .argLong(2L) + .argFloat(3.2f) + .argDouble(4.2) + .argBigDecimal(bigDecimal) + .argString("Hello") + .argString("T") + .argClobString("World") + .argBlobBytes("More".getBytes()) + .argLocalDateTime(localDateTimeNow) + .argLocalDate(localDateNow) + .argOffsetDateTime(offsetDateTimeNow) + .argZonedDateTime(zonedDateTimeNow) + .insert(1); db.toSelect("select nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal, str_varchar, str_fixed, str_lob, " - + "bin_blob, date_millis, local_date from dbtest") + + "bin_blob, date_millis, local_date, offset_date_time, tz_date_time from dbtest") .query((RowsHandler<Void>) rs -> { assertTrue(rs.next()); assertEquals(Integer.valueOf(1), rs.getIntegerOrNull(1)); @@ -190,15 +212,22 @@ public abstract class CommonTest { assertArrayEquals("More".getBytes(), rs.getBlobBytesOrNull("bin_blob")); assertArrayEquals("More".getBytes(), rs.getBlobBytesOrZeroLen(9)); assertArrayEquals("More".getBytes(), rs.getBlobBytesOrZeroLen("bin_blob")); - assertEquals(now, rs.getLocalDateTimeOrNull(10)); - assertEquals(now, rs.getLocalDateTimeOrNull("date_millis")); + assertEquals(localDateTimeNow, rs.getLocalDateTimeOrNull(10)); + assertEquals(localDateTimeNow, rs.getLocalDateTimeOrNull("date_millis")); assertEquals(localDateNow, rs.getLocalDateOrNull(11)); assertEquals(localDateNow, rs.getLocalDateOrNull("local_date")); + assertEquals(offsetDateTimeNow.truncatedTo(ChronoUnit.SECONDS), + rs.getOffsetDateTimeOrNull(12).truncatedTo(ChronoUnit.SECONDS)); + assertEquals(offsetDateTimeNow.truncatedTo(ChronoUnit.SECONDS), + rs.getOffsetDateTimeOrNull("offset_date_time").truncatedTo(ChronoUnit.SECONDS)); + // org.postgresql.util.PSQLException: conversion to class java.time.ZonedDateTime from timestamptz not supported + // assertEquals(zonedDateTimeNow, rs.getZonedDateTimeOrNull(13)); + // assertEquals(zonedDateTimeNow, rs.getZonedDateTimeOrNull("tz_date_time")); return null; }); // Repeat the above query, using the various methods that automatically infer the column db.toSelect("select nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal, str_varchar, str_fixed, str_lob, " - + "bin_blob, date_millis, local_date from dbtest") + + "bin_blob, date_millis, local_date, offset_date_time, tz_date_time from dbtest") .query((RowsHandler<Void>) rs -> { assertTrue(rs.next()); assertEquals(Integer.valueOf(1), rs.getIntegerOrNull()); @@ -210,12 +239,15 @@ public abstract class CommonTest { assertEquals("T", rs.getStringOrNull()); assertEquals("World", rs.getClobStringOrNull()); assertArrayEquals("More".getBytes(), rs.getBlobBytesOrNull()); - assertEquals(now, rs.getLocalDateTimeOrNull()); + assertEquals(localDateTimeNow, rs.getLocalDateTimeOrNull()); assertEquals(localDateNow, rs.getLocalDateOrNull()); + assertEquals(offsetDateTimeNow.truncatedTo(ChronoUnit.SECONDS), rs.getOffsetDateTimeOrNull().truncatedTo(ChronoUnit.SECONDS)); + // org.postgresql.util.PSQLException: conversion to class java.time.ZonedDateTime from timestamptz not supported + //assertEquals(zonedDateTimeNow, rs.getZonedDateTimeOrNull()); return null; }); db.toSelect("select nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal, str_varchar, str_fixed, str_lob, " - + "bin_blob, date_millis, local_date from dbtest") + + "bin_blob, date_millis, local_date, offset_date_time, tz_date_time from dbtest") .query((RowsHandler<Void>) rs -> { assertTrue(rs.next()); assertEquals(1, rs.getIntegerOrZero()); @@ -227,6 +259,11 @@ public abstract class CommonTest { assertEquals("T", rs.getStringOrEmpty()); assertEquals("World", rs.getClobStringOrEmpty()); assertArrayEquals("More".getBytes(), rs.getBlobBytesOrZeroLen()); + assertEquals(localDateTimeNow, rs.getLocalDateTimeOrNull()); + assertEquals(localDateNow, rs.getLocalDateOrNull()); + assertEquals(offsetDateTimeNow.truncatedTo(ChronoUnit.SECONDS), rs.getOffsetDateTimeOrNull().truncatedTo(ChronoUnit.SECONDS)); + // org.postgresql.util.PSQLException: conversion to class java.time.ZonedDateTime from timestamptz not supported + //assertEquals(zonedDateTimeNow, rs.getZonedDateTimeOrNull()); return null; }); db.toSelect("select str_lob, bin_blob from dbtest").query((RowsHandler<Void>) rs -> { @@ -275,16 +312,16 @@ public abstract class CommonTest { .argBigDecimal("bd", bigDecimal) .argString("s", "Hello") .argString("sf", "T") - .argLocalDateTime("date", now) + .argLocalDateTime("date", localDateTimeNow) .argLocalDate("local_date", localDateNow) .queryLongOrNull()); List<Long> result = db.toSelect("select count(*) from dbtest where nbr_integer=:i and nbr_long=:l and " + "abs(nbr_float-:f)<0.01 and abs(nbr_double-:d)<0.01 and nbr_big_decimal=:bd and str_varchar=:s " + "and str_fixed=:sf and date_millis=:date and local_date=:local_date").argInteger("i", 1).argLong("l", 2L).argFloat("f", 3.2f) .argDouble("d", 4.2).argBigDecimal("bd", bigDecimal).argString("s", "Hello").argString("sf", "T") - .argLocalDateTime("date", now).argLocalDate("local_date", localDateNow).queryLongs(); + .argLocalDateTime("date", localDateTimeNow).argLocalDate("local_date", localDateNow).queryLongs(); assertEquals(1, result.size()); - assertEquals(Long.valueOf(1), result.get(0)); + assertEquals(Long.valueOf(1), result.getFirst()); } @Test @@ -316,7 +353,7 @@ public abstract class CommonTest { .argString("T") .argClobString("World") .argBlobBytes("More".getBytes()) - .argLocalDateTime(now) + .argLocalDateTime(localDateTimeNow) .argLocalDate(localDateNow).insert()); db.toUpdate("update dbtest set nbr_integer=?, nbr_long=?, nbr_float=?, nbr_double=?, nbr_big_decimal=?, " + "str_varchar=?, str_fixed=?, str_lob=?, bin_blob=?, date_millis=?, local_date=?").argInteger(null).argLong(null) @@ -352,7 +389,7 @@ public abstract class CommonTest { assertEquals(1, db.toUpdate("update dbtest set nbr_integer=?, nbr_long=?, nbr_float=?, nbr_double=?, " + "nbr_big_decimal=?, str_varchar=?, str_fixed=?, str_lob=?, bin_blob=?, date_millis=?, local_date=?").argInteger(1) .argLong(2L).argFloat(3.2f).argDouble(4.2).argBigDecimal(bigDecimal).argString("Hello").argString("T") - .argClobString("World").argBlobBytes("More".getBytes()).argLocalDateTime(now).argLocalDate(localDateNow).update()); + .argClobString("World").argBlobBytes("More".getBytes()).argLocalDateTime(localDateTimeNow).argLocalDate(localDateNow).update()); db.toSelect("select nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal, str_varchar, str_fixed, str_lob, " + "bin_blob, date_millis, local_date from dbtest").query((RowsHandler<Void>) rs -> { assertTrue(rs.next()); @@ -374,8 +411,8 @@ public abstract class CommonTest { assertEquals("World", rs.getClobStringOrNull("str_lob")); assertArrayEquals("More".getBytes(), rs.getBlobBytesOrNull(9)); assertArrayEquals("More".getBytes(), rs.getBlobBytesOrNull("bin_blob")); - assertEquals(now, rs.getLocalDateTimeOrNull(10)); - assertEquals(now, rs.getLocalDateTimeOrNull("date_millis")); + assertEquals(localDateTimeNow, rs.getLocalDateTimeOrNull(10)); + assertEquals(localDateTimeNow, rs.getLocalDateTimeOrNull("date_millis")); assertEquals(localDateNow, rs.getLocalDateOrNull(11)); assertEquals(localDateNow, rs.getLocalDateOrNull("local_date")); return null; @@ -422,7 +459,7 @@ public abstract class CommonTest { .argLong(":b", 2L).argFloat(":c", 3.2f).argDouble(":d", 4.2).argBigDecimal(":e", bigDecimal) .argString(":f", "Hello").argString(":sf", "T") .argClobString(":g", "World").argBlobBytes(":h", "More".getBytes()) - .argLocalDateTime(":i", now).argLocalDate(":j", localDateNow).insert(1); + .argLocalDateTime(":i", localDateTimeNow).argLocalDate(":j", localDateNow).insert(1); db.toUpdate("update dbtest set nbr_integer=:a, nbr_long=:b, nbr_float=:c, nbr_double=:d, nbr_big_decimal=:e, " + "str_varchar=:f, str_fixed=:sf, str_lob=:g, bin_blob=:h, date_millis=:i, local_date=:j").argInteger(":a", null) .argLong(":b", null).argFloat(":c", null).argDouble(":d", null).argBigDecimal(":e", null) @@ -461,7 +498,7 @@ public abstract class CommonTest { .argLong(":b", 2L).argFloat(":c", 3.2f).argDouble(":d", 4.2).argBigDecimal(":e", bigDecimal) .argString(":f", "Hello").argString(":sf", "T") .argClobString(":g", "World").argBlobBytes(":h", "More".getBytes()) - .argLocalDateTime(":i", now).argLocalDate(":j", localDateNow).update(1); + .argLocalDateTime(":i", localDateTimeNow).argLocalDate(":j", localDateNow).update(1); db.toSelect("select nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal, str_varchar, str_fixed, str_lob, " + "bin_blob, date_millis, local_date from dbtest") .query((RowsHandler<Void>) rs -> { @@ -484,8 +521,8 @@ public abstract class CommonTest { assertEquals("World", rs.getClobStringOrNull("str_lob")); assertArrayEquals("More".getBytes(), rs.getBlobBytesOrNull(9)); assertArrayEquals("More".getBytes(), rs.getBlobBytesOrNull("bin_blob")); - assertEquals(now, rs.getLocalDateTimeOrNull(10)); - assertEquals(now, rs.getLocalDateTimeOrNull("date_millis")); + assertEquals(localDateTimeNow, rs.getLocalDateTimeOrNull(10)); + assertEquals(localDateTimeNow, rs.getLocalDateTimeOrNull("date_millis")); assertEquals(localDateNow, rs.getLocalDateOrNull(11)); assertEquals(localDateNow, rs.getLocalDateOrNull("local_date")); return null; @@ -595,16 +632,17 @@ public abstract class CommonTest { .addTable("dbtest") .addColumn(timestampColumnName).asLocalDateTime().table() .addColumn(dateColumnName).asLocalDate().table() - .schema().execute(db); + .schema() + .execute(db); db.toSelect("select * from dbtest").query((RowsHandler<Void>) rs -> { ResultSetMetaData metadata = rs.getMetadata(); for (int i = 1; i <= metadata.getColumnCount(); i++) { String columnName = metadata.getColumnName(i); - String columnType = metadata.getColumnTypeName(i); + String columnType = metadata.getColumnTypeName(i).toUpperCase(Locale.ROOT); if (columnName.equalsIgnoreCase(timestampColumnName)) { - assertEquals(db.flavor().columnTypeLocalDateTime(), columnType); + assertEquals("TIMESTAMP", columnType); } else if (columnName.equalsIgnoreCase(dateColumnName)) { - assertEquals("DATE", columnType.toUpperCase()); + assertEquals("DATE", columnType); } else { fail("Unexpected column " + columnName + " of type " + columnType); } @@ -616,10 +654,10 @@ public abstract class CommonTest { @Test public void intervals() { new Schema().addTable("dbtest").addColumn("d").asLocalDateTime().schema().execute(db); - db.toInsert("insert into dbtest (d) values (?)").argLocalDateTime(now).insert(1); + db.toInsert("insert into dbtest (d) values (?)").argLocalDateTime(localDateTimeNow).insert(1); assertEquals(1, db.toSelect("select count(1) from dbtest where d - interval '1' hour * ? < ?") .argInteger(2) - .argLocalDateTime(now) + .argLocalDateTime(localDateTimeNow) .queryIntegerOrZero()); } @@ -644,7 +682,7 @@ public abstract class CommonTest { .argDouble(Double.MAX_VALUE).argBigDecimal(new BigDecimal("123.456")) .argString("hello").argString("Z").argClobString("hello again") .argBlobBytes(new byte[]{'1', '2'}).argBoolean(true) - .argLocalDateTime(now) + .argLocalDateTime(localDateTimeNow) .argLocalDate(localDateNow).insert(1); db.toInsert("insert into dbtest (nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal, str_varchar," + " str_fixed, str_lob, bin_blob, boolean_flag, date_millis, local_date) values (?,?,?,?,?,?,?,?,?,?,?,?)") @@ -652,7 +690,7 @@ public abstract class CommonTest { .argDouble(Double.MIN_VALUE).argBigDecimal(new BigDecimal("-123.456")) .argString("goodbye").argString("A").argClobString("bye again") .argBlobBytes(new byte[]{'3', '4'}).argBoolean(false) - .argLocalDateTime(now) + .argLocalDateTime(localDateTimeNow) .argLocalDate(localDateNow).insert(1); String expectedSchema = new Schema().addTable("dbtest2") .addColumn("nbr_integer").asInteger().table() @@ -707,7 +745,7 @@ public abstract class CommonTest { .argClobString("str_lob", "bye again") .argBlobBytes("bin_blob", new byte[]{'3', '4'}) .argString("boolean_flag", "N")//.argBoolean("boolean_flag", false) - .argLocalDateTime("date_millis", now) + .argLocalDateTime("date_millis", localDateTimeNow) .argLocalDate("local_date", localDateNow), new SqlArgs().argInteger("nbr_integer", Integer.MAX_VALUE) .argLong("nbr_long", Long.MAX_VALUE) @@ -719,7 +757,7 @@ public abstract class CommonTest { .argClobString("str_lob", "hello again") .argBlobBytes("bin_blob", new byte[]{'1', '2'}) .argString("boolean_flag", "Y")//.argBoolean("boolean_flag", true) - .argLocalDateTime("date_millis", now) + .argLocalDateTime("date_millis", localDateTimeNow) .argLocalDate("local_date", localDateNow)), db.toSelect("select nbr_integer, nbr_long, nbr_float, nbr_double, nbr_big_decimal," + " str_varchar, str_fixed, str_lob, bin_blob, boolean_flag, date_millis, local_date from dbtest2 order by 1") @@ -1318,7 +1356,7 @@ public abstract class CommonTest { new Schema().addTable("dbtest").addColumn("i").asBigDecimal(38, 38).schema().execute(db); BigDecimal value = new BigDecimal("0.99999999999999999999999999999999999999"); // 38 digits db.toInsert("insert into dbtest (i) values (?)").argBigDecimal(value).insert(1); - logger.info(db.toSelect("select i from dbtest").queryBigDecimalOrNull().toString()); + String s = db.toSelect("select i from dbtest").queryBigDecimalOrNull().toString(); assertEquals(value, db.toSelect("select i from dbtest where i=?").argBigDecimal(value).queryBigDecimalOrNull()); } @@ -1367,15 +1405,15 @@ public abstract class CommonTest { .execute(db); db.toInsert("insert into dbtest (pk, d) values (:seq, :d)") .argPkSeq(":seq", "dbtest_seq") - .argLocalDateTime(":d", now) + .argLocalDateTime(":d", localDateTimeNow) .insertReturning("dbtest", "pk", rs -> { assertTrue(rs.next()); assertEquals(Long.valueOf(1L), rs.getLongOrNull(1)); - assertThat(rs.getLocalDateTimeOrNull(2, ZoneId.systemDefault()), equalTo(now)); + assertThat(rs.getLocalDateTimeOrNull(2), equalTo(localDateTimeNow)); assertFalse(rs.next()); return null; }, "d"); - assertEquals(Long.valueOf(1L), db.toSelect("select count(*) from dbtest where d=?").argLocalDateTime(now).queryLongOrNull()); + assertEquals(Long.valueOf(1L), db.toSelect("select count(*) from dbtest where d=?").argLocalDateTime(localDateTimeNow).queryLongOrNull()); } @Test @@ -1393,7 +1431,7 @@ public abstract class CommonTest { .execute(db); db.toInsert("insert into dbtest (pk, d, d3, s) values (?,?,?,?)") .argLong(1L) - .argLocalDateTime(now) + .argLocalDateTime(localDateTimeNow) .argLocalDate(localDateNow) .argString("foo") .insert(1); @@ -1424,10 +1462,10 @@ public abstract class CommonTest { assertEquals("foo", db.toSelect("select s from dbtest").queryStrings().get(0)); assertTrue(db.toSelect("select s from dbtest where 1=0").queryStrings().isEmpty()); assertTrue(db.toSelect("select s2 from dbtest").queryStrings().isEmpty()); - assertEquals(now, db.toSelect("select d from dbtest").queryLocalDateTimeOrNull()); + assertEquals(localDateTimeNow, db.toSelect("select d from dbtest").queryLocalDateTimeOrNull()); assertNull(db.toSelect("select d from dbtest where 1=0").queryLocalDateTimeOrNull()); assertNull(db.toSelect("select d2 from dbtest").queryLocalDateTimeOrNull()); - assertEquals(db.toSelect("select d from dbtest").queryLocalDateTimes().get(0), now); + assertEquals(db.toSelect("select d from dbtest").queryLocalDateTimes().get(0), localDateTimeNow); assertTrue(db.toSelect("select d from dbtest where 1=0").queryLocalDateTimes().isEmpty()); assertTrue(db.toSelect("select d2 from dbtest").queryLocalDateTimes().isEmpty()); @@ -1570,27 +1608,32 @@ public abstract class CommonTest { for (int attempts = 1; attempts <= 10; attempts++) { new Schema() .addTable("dbtest") - .addColumn("d").asLocalDateTime().table().schema() + .addColumn("d").asLocalDateTime() + .table() + .schema() .execute(db); db.toInsert("insert into dbtest (d) values (?)") .argLocalDateTimeNowPerDb() .insert(1); LocalDateTime dbNow = db.toSelect("select d from dbtest").queryLocalDateTimeOrNull(); if (dbNow != null && dbNow.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() % 10 != 0) { + // done return; } - logger.info("Zero in least significant digit (attempt " + attempts + ")"); - db.dropTableQuietly(TEST_TABLE_NAME); + logger.log(Level.INFO, "Zero in least significant digit (attempt " + attempts + ")"); + db.dropTableQuietly("dbtest"); } - fail("Timestamp had zero in the least significant digit"); + fail("unable to match dateMillis"); } @Test public void dateRoundTrip() { new Schema() .addTable("dbtest") - .addColumn("d1").asLocalDateTime().table() - .addColumn("d2").asLocalDateTime().table() + .addColumn("d1").asLocalDateTime() + .table() + .addColumn("d2").asLocalDateTime() + .table() .schema() .execute(db); db.toInsert("insert into dbtest (d1) values (?)") @@ -1600,15 +1643,14 @@ public abstract class CommonTest { db.toUpdate("update dbtest set d2 = ?") .argLocalDateTime(dbNow) .update(1); - assertEquals(Long.valueOf(1L), db.toSelect("select count(*) from dbtest where d1=d2").queryLongOrNull()); + assertEquals(Long.valueOf(1L), db.toSelect("select count(*) from dbtest where d1 = d2").queryLongOrNull()); } @Test public void dateRoundTripTimezones() { new Schema() .addTable("dbtest") - .addColumn("d") - .asLocalDateTime() + .addColumn("d").asLocalDateTime() .table() .schema() .execute(db); @@ -1617,7 +1659,6 @@ public abstract class CommonTest { LocalDateTime dateMinus = LocalDateTime.ofInstant(instant, dateMinusZone); ZoneId datePlusZone = ZoneId.ofOffset("GMT", ZoneOffset.ofHours(+4)); LocalDateTime datePlus = LocalDateTime.ofInstant(instant,datePlusZone); - logger.log(Level.INFO, "dateMinus = " + dateMinus); db.toInsert("insert into dbtest (d) values (?)") .argLocalDateTime(dateMinus) .insert(1); @@ -1631,7 +1672,7 @@ public abstract class CommonTest { .argLocalDateTime(datePlus) .insert(1); LocalDateTime localDateTimePlus = db.toSelect("select d from dbtest") - .queryLocalDateTimeOrNull(datePlusZone); + .queryLocalDateTimeOrNull(); assertEquals(datePlus, localDateTimePlus); assertEquals("1970-01-03 02:17:36.789", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS").format(localDateTimePlus)); @@ -1651,7 +1692,6 @@ public abstract class CommonTest { LocalDateTime dateMinus = LocalDateTime.ofInstant(instant, dateMinusZone); ZoneId datePlusZone = ZoneId.ofOffset("GMT", ZoneOffset.ofHours(+4)); LocalDateTime datePlus = LocalDateTime.ofInstant(instant, datePlusZone); - logger.info("LocalDateTime: dateMinus=" + dateMinus + " datePlus=" + datePlus); new Schema().addTable("dbtest").addColumn("d") .asLocalDateTime() .schema() @@ -1670,7 +1710,7 @@ public abstract class CommonTest { .argLocalDateTime(datePlus) .insert(1); localDateTime = db.toSelect("select d from dbtest") - .queryLocalDateTimeOrNull(datePlusZone); + .queryLocalDateTimeOrNull(); assertEquals("1970-01-03 02:17:36.789", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS").format(localDateTime.atZone(datePlusZone))); db.toDelete("delete from dbtest where d = ?") diff --git a/settings.gradle b/settings.gradle index 97b4ef6..4a79649 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,18 +2,18 @@ dependencyResolutionManagement { versionCatalogs { libs { version('gradle', '8.7') - library('mariadb', 'org.mariadb.jdbc', 'mariadb-java-client').version('3.4.1') - library('oracle', 'com.oracle.database.jdbc', 'ojdbc11').version('23.4.0.24.05') - library('postgresql', 'org.postgresql', 'postgresql').version('42.7.3') + library('mariadb', 'org.mariadb.jdbc', 'mariadb-java-client').version('3.5.2') + library('oracle', 'com.oracle.database.jdbc', 'ojdbc11').version('23.7.0.25.01') + library('postgresql', 'org.postgresql', 'postgresql').version('42.7.5') } testLibs { - version('junit', '5.10.2') + version('junit', '5.12.0') version('testcontainers', '1.20.0') library('junit-jupiter-api', 'org.junit.jupiter', 'junit-jupiter-api').versionRef('junit') library('junit-jupiter-params', 'org.junit.jupiter', 'junit-jupiter-params').versionRef('junit') library('junit-jupiter-engine', 'org.junit.jupiter', 'junit-jupiter-engine').versionRef('junit') - library('junit-jupiter-platform-launcher', 'org.junit.platform', 'junit-platform-launcher').version('1.10.1') - library('hamcrest', 'org.hamcrest', 'hamcrest-library').version('2.2') + library('junit-jupiter-platform-launcher', 'org.junit.platform', 'junit-platform-launcher').version('1.12.0') + library('hamcrest', 'org.hamcrest', 'hamcrest-library').version('3.0') library('junit4', 'junit', 'junit').version('4.13.2') library('derby', 'org.apache.derby', 'derby').version('10.17.1.0') library('hsqldb', 'org.hsqldb', 'hsqldb').version('2.7.3') @@ -35,4 +35,3 @@ include 'jdbc-test' include 'jdbc-mariadb' include 'jdbc-oracle' include 'jdbc-postgresql' -include 'jdbc-sqlserver'