diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java b/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java index b70d66bfb..e5e175b9e 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java @@ -1056,7 +1056,7 @@ private void writeInternal(byte[] b, int off, int len) throws IOException { private final class ProxyInputStream extends InputStream { private InputStream filteredStream; - private final transient Lock proxyInputStreamLock = new ReentrantLock(); + private final Lock proxyInputStreamLock = new ReentrantLock(); /** * Bytes that have been read by a poll(s). @@ -3825,6 +3825,20 @@ void writeDate(String value) throws SQLServerException { SSType.DATE); } + void writeDate(long utcMillis, Calendar cal) throws SQLServerException { + GregorianCalendar calendar = initializeCalender(TimeZone.getDefault()); + + // Load the calendar with the desired value + calendar.setTimeInMillis(utcMillis); + if (cal != null) { + calendar.setTimeZone(cal.getTimeZone()); + } + + writeScaledTemporal(calendar, 0, // subsecond nanos (none for a date value) + 0, // scale (dates are not scaled) + SSType.DATE); + } + void writeTime(java.sql.Timestamp value, int scale) throws SQLServerException { GregorianCalendar calendar = initializeCalender(TimeZone.getDefault()); long utcMillis; // Value to which the calendar is to be set (in milliseconds 1/1/1970 00:00:00 GMT) @@ -3838,6 +3852,20 @@ void writeTime(java.sql.Timestamp value, int scale) throws SQLServerException { writeScaledTemporal(calendar, subSecondNanos, scale, SSType.TIME); } + void writeTime(java.sql.Timestamp value, int scale, Calendar cal) throws SQLServerException { + GregorianCalendar calendar = initializeCalender(TimeZone.getDefault()); + long utcMillis = value.getTime(); // Value to which the calendar is to be set (in milliseconds 1/1/1970 00:00:00 GMT) + int subSecondNanos = value.getNanos(); + + // Load the calendar with the desired value + calendar.setTimeInMillis(utcMillis); + if (cal != null) { + calendar.setTimeZone(cal.getTimeZone()); + } + + writeScaledTemporal(calendar, subSecondNanos, scale, SSType.TIME); + } + void writeDateTimeOffset(Object value, int scale, SSType destSSType) throws SQLServerException { GregorianCalendar calendar; TimeZone timeZone; // Time zone to associate with the value in the Gregorian calendar diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerConnection.java b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerConnection.java index 7ab7772d7..c49b553ae 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerConnection.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerConnection.java @@ -498,14 +498,14 @@ CallableStatement prepareCall(String sql, int nType, int nConcur, int nHold, */ void setCalcBigDecimalPrecision(boolean calcBigDecimalPrecision); - /** + /** * Specifies the flag for using Bulk Copy API for batch insert operations. * * @param useBulkCopyForBatchInsert * boolean value for useBulkCopyForBatchInsert. */ - void setUseBulkCopyForBatchInsert(boolean useBulkCopyForBatchInsert) ; - + void setUseBulkCopyForBatchInsert(boolean useBulkCopyForBatchInsert); + /** * Returns the useBulkCopyForBatchInsert value. * diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkBatchInsertRecord.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkBatchInsertRecord.java index 8b4057b3e..a696e3490 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkBatchInsertRecord.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkBatchInsertRecord.java @@ -30,7 +30,7 @@ class SQLServerBulkBatchInsertRecord extends SQLServerBulkRecord { */ private static final long serialVersionUID = -955998113956445541L; - private transient List batchParam; + transient List batchParam; private int batchParamIndex = -1; private List columnList; private List valueList; diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java index 8b20c4f8f..c2f51aef5 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java @@ -2064,7 +2064,7 @@ private void writeNullToTdsWriter(TDSWriter tdsWriter, int srcJdbcType, private void writeColumnToTdsWriter(TDSWriter tdsWriter, int bulkPrecision, int bulkScale, int bulkJdbcType, boolean bulkNullable, // should it be destNullable instead? - int srcColOrdinal, int destColOrdinal, boolean isStreaming, Object colValue) throws SQLServerException { + int srcColOrdinal, int destColOrdinal, boolean isStreaming, Object colValue, Calendar cal) throws SQLServerException { SSType destSSType = destColumnMetadata.get(destColOrdinal).ssType; bulkPrecision = validateSourcePrecision(bulkPrecision, bulkJdbcType, @@ -2480,10 +2480,17 @@ else if (4 >= bulkScale) tdsWriter.writeByte((byte) 0x07); else tdsWriter.writeByte((byte) 0x08); - String timeStampValue = colValue.toString(); - tdsWriter.writeTime(java.sql.Timestamp.valueOf(timeStampValue), bulkScale); + + Timestamp ts; + if (colValue instanceof java.sql.Timestamp) { + ts = (Timestamp) colValue; + } else { + ts = Timestamp.valueOf(colValue.toString()); + } + + tdsWriter.writeTime(ts, bulkScale, cal); // Send only the date part - tdsWriter.writeDate(timeStampValue.substring(0, timeStampValue.lastIndexOf(' '))); + tdsWriter.writeDate(ts.getTime(), cal); } } break; @@ -2981,7 +2988,7 @@ private Object readColumnFromResultSet(int srcColOrdinal, int srcJdbcType, boole * Reads the given column from the result set current row and writes the data to tdsWriter. */ private void writeColumn(TDSWriter tdsWriter, int srcColOrdinal, int destColOrdinal, - Object colValue) throws SQLServerException { + Object colValue, Calendar cal) throws SQLServerException { String destName = destColumnMetadata.get(destColOrdinal).columnName; int srcPrecision, srcScale, destPrecision, srcJdbcType; SSType destSSType = null; @@ -3102,7 +3109,7 @@ else if (null != serverBulkData && (null == destCryptoMeta)) { } } writeColumnToTdsWriter(tdsWriter, srcPrecision, srcScale, srcJdbcType, srcNullable, srcColOrdinal, - destColOrdinal, isStreaming, colValue); + destColOrdinal, isStreaming, colValue, cal); } /** @@ -3633,7 +3640,7 @@ private boolean writeBatchData(TDSWriter tdsWriter, TDSCommand command, // Loop for each destination column. The mappings is a many to one mapping // where multiple source columns can be mapped to one destination column. for (ColumnMapping columnMapping : columnMappings) { - writeColumn(tdsWriter, columnMapping.sourceColumnOrdinal, columnMapping.destinationColumnOrdinal, + writeColumn(tdsWriter, columnMapping.sourceColumnOrdinal, columnMapping.destinationColumnOrdinal, null, null // cell // value is // retrieved @@ -3647,20 +3654,32 @@ private boolean writeBatchData(TDSWriter tdsWriter, TDSCommand command, else { // Get all the column values of the current row. Object[] rowObjects; + Parameter[] params = null; try { rowObjects = serverBulkData.getRowData(); + if (serverBulkData instanceof SQLServerBulkBatchInsertRecord) { + params = ((SQLServerBulkBatchInsertRecord) serverBulkData).batchParam.get(row); + } } catch (Exception ex) { // if no more data available to retrive throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveSourceData"), ex); } for (ColumnMapping columnMapping : columnMappings) { + + Object rowObject = rowObjects[columnMapping.sourceColumnOrdinal - 1]; + Calendar cal = null; + + if (rowObject instanceof Timestamp && params != null) { + cal = params[columnMapping.sourceColumnOrdinal - 1].getInputDTV().getCalendar(); + } + // If the SQLServerBulkCSVRecord does not have metadata for columns, it returns strings in the // object array. // COnvert the strings using destination table types. writeColumn(tdsWriter, columnMapping.sourceColumnOrdinal, columnMapping.destinationColumnOrdinal, - rowObjects[columnMapping.sourceColumnOrdinal - 1]); + rowObject, cal); } } row++; diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerCallableStatement.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerCallableStatement.java index 1bcb04529..f98585fe4 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerCallableStatement.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerCallableStatement.java @@ -2589,7 +2589,8 @@ public void registerOutParameter(String parameterName, int sqlType) throws SQLSe loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {parameterName, sqlType}); checkClosed(); - registerOutParameterByName(findColumn(parameterName, CallableStatementGetterSetterMethod.IS_SETTER_METHOD), sqlType); + registerOutParameterByName(findColumn(parameterName, CallableStatementGetterSetterMethod.IS_SETTER_METHOD), + sqlType); loggerExternal.exiting(getClassNameLogging(), "registerOutParameter"); } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionPoolProxy.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionPoolProxy.java index 4c40b01c6..ffda2dd6b 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionPoolProxy.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionPoolProxy.java @@ -712,6 +712,7 @@ public boolean getCalcBigDecimalPrecision() { public void setCalcBigDecimalPrecision(boolean calcBigDecimalPrecision) { wrappedConnection.setCalcBigDecimalPrecision(calcBigDecimalPrecision); } + /** * Returns the useBulkCopyForBatchInsert value. * @@ -719,7 +720,7 @@ public void setCalcBigDecimalPrecision(boolean calcBigDecimalPrecision) { */ @Override public boolean getUseBulkCopyForBatchInsert() { - return wrappedConnection.getUseBulkCopyForBatchInsert(); + return wrappedConnection.getUseBulkCopyForBatchInsert(); } /** @@ -730,6 +731,6 @@ public boolean getUseBulkCopyForBatchInsert() { */ @Override public void setUseBulkCopyForBatchInsert(boolean useBulkCopyForBatchInsert) { - wrappedConnection.setUseBulkCopyForBatchInsert(useBulkCopyForBatchInsert); + wrappedConnection.setUseBulkCopyForBatchInsert(useBulkCopyForBatchInsert); } } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java index 35b27b310..2c45d1090 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java @@ -907,8 +907,8 @@ public final class SQLServerDriver implements java.sql.Driver { Boolean.toString(SQLServerDriverBooleanProperty.USE_DEFAULT_JAAS_CONFIG.getDefaultValue()), false, TRUE_FALSE), new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.CALC_BIG_DECIMAL_PRECISION.toString(), - Boolean.toString(SQLServerDriverBooleanProperty.CALC_BIG_DECIMAL_PRECISION.getDefaultValue()), false, - TRUE_FALSE), + Boolean.toString(SQLServerDriverBooleanProperty.CALC_BIG_DECIMAL_PRECISION.getDefaultValue()), + false, TRUE_FALSE), new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.SSL_PROTOCOL.toString(), SQLServerDriverStringProperty.SSL_PROTOCOL.getDefaultValue(), false, new String[] {SSLProtocol.TLS.toString(), SSLProtocol.TLS_V10.toString(), diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement.java index bb8e49b9c..d5b9b5499 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement.java @@ -3422,6 +3422,7 @@ public final void setTimestamp(int n, java.sql.Timestamp x, java.util.Calendar c if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setTimestamp", new Object[] {n, x, cal}); checkClosed(); + setValue(n, JDBCType.TIMESTAMP, x, JavaType.TIMESTAMP, cal, false); loggerExternal.exiting(getClassNameLogging(), "setTimestamp"); } @@ -3433,6 +3434,7 @@ public final void setTimestamp(int n, java.sql.Timestamp x, java.util.Calendar c if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setTimestamp", new Object[] {n, x, cal, forceEncrypt}); checkClosed(); + setValue(n, JDBCType.TIMESTAMP, x, JavaType.TIMESTAMP, cal, forceEncrypt); loggerExternal.exiting(getClassNameLogging(), "setTimestamp"); } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionTest.java index 04fedc1ff..eabbbb574 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionTest.java @@ -209,7 +209,8 @@ public void testDataSource() throws SQLServerException { assertEquals(booleanPropValue, ds.getUseFlexibleCallableStatements(), TestResource.getResource("R_valuesAreDifferent")); ds.setCalcBigDecimalPrecision(booleanPropValue); - assertEquals(booleanPropValue, ds.getCalcBigDecimalPrecision(), TestResource.getResource("R_valuesAreDifferent")); + assertEquals(booleanPropValue, ds.getCalcBigDecimalPrecision(), + TestResource.getResource("R_valuesAreDifferent")); ds.setServerCertificate(stringPropValue); assertEquals(stringPropValue, ds.getServerCertificate(), TestResource.getResource("R_valuesAreDifferent")); diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/resiliency/BasicConnectionTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/resiliency/BasicConnectionTest.java index b19d25248..3712e9d1d 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/resiliency/BasicConnectionTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/resiliency/BasicConnectionTest.java @@ -64,7 +64,7 @@ public void testBasicConnectionAAD() throws Exception { basicReconnect("jdbc:sqlserver://" + azureServer + ";database=" + azureDatabase + ";user=" + azureUserName + ";password=" + azurePassword + ";loginTimeout=90;Authentication=ActiveDirectoryPassword"); - retry = THROTTLE_RETRY_COUNT + 1; + retry = THROTTLE_RETRY_COUNT + 1; } catch (Exception e) { if (e.getMessage().matches(TestUtils.formatErrorMsg("R_crClientAllRecoveryAttemptsFailed"))) { System.out.println(e.getMessage() + ". Recovery failed, retry #" + retry + " in " diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/BatchExecutionTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/BatchExecutionTest.java index 3482eff6b..3384f278c 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/BatchExecutionTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/BatchExecutionTest.java @@ -13,11 +13,17 @@ import java.sql.BatchUpdateException; import java.sql.CallableStatement; import java.sql.Connection; +import java.sql.Date; +import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import java.sql.Time; +import java.sql.Timestamp; import java.util.Arrays; +import java.util.Calendar; +import java.util.TimeZone; import com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement; import org.junit.jupiter.api.AfterAll; @@ -54,6 +60,10 @@ public class BatchExecutionTest extends AbstractTest { private static String ctstable3; private static String ctstable4; private static String ctstable3Procedure1; + private static String timestampTable1 = AbstractSQLGenerator + .escapeIdentifier(RandomUtil.getIdentifier("timestamptable1")); + private static String timestampTable2 = AbstractSQLGenerator + .escapeIdentifier(RandomUtil.getIdentifier("timestamptable2")); /** * This tests the updateCount when the error query does cause a SQL state HY008. @@ -99,6 +109,183 @@ public void testBatchUpdateCountTrueOnFirstPstmtSpPrepare() throws Exception { testBatchUpdateCountWith(5, 4, true, "prepare", expectedUpdateCount); } + @Test + public void testValidTimezoneForTimestampBatchInsertWithBulkCopy() throws Exception { + Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); + long ms = 1578743412000L; + + // Insert Timestamp using batch insert + try (Connection con = DriverManager.getConnection(connectionString); Statement stmt = con.createStatement(); + PreparedStatement pstmt = con.prepareStatement("INSERT INTO " + timestampTable1 + " VALUES(?)")) { + + TestUtils.dropTableIfExists(timestampTable1, stmt); + String createSql = "CREATE TABLE " + timestampTable1 + " (c1 DATETIME2(3))"; + stmt.execute(createSql); + + Timestamp timestamp = new Timestamp(ms); + + pstmt.setTimestamp(1, timestamp, gmtCal); + pstmt.addBatch(); + pstmt.executeBatch(); + } + + // Insert Timestamp using bulkcopy for batch insert + try (Connection con = DriverManager.getConnection( + connectionString + ";useBulkCopyForBatchInsert=true;sendTemporalDataTypesAsStringForBulkCopy=false;"); + PreparedStatement pstmt = con.prepareStatement("INSERT INTO " + timestampTable1 + " VALUES(?)")) { + + Timestamp timestamp = new Timestamp(ms); + + pstmt.setTimestamp(1, timestamp, gmtCal); + pstmt.addBatch(); + pstmt.executeBatch(); + } + + // Compare Timestamp values inserted, should be the same + try (Connection con = DriverManager.getConnection(connectionString); Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM " + timestampTable1)) { + Timestamp ts0; + Timestamp ts1; + Time t0; + Time t1; + Date d0; + Date d1; + + rs.next(); + ts0 = rs.getTimestamp(1); + t0 = rs.getTime(1); + d0 = rs.getDate(1); + rs.next(); + ts1 = rs.getTimestamp(1); + t1 = rs.getTime(1); + d1 = rs.getDate(1); + + assertEquals(ts0, ts1); + assertEquals(t0, t1); + assertEquals(d0, d1); + } + } + + @Test + public void testValidTimezonesDstTimestampBatchInsertWithBulkCopy() throws Exception { + Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); + + for (String tzId: TimeZone.getAvailableIDs()) { + TimeZone.setDefault(TimeZone.getTimeZone(tzId)); + + long ms = 1696127400000L; // DST + + // Insert Timestamp using batch insert + try (Connection con = DriverManager.getConnection(connectionString); Statement stmt = con.createStatement(); + PreparedStatement pstmt = con.prepareStatement("INSERT INTO " + timestampTable1 + " VALUES(?)")) { + + TestUtils.dropTableIfExists(timestampTable1, stmt); + String createSql = "CREATE TABLE " + timestampTable1 + " (c1 DATETIME2(3))"; + stmt.execute(createSql); + + Timestamp timestamp = new Timestamp(ms); + + pstmt.setTimestamp(1, timestamp, gmtCal); + pstmt.addBatch(); + pstmt.executeBatch(); + } + + // Insert Timestamp using bulkcopy for batch insert + try (Connection con = DriverManager.getConnection( + connectionString + ";useBulkCopyForBatchInsert=true;sendTemporalDataTypesAsStringForBulkCopy=false;"); + PreparedStatement pstmt = con.prepareStatement("INSERT INTO " + timestampTable1 + " VALUES(?)")) { + + Timestamp timestamp = new Timestamp(ms); + + pstmt.setTimestamp(1, timestamp, gmtCal); + pstmt.addBatch(); + pstmt.executeBatch(); + } + + // Compare Timestamp values inserted, should be the same + try (Connection con = DriverManager.getConnection(connectionString); Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM " + timestampTable1)) { + Timestamp ts0; + Timestamp ts1; + Time t0; + Time t1; + Date d0; + Date d1; + + rs.next(); + ts0 = rs.getTimestamp(1); + t0 = rs.getTime(1); + d0 = rs.getDate(1); + rs.next(); + ts1 = rs.getTimestamp(1); + t1 = rs.getTime(1); + d1 = rs.getDate(1); + + String failureMsg = "Failed for time zone: " + tzId; + assertEquals(ts0, ts1, failureMsg); + assertEquals(t0, t1, failureMsg); + assertEquals(d0, d1, failureMsg); + } + } + } + + @Test + public void testBatchInsertTimestampNoTimezoneDoubleConversion() throws Exception { + Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT")); + long ms = 1578743412000L; + + // Insert Timestamp using prepared statement when useBulkCopyForBatchInsert=true + try (Connection con = DriverManager.getConnection(connectionString + + ";useBulkCopyForBatchInsert=true;sendTemporalDataTypesAsStringForBulkCopy=false;"); Statement stmt = con.createStatement(); + PreparedStatement pstmt = con.prepareStatement("INSERT INTO " + timestampTable2 + " VALUES(?)")) { + + TestUtils.dropTableIfExists(timestampTable2, stmt); + String createSql = "CREATE TABLE" + timestampTable2 + " (c1 DATETIME2(3))"; + stmt.execute(createSql); + + Timestamp timestamp = new Timestamp(ms); + + pstmt.setTimestamp(1, timestamp, gmtCal); + pstmt.execute(); + } + + // Insert Timestamp using bulkcopy for batch insert + try (Connection con = DriverManager.getConnection( + connectionString + ";useBulkCopyForBatchInsert=true;sendTemporalDataTypesAsStringForBulkCopy=false;"); + PreparedStatement pstmt = con.prepareStatement("INSERT INTO " + timestampTable2 + " VALUES(?)")) { + + Timestamp timestamp = new Timestamp(ms); + + pstmt.setTimestamp(1, timestamp, gmtCal); + pstmt.addBatch(); + pstmt.executeBatch(); + } + + // Compare Timestamp values inserted, should be the same + try (Connection con = DriverManager.getConnection(connectionString); Statement stmt = con.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM " + timestampTable2)) { + Timestamp ts0; + Timestamp ts1; + Time t0; + Time t1; + Date d0; + Date d1; + + rs.next(); + ts0 = rs.getTimestamp(1); + t0 = rs.getTime(1); + d0 = rs.getDate(1); + rs.next(); + ts1 = rs.getTimestamp(1); + t1 = rs.getTime(1); + d1 = rs.getDate(1); + + assertEquals(ts0, ts1); + assertEquals(t0, t1); + assertEquals(d0, d1); + } + } + /** * This tests the updateCount when the error query does not cause a SQL state HY008. * @@ -466,6 +653,9 @@ private static void dropTable() throws SQLException { TestUtils.dropTableIfExists(AbstractSQLGenerator.escapeIdentifier(ctstable1), stmt); TestUtils.dropTableIfExists(AbstractSQLGenerator.escapeIdentifier(ctstable3), stmt); TestUtils.dropTableIfExists(AbstractSQLGenerator.escapeIdentifier(ctstable4), stmt); + TestUtils.dropTableIfExists(AbstractSQLGenerator.escapeIdentifier(ctstable4), stmt); + TestUtils.dropTableIfExists(timestampTable1, stmt); + TestUtils.dropTableIfExists(timestampTable2, stmt); } }