From 678b0c1900266bec50ba4d9b3aaf193a1e18c0b8 Mon Sep 17 00:00:00 2001 From: graynk Date: Fri, 7 Dec 2018 12:42:13 +0500 Subject: [PATCH 1/8] changes to support java.time and and override to account for H2 not supporting time with timezone --- .../com/j256/ormlite/db/H2DatabaseType.java | 5 ++++ .../ormlite/jdbc/JdbcDatabaseConnection.java | 2 +- .../ormlite/jdbc/JdbcDatabaseResults.java | 26 +++++++++++++++++++ .../com/j256/ormlite/jdbc/TypeValMapper.java | 13 ++++++++++ 4 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/j256/ormlite/db/H2DatabaseType.java b/src/main/java/com/j256/ormlite/db/H2DatabaseType.java index 554c8e3c..06334ae1 100644 --- a/src/main/java/com/j256/ormlite/db/H2DatabaseType.java +++ b/src/main/java/com/j256/ormlite/db/H2DatabaseType.java @@ -52,6 +52,11 @@ public void appendLimitValue(StringBuilder sb, long limit, Long offset) { sb.append(limit).append(' '); } + @Override + public void appendOffsetTimeType(StringBuilder sb, FieldType fieldType, int fieldWidth) { + sb.append("TIMESTAMP WITH TIME ZONE"); + } + @Override public boolean isOffsetLimitArgument() { return true; diff --git a/src/main/java/com/j256/ormlite/jdbc/JdbcDatabaseConnection.java b/src/main/java/com/j256/ormlite/jdbc/JdbcDatabaseConnection.java index a6cedf47..eca6ffb9 100644 --- a/src/main/java/com/j256/ormlite/jdbc/JdbcDatabaseConnection.java +++ b/src/main/java/com/j256/ormlite/jdbc/JdbcDatabaseConnection.java @@ -31,7 +31,7 @@ */ public class JdbcDatabaseConnection implements DatabaseConnection { - private static final String JDBC_VERSION = "VERSION__5.1-SNAPSHOT__"; + private static final String JDBC_VERSION = "VERSION__5.2-SNAPSHOT__"; private static Logger logger = LoggerFactory.getLogger(JdbcDatabaseConnection.class); private static final String JDBC_META_TABLE_NAME_COLUMN = "TABLE_NAME"; diff --git a/src/main/java/com/j256/ormlite/jdbc/JdbcDatabaseResults.java b/src/main/java/com/j256/ormlite/jdbc/JdbcDatabaseResults.java index ce2ebef0..911fc56b 100644 --- a/src/main/java/com/j256/ormlite/jdbc/JdbcDatabaseResults.java +++ b/src/main/java/com/j256/ormlite/jdbc/JdbcDatabaseResults.java @@ -9,6 +9,7 @@ import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Timestamp; +import java.time.*; import com.j256.ormlite.dao.ObjectCache; import com.j256.ormlite.misc.IOUtils; @@ -175,6 +176,31 @@ public Timestamp getTimestamp(int columnIndex) throws SQLException { return resultSet.getTimestamp(columnIndex + 1); } + @Override + public LocalDate getLocalDate(int columnIndex) throws SQLException { + return resultSet.getObject(columnIndex + 1, LocalDate.class); + } + + @Override + public LocalTime getLocalTime(int columnIndex) throws SQLException { + return resultSet.getObject(columnIndex + 1, LocalTime.class); + } + + @Override + public LocalDateTime getLocalDateTime(int columnIndex) throws SQLException { + return resultSet.getObject(columnIndex + 1, LocalDateTime.class); + } + + @Override + public OffsetTime getOffsetTime(int columnIndex) throws SQLException { + return resultSet.getObject(columnIndex + 1, OffsetTime.class); + } + + @Override + public OffsetDateTime getOffsetDateTime(int columnIndex) throws SQLException { + return resultSet.getObject(columnIndex + 1, OffsetDateTime.class); + } + @Override public BigDecimal getBigDecimal(int columnIndex) throws SQLException { return resultSet.getBigDecimal(columnIndex + 1); diff --git a/src/main/java/com/j256/ormlite/jdbc/TypeValMapper.java b/src/main/java/com/j256/ormlite/jdbc/TypeValMapper.java index f1e525da..288726cf 100644 --- a/src/main/java/com/j256/ormlite/jdbc/TypeValMapper.java +++ b/src/main/java/com/j256/ormlite/jdbc/TypeValMapper.java @@ -27,8 +27,21 @@ public class TypeValMapper { values = new int[] { Types.LONGVARCHAR }; break; case DATE: + case LOCAL_DATE_TIME: values = new int[] { Types.TIMESTAMP }; break; + case LOCAL_DATE: + values = new int[] { Types.DATE }; + break; + case LOCAL_TIME: + values = new int[] { Types.TIME }; + break; + case OFFSET_TIME: + values = new int[] { Types.TIME_WITH_TIMEZONE }; + break; + case OFFSET_DATE_TIME: + values = new int[] { Types.TIMESTAMP_WITH_TIMEZONE }; + break; case BOOLEAN: values = new int[] { Types.BOOLEAN }; break; From 559a93e3776a38f92d7e389015b4fe9cd1633937 Mon Sep 17 00:00:00 2001 From: graynk Date: Tue, 11 Dec 2018 15:02:33 +0500 Subject: [PATCH 2/8] Added forced conversions to sql types for DBs that are non-compliant to JDBC 4.2 Not sure about Db2 and Netezza. --- .../com/j256/ormlite/db/Db2DatabaseType.java | 21 +++++++++++++++++ .../ormlite/db/DerbyEmbeddedDatabaseType.java | 15 ++++++++---- .../com/j256/ormlite/db/H2DatabaseType.java | 11 ++++++++- .../j256/ormlite/db/NetezzaDatabaseType.java | 21 +++++++++++++++++ .../j256/ormlite/db/PostgresDatabaseType.java | 16 ++++++++++++- .../j256/ormlite/db/SqliteDatabaseType.java | 23 +++++++++++++++++++ 6 files changed, 100 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/j256/ormlite/db/Db2DatabaseType.java b/src/main/java/com/j256/ormlite/db/Db2DatabaseType.java index 63d3c723..fdb56316 100644 --- a/src/main/java/com/j256/ormlite/db/Db2DatabaseType.java +++ b/src/main/java/com/j256/ormlite/db/Db2DatabaseType.java @@ -2,6 +2,9 @@ import java.util.List; +import com.j256.ormlite.field.DataPersister; +import com.j256.ormlite.field.DataType; +import com.j256.ormlite.field.FieldConverter; import com.j256.ormlite.field.FieldType; /** @@ -74,4 +77,22 @@ public boolean isOffsetSqlSupported() { // there is no easy way to do this in this database type return false; } + + @Override + public FieldConverter getFieldConverter(DataPersister dataType, FieldType fieldType) { + // we are only overriding certain types + switch (dataType.getSqlType()) { + case LOCAL_DATE: // db2 doesn't support JDBC 4.2 + return DataType.LOCAL_DATE_SQL.getDataPersister(); + case LOCAL_TIME: + return DataType.LOCAL_TIME_SQL.getDataPersister(); + case LOCAL_DATE_TIME: + return DataType.LOCAL_DATE_TIME_SQL.getDataPersister(); + case OFFSET_TIME: // db2 doesn't seem to support TIME/STAMP WITH TIME ZONE + case OFFSET_DATE_TIME: + return null; + default: + return super.getFieldConverter(dataType, fieldType); + } + } } diff --git a/src/main/java/com/j256/ormlite/db/DerbyEmbeddedDatabaseType.java b/src/main/java/com/j256/ormlite/db/DerbyEmbeddedDatabaseType.java index d990ed7b..57036cf4 100644 --- a/src/main/java/com/j256/ormlite/db/DerbyEmbeddedDatabaseType.java +++ b/src/main/java/com/j256/ormlite/db/DerbyEmbeddedDatabaseType.java @@ -9,11 +9,7 @@ import javax.sql.rowset.serial.SerialBlob; -import com.j256.ormlite.field.BaseFieldConverter; -import com.j256.ormlite.field.DataPersister; -import com.j256.ormlite.field.FieldConverter; -import com.j256.ormlite.field.FieldType; -import com.j256.ormlite.field.SqlType; +import com.j256.ormlite.field.*; import com.j256.ormlite.misc.IOUtils; import com.j256.ormlite.misc.SqlExceptionUtil; import com.j256.ormlite.support.DatabaseResults; @@ -73,6 +69,15 @@ public FieldConverter getFieldConverter(DataPersister dataType, FieldType fieldT serializableConverter = new SerializableFieldConverter(); } return serializableConverter; + case LOCAL_DATE: // derby doesn't support JDBC 4.2 + return DataType.LOCAL_DATE_SQL.getDataPersister(); + case LOCAL_TIME: + return DataType.LOCAL_TIME_SQL.getDataPersister(); + case LOCAL_DATE_TIME: + return DataType.LOCAL_DATE_TIME_SQL.getDataPersister(); + case OFFSET_TIME: // derby doesn't seem to support TIME/STAMP WITH TIME ZONE + case OFFSET_DATE_TIME: + return null; default: return super.getFieldConverter(dataType, fieldType); } diff --git a/src/main/java/com/j256/ormlite/db/H2DatabaseType.java b/src/main/java/com/j256/ormlite/db/H2DatabaseType.java index 06334ae1..b976fa96 100644 --- a/src/main/java/com/j256/ormlite/db/H2DatabaseType.java +++ b/src/main/java/com/j256/ormlite/db/H2DatabaseType.java @@ -2,7 +2,7 @@ import java.util.List; -import com.j256.ormlite.field.FieldType; +import com.j256.ormlite.field.*; /** * H2 database type information used to create the tables, etc.. @@ -57,6 +57,15 @@ public void appendOffsetTimeType(StringBuilder sb, FieldType fieldType, int fiel sb.append("TIMESTAMP WITH TIME ZONE"); } + @Override + public FieldConverter getFieldConverter(DataPersister dataPersister, FieldType fieldType) { + // H2 doesn't support TIME WITH TIME ZONE + if (dataPersister.getSqlType() == SqlType.OFFSET_TIME) + return DataType.OFFSET_TIME_SQL.getDataPersister(); + // default is to use the dataPersister itself + return dataPersister; + } + @Override public boolean isOffsetLimitArgument() { return true; diff --git a/src/main/java/com/j256/ormlite/db/NetezzaDatabaseType.java b/src/main/java/com/j256/ormlite/db/NetezzaDatabaseType.java index a15463df..89c1bf42 100644 --- a/src/main/java/com/j256/ormlite/db/NetezzaDatabaseType.java +++ b/src/main/java/com/j256/ormlite/db/NetezzaDatabaseType.java @@ -2,6 +2,9 @@ import java.util.List; +import com.j256.ormlite.field.DataPersister; +import com.j256.ormlite.field.DataType; +import com.j256.ormlite.field.FieldConverter; import com.j256.ormlite.field.FieldType; /** @@ -80,4 +83,22 @@ public void appendSelectNextValFromSequence(StringBuilder sb, String sequenceNam // this is word and not entity unfortunately appendEscapedWord(sb, sequenceName); } + + @Override + public FieldConverter getFieldConverter(DataPersister dataType, FieldType fieldType) { + // we are only overriding certain types + switch (dataType.getSqlType()) { + case LOCAL_DATE: // netezza doesn't seem to support JDBC 4.2 + return DataType.LOCAL_DATE_SQL.getDataPersister(); + case LOCAL_TIME: + return DataType.LOCAL_TIME_SQL.getDataPersister(); + case LOCAL_DATE_TIME: + return DataType.LOCAL_DATE_TIME_SQL.getDataPersister(); + case OFFSET_TIME: + case OFFSET_DATE_TIME: + return null; + default: + return super.getFieldConverter(dataType, fieldType); + } + } } diff --git a/src/main/java/com/j256/ormlite/db/PostgresDatabaseType.java b/src/main/java/com/j256/ormlite/db/PostgresDatabaseType.java index 8cdfcce4..c2e6e60d 100644 --- a/src/main/java/com/j256/ormlite/db/PostgresDatabaseType.java +++ b/src/main/java/com/j256/ormlite/db/PostgresDatabaseType.java @@ -2,7 +2,7 @@ import java.util.List; -import com.j256.ormlite.field.FieldType; +import com.j256.ormlite.field.*; /** * Postgres database type information used to create the tables, etc.. @@ -127,4 +127,18 @@ public boolean isCreateIfNotExistsSupported() { return super.isCreateIfNotExistsSupported(); } } + + @Override + public void appendOffsetTimeType(StringBuilder sb, FieldType fieldType, int fieldWidth) { + sb.append("TIMESTAMP WITH TIME ZONE"); + } + + @Override + public FieldConverter getFieldConverter(DataPersister dataPersister, FieldType fieldType) { + // H2 doesn't support TIME WITH TIME ZONE + if (dataPersister.getSqlType() == SqlType.OFFSET_TIME) + return DataType.OFFSET_TIME_SQL.getDataPersister(); + // default is to use the dataPersister itself + return dataPersister; + } } diff --git a/src/main/java/com/j256/ormlite/db/SqliteDatabaseType.java b/src/main/java/com/j256/ormlite/db/SqliteDatabaseType.java index 6bceb71b..f0be43ae 100644 --- a/src/main/java/com/j256/ormlite/db/SqliteDatabaseType.java +++ b/src/main/java/com/j256/ormlite/db/SqliteDatabaseType.java @@ -1,5 +1,10 @@ package com.j256.ormlite.db; +import com.j256.ormlite.field.DataPersister; +import com.j256.ormlite.field.DataType; +import com.j256.ormlite.field.FieldConverter; +import com.j256.ormlite.field.FieldType; + /** * Sqlite database type information used to create the tables, etc.. * @@ -52,4 +57,22 @@ public boolean isNestedSavePointsSupported() { public void appendOffsetValue(StringBuilder sb, long offset) { throw new IllegalStateException("Offset is part of the LIMIT in database type " + getClass()); } + + @Override + public FieldConverter getFieldConverter(DataPersister dataType, FieldType fieldType) { + // we are only overriding certain types + switch (dataType.getSqlType()) { + case LOCAL_DATE: // sqlite doesn't support JDBC 4.2 + return DataType.LOCAL_DATE_SQL.getDataPersister(); + case LOCAL_TIME: + return DataType.LOCAL_TIME_SQL.getDataPersister(); + case LOCAL_DATE_TIME: + return DataType.LOCAL_DATE_TIME_SQL.getDataPersister(); + case OFFSET_TIME: // sqlite doesn't seem to support TIME/STAMP WITH TIME ZONE + case OFFSET_DATE_TIME: + return null; + default: + return super.getFieldConverter(dataType, fieldType); + } + } } From e86d9c818848f9242baec44995d23f1a4ed3b532 Mon Sep 17 00:00:00 2001 From: graynk Date: Wed, 12 Dec 2018 14:11:03 +0500 Subject: [PATCH 3/8] Override of new missing methods Unfolded imports --- .../ormlite/db/DerbyEmbeddedDatabaseType.java | 7 ++++++- .../com/j256/ormlite/db/H2DatabaseType.java | 6 +++++- .../j256/ormlite/db/PostgresDatabaseType.java | 6 +++++- .../j256/ormlite/jdbc/JdbcDatabaseResults.java | 18 +++++++++++++++++- .../com/j256/ormlite/jdbc/TypeValMapper.java | 4 ++-- 5 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/j256/ormlite/db/DerbyEmbeddedDatabaseType.java b/src/main/java/com/j256/ormlite/db/DerbyEmbeddedDatabaseType.java index 57036cf4..8746e039 100644 --- a/src/main/java/com/j256/ormlite/db/DerbyEmbeddedDatabaseType.java +++ b/src/main/java/com/j256/ormlite/db/DerbyEmbeddedDatabaseType.java @@ -9,7 +9,12 @@ import javax.sql.rowset.serial.SerialBlob; -import com.j256.ormlite.field.*; +import com.j256.ormlite.field.BaseFieldConverter; +import com.j256.ormlite.field.DataPersister; +import com.j256.ormlite.field.FieldConverter; +import com.j256.ormlite.field.FieldType; +import com.j256.ormlite.field.SqlType; +import com.j256.ormlite.field.DataType; import com.j256.ormlite.misc.IOUtils; import com.j256.ormlite.misc.SqlExceptionUtil; import com.j256.ormlite.support.DatabaseResults; diff --git a/src/main/java/com/j256/ormlite/db/H2DatabaseType.java b/src/main/java/com/j256/ormlite/db/H2DatabaseType.java index b976fa96..e3166d8b 100644 --- a/src/main/java/com/j256/ormlite/db/H2DatabaseType.java +++ b/src/main/java/com/j256/ormlite/db/H2DatabaseType.java @@ -2,7 +2,11 @@ import java.util.List; -import com.j256.ormlite.field.*; +import com.j256.ormlite.field.FieldType; +import com.j256.ormlite.field.SqlType; +import com.j256.ormlite.field.DataType; +import com.j256.ormlite.field.DataPersister; +import com.j256.ormlite.field.FieldConverter; /** * H2 database type information used to create the tables, etc.. diff --git a/src/main/java/com/j256/ormlite/db/PostgresDatabaseType.java b/src/main/java/com/j256/ormlite/db/PostgresDatabaseType.java index c2e6e60d..0a8e3434 100644 --- a/src/main/java/com/j256/ormlite/db/PostgresDatabaseType.java +++ b/src/main/java/com/j256/ormlite/db/PostgresDatabaseType.java @@ -2,7 +2,11 @@ import java.util.List; -import com.j256.ormlite.field.*; +import com.j256.ormlite.field.FieldType; +import com.j256.ormlite.field.SqlType; +import com.j256.ormlite.field.DataType; +import com.j256.ormlite.field.DataPersister; +import com.j256.ormlite.field.FieldConverter; /** * Postgres database type information used to create the tables, etc.. diff --git a/src/main/java/com/j256/ormlite/jdbc/JdbcDatabaseResults.java b/src/main/java/com/j256/ormlite/jdbc/JdbcDatabaseResults.java index 911fc56b..5b2f7415 100644 --- a/src/main/java/com/j256/ormlite/jdbc/JdbcDatabaseResults.java +++ b/src/main/java/com/j256/ormlite/jdbc/JdbcDatabaseResults.java @@ -9,7 +9,13 @@ import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Timestamp; -import java.time.*; +import java.sql.Time; +import java.sql.Date; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.LocalDateTime; +import java.time.OffsetTime; +import java.time.OffsetDateTime; import com.j256.ormlite.dao.ObjectCache; import com.j256.ormlite.misc.IOUtils; @@ -176,6 +182,16 @@ public Timestamp getTimestamp(int columnIndex) throws SQLException { return resultSet.getTimestamp(columnIndex + 1); } + @Override + public Date getDate(int columnIndex) throws SQLException { + return resultSet.getDate(columnIndex + 1); + } + + @Override + public Time getTime(int columnIndex) throws SQLException { + return resultSet.getTime(columnIndex + 1); + } + @Override public LocalDate getLocalDate(int columnIndex) throws SQLException { return resultSet.getObject(columnIndex + 1, LocalDate.class); diff --git a/src/main/java/com/j256/ormlite/jdbc/TypeValMapper.java b/src/main/java/com/j256/ormlite/jdbc/TypeValMapper.java index 288726cf..bde00c00 100644 --- a/src/main/java/com/j256/ormlite/jdbc/TypeValMapper.java +++ b/src/main/java/com/j256/ormlite/jdbc/TypeValMapper.java @@ -37,8 +37,8 @@ public class TypeValMapper { values = new int[] { Types.TIME }; break; case OFFSET_TIME: - values = new int[] { Types.TIME_WITH_TIMEZONE }; - break; + values = new int[] { Types.TIME_WITH_TIMEZONE }; + break; case OFFSET_DATE_TIME: values = new int[] { Types.TIMESTAMP_WITH_TIMEZONE }; break; From ed1adcb39286935c3dea45b82e1ec58b22f0cb85 Mon Sep 17 00:00:00 2001 From: Nikitka Date: Wed, 12 Dec 2018 14:14:15 +0500 Subject: [PATCH 4/8] Delete JdbcDatabaseConnection.java --- .../ormlite/jdbc/JdbcDatabaseConnection.java | 374 ------------------ 1 file changed, 374 deletions(-) delete mode 100644 src/main/java/com/j256/ormlite/jdbc/JdbcDatabaseConnection.java diff --git a/src/main/java/com/j256/ormlite/jdbc/JdbcDatabaseConnection.java b/src/main/java/com/j256/ormlite/jdbc/JdbcDatabaseConnection.java deleted file mode 100644 index eca6ffb9..00000000 --- a/src/main/java/com/j256/ormlite/jdbc/JdbcDatabaseConnection.java +++ /dev/null @@ -1,374 +0,0 @@ -package com.j256.ormlite.jdbc; - -import java.io.IOException; -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.SQLException; -import java.sql.Savepoint; -import java.sql.Statement; -import java.sql.Types; - -import com.j256.ormlite.dao.ObjectCache; -import com.j256.ormlite.field.FieldType; -import com.j256.ormlite.logger.Logger; -import com.j256.ormlite.logger.LoggerFactory; -import com.j256.ormlite.misc.IOUtils; -import com.j256.ormlite.misc.VersionUtils; -import com.j256.ormlite.stmt.GenericRowMapper; -import com.j256.ormlite.stmt.StatementBuilder.StatementType; -import com.j256.ormlite.support.CompiledStatement; -import com.j256.ormlite.support.DatabaseConnection; -import com.j256.ormlite.support.DatabaseResults; -import com.j256.ormlite.support.GeneratedKeyHolder; - -/** - * Wrapper around a JDBC {@link Connection} object which we delegate to. - * - * @author graywatson - */ -public class JdbcDatabaseConnection implements DatabaseConnection { - - private static final String JDBC_VERSION = "VERSION__5.2-SNAPSHOT__"; - - private static Logger logger = LoggerFactory.getLogger(JdbcDatabaseConnection.class); - private static final String JDBC_META_TABLE_NAME_COLUMN = "TABLE_NAME"; - - private static Object[] noArgs = new Object[0]; - private static FieldType[] noArgTypes = new FieldType[0]; - private static GenericRowMapper longWrapper = new OneLongWrapper(); - - private Connection connection; - private Boolean supportsSavePoints = null; - - static { - VersionUtils.checkCoreVersusJdbcVersions(JDBC_VERSION); - } - - public JdbcDatabaseConnection(Connection connection) { - this.connection = connection; - logger.trace("connection opened: {}", connection); - } - - @Override - public boolean isAutoCommitSupported() { - return true; - } - - @Override - public boolean isAutoCommit() throws SQLException { - boolean autoCommit = connection.getAutoCommit(); - logger.trace("connection autoCommit is {}", autoCommit); - return autoCommit; - } - - @Override - public void setAutoCommit(boolean autoCommit) throws SQLException { - connection.setAutoCommit(autoCommit); - logger.trace("connection set autoCommit to {}", autoCommit); - } - - @Override - public Savepoint setSavePoint(String name) throws SQLException { - if (supportsSavePoints == null) { - DatabaseMetaData metaData = connection.getMetaData(); - supportsSavePoints = metaData.supportsSavepoints(); - logger.trace("connection supports save points is {}", supportsSavePoints); - } - if (supportsSavePoints) { - Savepoint savepoint = connection.setSavepoint(name); - logger.trace("save-point {} set with name {}", savepoint, name); - return savepoint; - } else { - return null; - } - } - - @Override - public void commit(Savepoint savepoint) throws SQLException { - if (savepoint == null) { - connection.commit(); - logger.trace("connection committed"); - } else { - // release might clear the name so we record it beforehand - Object obj = savepoint.getSavepointName(); - if (obj == null) { - obj = savepoint; - } - /* - * Initially I was doing a connection.releaseSavepoint(savepoint) which was only dropping the savepoint -- - * not committing it like I thought. I'm still surprised there is not a commit(savepoint). - */ - connection.commit(); - logger.trace("connection is committed for save-point {}", obj); - } - } - - @Override - public void rollback(Savepoint savepoint) throws SQLException { - if (savepoint == null) { - connection.rollback(); - logger.trace("connection is rolled back"); - } else { - // rollback might clear the name so we record it beforehand - Object obj = savepoint.getSavepointName(); - if (obj == null) { - obj = savepoint; - } - connection.rollback(savepoint); - logger.trace("save-point {} is rolled back", obj); - } - } - - @Override - public void releaseSavePoint(Savepoint savePoint) throws SQLException { - connection.releaseSavepoint(savePoint); - } - - @Override - public int executeStatement(String statementStr, int resultFlags) throws SQLException { - if (resultFlags == DatabaseConnection.DEFAULT_RESULT_FLAGS) { - resultFlags = ResultSet.TYPE_FORWARD_ONLY; - } - Statement statement = connection.createStatement(resultFlags, ResultSet.CONCUR_READ_ONLY); - statement.execute(statementStr); - return statement.getUpdateCount(); - } - - @Override - public CompiledStatement compileStatement(String statement, StatementType type, FieldType[] argFieldTypes, - int resultFlags, boolean cacheStore) throws SQLException { - if (resultFlags == DatabaseConnection.DEFAULT_RESULT_FLAGS) { - resultFlags = ResultSet.TYPE_FORWARD_ONLY; - } - JdbcCompiledStatement compiledStatement = new JdbcCompiledStatement( - connection.prepareStatement(statement, resultFlags, ResultSet.CONCUR_READ_ONLY), type, cacheStore); - logger.trace("compiled statement: {}", statement); - return compiledStatement; - } - - @Override - public void close() throws IOException { - try { - connection.close(); - } catch (SQLException e) { - throw new IOException("could not close SQL connection", e); - } - logger.trace("connection closed: {}", connection); - } - - @Override - public void closeQuietly() { - IOUtils.closeQuietly(this); - } - - /** - * Returns whether the connection has already been closed. Used by {@link JdbcConnectionSource}. - */ - @Override - public boolean isClosed() throws SQLException { - boolean isClosed = connection.isClosed(); - logger.trace("connection is closed returned {}", isClosed); - return isClosed; - } - - @Override - public int insert(String statement, Object[] args, FieldType[] argFieldTypes, GeneratedKeyHolder keyHolder) - throws SQLException { - PreparedStatement stmt; - if (keyHolder == null) { - stmt = connection.prepareStatement(statement); - } else { - stmt = connection.prepareStatement(statement, Statement.RETURN_GENERATED_KEYS); - } - try { - statementSetArgs(stmt, args, argFieldTypes); - int rowN = stmt.executeUpdate(); - logger.trace("insert statement is prepared and executed: {}", statement); - if (keyHolder != null) { - ResultSet resultSet = stmt.getGeneratedKeys(); - ResultSetMetaData metaData = resultSet.getMetaData(); - int colN = metaData.getColumnCount(); - boolean wasSet = false; - while (resultSet.next()) { - for (int colC = 1; colC <= colN; colC++) { - // get the id column data so we can pass it back to the caller thru the keyHolder - Number id = getIdColumnData(resultSet, metaData, colC); - keyHolder.addKey(id); - wasSet = true; - } - } - if (!wasSet) { - throw new SQLException( - "no generated-keys were returned from statement, maybe a schema mismatch between entity and database table?: " - + statement); - } - } - return rowN; - } finally { - stmt.close(); - } - } - - @Override - public int update(String statement, Object[] args, FieldType[] argFieldTypes) throws SQLException { - return update(statement, args, argFieldTypes, "update"); - } - - @Override - public int delete(String statement, Object[] args, FieldType[] argFieldTypes) throws SQLException { - // it's a call to executeUpdate - return update(statement, args, argFieldTypes, "delete"); - } - - @Override - public Object queryForOne(String statement, Object[] args, FieldType[] argFieldTypes, - GenericRowMapper rowMapper, ObjectCache objectCache) throws SQLException { - return queryForOne(statement, args, argFieldTypes, rowMapper, objectCache, "query for one"); - } - - @Override - public long queryForLong(String statement) throws SQLException { - return queryForLong(statement, noArgs, noArgTypes); - } - - @Override - public long queryForLong(String statement, Object[] args, FieldType[] argFieldTypes) throws SQLException { - // don't care about the object cache here - Object result = queryForOne(statement, args, argFieldTypes, longWrapper, null, "query for long"); - if (result == null) { - throw new SQLException("No results returned in query-for-long: " + statement); - } else if (result == MORE_THAN_ONE) { - throw new SQLException("More than 1 result returned in query-for-long: " + statement); - } else { - return (Long) result; - } - } - - @Override - public boolean isTableExists(String tableName) throws SQLException { - DatabaseMetaData metaData = connection.getMetaData(); - logger.trace("Got meta data from connection"); - ResultSet results = null; - try { - results = metaData.getTables(null, null, "%", new String[] { "TABLE" }); - // we do it this way because some result sets don't like us to findColumn if no results - if (!results.next()) { - return false; - } - int col = results.findColumn(JDBC_META_TABLE_NAME_COLUMN); - do { - String dbTableName = results.getString(col); - if (tableName.equalsIgnoreCase(dbTableName)) { - return true; - } - } while (results.next()); - return false; - } finally { - if (results != null) { - results.close(); - } - } - } - - /** - * Return the internal database connection. Most likely for testing purposes. - */ - public Connection getInternalConnection() { - return connection; - } - - /** - * Set the internal database connection. Most likely for testing purposes. - */ - public void setInternalConnection(Connection connection) { - this.connection = connection; - } - - private int update(String statement, Object[] args, FieldType[] argFieldTypes, String label) throws SQLException { - PreparedStatement stmt = connection.prepareStatement(statement); - try { - statementSetArgs(stmt, args, argFieldTypes); - int rowCount = stmt.executeUpdate(); - logger.trace("{} statement is prepared and executed returning {}: {}", label, rowCount, statement); - return rowCount; - } finally { - stmt.close(); - } - } - - private Object queryForOne(String statement, Object[] args, FieldType[] argFieldTypes, - GenericRowMapper rowMapper, ObjectCache objectCache, String label) throws SQLException { - PreparedStatement stmt = - connection.prepareStatement(statement, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); - DatabaseResults results = null; - try { - statementSetArgs(stmt, args, argFieldTypes); - results = new JdbcDatabaseResults(stmt, stmt.executeQuery(), objectCache, true); - logger.trace("{} statement is prepared and executed: {}", label, statement); - if (!results.first()) { - // no results at all - return null; - } - T first = rowMapper.mapRow(results); - if (results.next()) { - return MORE_THAN_ONE; - } else { - return first; - } - } finally { - IOUtils.closeQuietly(results); - stmt.close(); - } - } - - /** - * Return the id associated with the column. - */ - private Number getIdColumnData(ResultSet resultSet, ResultSetMetaData metaData, int columnIndex) - throws SQLException { - int typeVal = metaData.getColumnType(columnIndex); - switch (typeVal) { - case Types.BIGINT: - case Types.DECIMAL: - case Types.NUMERIC: - return (Number) resultSet.getLong(columnIndex); - case Types.INTEGER: - return (Number) resultSet.getInt(columnIndex); - default: - String columnName = metaData.getColumnName(columnIndex); - throw new SQLException( - "Unexpected ID column type " + TypeValMapper.getSqlTypeForTypeVal(typeVal) + " (typeVal " - + typeVal + ") in column " + columnName + "(#" + columnIndex + ") is not a number"); - } - } - - private void statementSetArgs(PreparedStatement stmt, Object[] args, FieldType[] argFieldTypes) - throws SQLException { - if (args == null) { - return; - } - for (int i = 0; i < args.length; i++) { - Object arg = args[i]; - int typeVal = TypeValMapper.getTypeValForSqlType(argFieldTypes[i].getSqlType()); - if (arg == null) { - stmt.setNull(i + 1, typeVal); - } else { - stmt.setObject(i + 1, arg, typeVal); - } - } - } - - /** - * Row mapper that handles a single long result. - */ - private static class OneLongWrapper implements GenericRowMapper { - @Override - public Long mapRow(DatabaseResults rs) throws SQLException { - // maps the first column (sql #1) - return rs.getLong(0); - } - } -} From 3eb089b13bad0a5f20cc13fe9250d3c8f1e39b82 Mon Sep 17 00:00:00 2001 From: graynk Date: Wed, 12 Dec 2018 14:16:37 +0500 Subject: [PATCH 5/8] Whoops. --- src/main/java/com/j256/ormlite/jdbc/JdbcDatabaseConnection.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/j256/ormlite/jdbc/JdbcDatabaseConnection.java b/src/main/java/com/j256/ormlite/jdbc/JdbcDatabaseConnection.java index eca6ffb9..a6cedf47 100644 --- a/src/main/java/com/j256/ormlite/jdbc/JdbcDatabaseConnection.java +++ b/src/main/java/com/j256/ormlite/jdbc/JdbcDatabaseConnection.java @@ -31,7 +31,7 @@ */ public class JdbcDatabaseConnection implements DatabaseConnection { - private static final String JDBC_VERSION = "VERSION__5.2-SNAPSHOT__"; + private static final String JDBC_VERSION = "VERSION__5.1-SNAPSHOT__"; private static Logger logger = LoggerFactory.getLogger(JdbcDatabaseConnection.class); private static final String JDBC_META_TABLE_NAME_COLUMN = "TABLE_NAME"; From 5569c600c38f66f6f1705de2d535cc91dcc112dc Mon Sep 17 00:00:00 2001 From: graynk Date: Thu, 13 Dec 2018 12:05:28 +0500 Subject: [PATCH 6/8] Typo --- src/main/java/com/j256/ormlite/db/PostgresDatabaseType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/j256/ormlite/db/PostgresDatabaseType.java b/src/main/java/com/j256/ormlite/db/PostgresDatabaseType.java index 0a8e3434..bf752064 100644 --- a/src/main/java/com/j256/ormlite/db/PostgresDatabaseType.java +++ b/src/main/java/com/j256/ormlite/db/PostgresDatabaseType.java @@ -139,7 +139,7 @@ public void appendOffsetTimeType(StringBuilder sb, FieldType fieldType, int fiel @Override public FieldConverter getFieldConverter(DataPersister dataPersister, FieldType fieldType) { - // H2 doesn't support TIME WITH TIME ZONE + // Postgres doesn't support TIME WITH TIME ZONE if (dataPersister.getSqlType() == SqlType.OFFSET_TIME) return DataType.OFFSET_TIME_SQL.getDataPersister(); // default is to use the dataPersister itself From 2f47ff5940a06e04616b7b65febe8cf91ed3fb73 Mon Sep 17 00:00:00 2001 From: graynk Date: Tue, 18 Dec 2018 10:34:47 +0500 Subject: [PATCH 7/8] Enum change --- src/main/java/com/j256/ormlite/db/H2DatabaseType.java | 2 +- src/main/java/com/j256/ormlite/db/PostgresDatabaseType.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/j256/ormlite/db/H2DatabaseType.java b/src/main/java/com/j256/ormlite/db/H2DatabaseType.java index e3166d8b..98755a71 100644 --- a/src/main/java/com/j256/ormlite/db/H2DatabaseType.java +++ b/src/main/java/com/j256/ormlite/db/H2DatabaseType.java @@ -65,7 +65,7 @@ public void appendOffsetTimeType(StringBuilder sb, FieldType fieldType, int fiel public FieldConverter getFieldConverter(DataPersister dataPersister, FieldType fieldType) { // H2 doesn't support TIME WITH TIME ZONE if (dataPersister.getSqlType() == SqlType.OFFSET_TIME) - return DataType.OFFSET_TIME_SQL.getDataPersister(); + return DataType.OFFSET_TIME_COMPAT.getDataPersister(); // default is to use the dataPersister itself return dataPersister; } diff --git a/src/main/java/com/j256/ormlite/db/PostgresDatabaseType.java b/src/main/java/com/j256/ormlite/db/PostgresDatabaseType.java index bf752064..4ac932e8 100644 --- a/src/main/java/com/j256/ormlite/db/PostgresDatabaseType.java +++ b/src/main/java/com/j256/ormlite/db/PostgresDatabaseType.java @@ -141,7 +141,7 @@ public void appendOffsetTimeType(StringBuilder sb, FieldType fieldType, int fiel public FieldConverter getFieldConverter(DataPersister dataPersister, FieldType fieldType) { // Postgres doesn't support TIME WITH TIME ZONE if (dataPersister.getSqlType() == SqlType.OFFSET_TIME) - return DataType.OFFSET_TIME_SQL.getDataPersister(); + return DataType.OFFSET_TIME_COMPAT.getDataPersister(); // default is to use the dataPersister itself return dataPersister; } From ab77ff7780690b82723c44960ecd944b0e2a43e6 Mon Sep 17 00:00:00 2001 From: graynk Date: Tue, 19 Mar 2019 14:17:29 +0500 Subject: [PATCH 8/8] Draft for FieldConverter wrapper for Offset types --- .../com/j256/ormlite/db/Db2DatabaseType.java | 52 ++++++++++++++++--- 1 file changed, 46 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/j256/ormlite/db/Db2DatabaseType.java b/src/main/java/com/j256/ormlite/db/Db2DatabaseType.java index 95a16793..f4533850 100644 --- a/src/main/java/com/j256/ormlite/db/Db2DatabaseType.java +++ b/src/main/java/com/j256/ormlite/db/Db2DatabaseType.java @@ -1,11 +1,16 @@ package com.j256.ormlite.db; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.time.LocalDateTime; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; import java.util.List; -import com.j256.ormlite.field.DataPersister; -import com.j256.ormlite.field.DataType; -import com.j256.ormlite.field.FieldConverter; -import com.j256.ormlite.field.FieldType; +import com.j256.ormlite.field.*; +import com.j256.ormlite.field.types.OffsetDateTimeType; +import com.j256.ormlite.support.DatabaseResults; /** * IBM DB2 database type information used to create the tables, etc.. @@ -88,11 +93,46 @@ public FieldConverter getFieldConverter(DataPersister dataType, FieldType fieldT return DataType.LOCAL_TIME_SQL.getDataPersister(); case LOCAL_DATE_TIME: return DataType.LOCAL_DATE_TIME_SQL.getDataPersister(); - case OFFSET_TIME: // db2 doesn't seem to support TIME/STAMP WITH TIME ZONE - case OFFSET_DATE_TIME: + // db2 doesn't seem to support TIME/STAMP WITH TIME ZONE + case OFFSET_TIME: return null; + case OFFSET_DATE_TIME: + return OffsetToLocalDateTimeSqlType.getSingleton(); default: return super.getFieldConverter(dataType, fieldType); } } + + private static class OffsetToLocalDateTimeSqlType extends OffsetDateTimeType { + private static final OffsetToLocalDateTimeSqlType singleton = isJavaTimeSupported() ? + new OffsetToLocalDateTimeSqlType() : null; + public static OffsetToLocalDateTimeSqlType getSingleton() { return singleton; } + private OffsetToLocalDateTimeSqlType() { super(SqlType.OFFSET_DATE_TIME, new Class[] { OffsetDateTime.class }); } + protected OffsetToLocalDateTimeSqlType(SqlType sqlType, Class[] classes) { super(sqlType, classes); } + + @Override + public Object parseDefaultString(FieldType fieldType, String defaultStr) throws SQLException { + OffsetDateTime offsetDateTime = (OffsetDateTime) super.parseDefaultString(fieldType, defaultStr); + // convert to local timezone + LocalDateTime localDateTime = offsetDateTime.atZoneSameInstant(ZoneId.of("UTC")).toLocalDateTime(); + return Timestamp.valueOf(localDateTime); + } + + @Override + public Object resultToSqlArg(FieldType fieldType, DatabaseResults results, int columnPos) throws SQLException { + return results.getTimestamp(columnPos); + } + + @Override + public Object sqlArgToJava(FieldType fieldType, Object sqlArg, int columnPos) { + Timestamp value = (Timestamp) sqlArg; + return OffsetDateTime.of(value.toLocalDateTime(), ZoneOffset.of("Z")); + } + + @Override + public Object javaToSqlArg(FieldType fieldType, Object javaObject) { + OffsetDateTime offsetDateTime = (OffsetDateTime) javaObject; + return Timestamp.valueOf(offsetDateTime.atZoneSameInstant(ZoneId.of("UTC")).toLocalDateTime()); + } + } }