From 5fef638997d18ea91e4590a6987af6c550b23768 Mon Sep 17 00:00:00 2001 From: v-xiangs Date: Fri, 26 May 2017 11:26:06 -0700 Subject: [PATCH 1/3] fix the issue. precision was ignored because getObject returns Time object, which is converted to String later on and precision is removed. --- src/main/java/com/microsoft/sqlserver/jdbc/TVP.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/TVP.java b/src/main/java/com/microsoft/sqlserver/jdbc/TVP.java index dfd312926..4332a4e55 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/TVP.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/TVP.java @@ -112,7 +112,12 @@ Object[] getRowData() throws SQLServerException { Object[] rowData = new Object[colCount]; for (int i = 0; i < colCount; i++) { try { - rowData[i] = sourceResultSet.getObject(i + 1); + if (java.sql.Types.TIME == sourceResultSet.getMetaData().getColumnType(i + 1)) { + rowData[i] = sourceResultSet.getTimestamp(i + 1); + } + else { + rowData[i] = sourceResultSet.getObject(i + 1); + } } catch (SQLException e) { throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveSourceData"), e); From b75da5c4f39d5ee1493ebb1d211842813099e6fb Mon Sep 17 00:00:00 2001 From: v-xiangs Date: Fri, 26 May 2017 11:28:42 -0700 Subject: [PATCH 2/3] add test --- .../sqlserver/jdbc/tvp/TVPIssuesTest.java | 138 +++++++++++++----- 1 file changed, 101 insertions(+), 37 deletions(-) diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPIssuesTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPIssuesTest.java index 78294fc80..e2b88cf4d 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPIssuesTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPIssuesTest.java @@ -35,10 +35,16 @@ public class TVPIssuesTest extends AbstractTest { static Connection connection = null; static Statement stmt = null; - private static String tvpName = "TVPIssuesTest_TVP"; - private static String procedureName = "TVPIssuesTest_SP"; - private static String srcTable = "TVPIssuesTest_src"; - private static String desTable = "TVPIssuesTest_dest"; + private static String tvp_varcharMax = "TVPIssuesTest_varcharMax_TVP"; + private static String spName_varcharMax = "TVPIssuesTest_varcharMax_SP"; + private static String srcTable_varcharMax = "TVPIssuesTest_varcharMax_srcTable"; + private static String desTable_varcharMax = "TVPIssuesTest_varcharMax_destTable"; + + private static String tvp_time_6 = "TVPIssuesTest_time_6_TVP"; + private static String srcTable_time_6 = "TVPIssuesTest_time_6_srcTable"; + private static String desTable_time_6 = "TVPIssuesTest_time_6_destTable"; + + private static String expectedTime6value = "15:39:27.616667"; @Test public void tryTVP_RS_varcharMax_4001_Issue() throws Exception { @@ -46,14 +52,15 @@ public void tryTVP_RS_varcharMax_4001_Issue() throws Exception { setup(); SQLServerStatement st = (SQLServerStatement) connection.createStatement(); - ResultSet rs = st.executeQuery("select * from " + srcTable); + ResultSet rs = st.executeQuery("select * from " + srcTable_varcharMax); - SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection.prepareStatement("INSERT INTO " + desTable + " select * from ? ;"); + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection + .prepareStatement("INSERT INTO " + desTable_varcharMax + " select * from ? ;"); - pstmt.setStructured(1, tvpName, rs); + pstmt.setStructured(1, tvp_varcharMax, rs); pstmt.execute(); - testDestinationTable(); + testCharDestTable(); } /** @@ -64,11 +71,11 @@ public void tryTVP_RS_varcharMax_4001_Issue() throws Exception { @Test public void testExceptionWithInvalidStoredProcedureName() throws Exception { SQLServerStatement st = (SQLServerStatement) connection.createStatement(); - ResultSet rs = st.executeQuery("select * from " + srcTable); + ResultSet rs = st.executeQuery("select * from " + srcTable_varcharMax); dropProcedure(); - final String sql = "{call " + procedureName + "(?)}"; + final String sql = "{call " + spName_varcharMax + "(?)}"; SQLServerCallableStatement Cstmt = (SQLServerCallableStatement) connection.prepareCall(sql); try { Cstmt.setObject(1, rs); @@ -84,8 +91,29 @@ public void testExceptionWithInvalidStoredProcedureName() throws Exception { } } - private void testDestinationTable() throws SQLException, IOException { - ResultSet rs = connection.createStatement().executeQuery("select * from " + desTable); + /** + * Fix an issue: If column is time(x) and TVP is used (with either ResultSet, Stored Procedure or SQLServerDataTable). The milliseconds or + * nanoseconds are not copied into the destination table. + * + * @throws Exception + */ + @Test + public void tryTVP_Precision_missed_issue_315() throws Exception { + + setup(); + + ResultSet rs = stmt.executeQuery("select * from " + srcTable_time_6); + + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection + .prepareStatement("INSERT INTO " + desTable_time_6 + " select * from ? ;"); + pstmt.setStructured(1, tvp_time_6, rs); + pstmt.execute(); + + testTime6DestTable(); + } + + private void testCharDestTable() throws SQLException, IOException { + ResultSet rs = connection.createStatement().executeQuery("select * from " + desTable_varcharMax); while (rs.next()) { assertEquals(rs.getString(1).length(), 4001, " The inserted length is truncated or not correct!"); } @@ -94,19 +122,14 @@ private void testDestinationTable() throws SQLException, IOException { } } - private static void populateSourceTable() throws SQLException { - String sql = "insert into " + srcTable + " values (?)"; - - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < 4001; i++) { - sb.append("a"); + private void testTime6DestTable() throws SQLException, IOException { + ResultSet rs = connection.createStatement().executeQuery("select * from " + desTable_time_6); + while (rs.next()) { + assertEquals(rs.getString(1), expectedTime6value, " The time value is truncated or not correct!"); + } + if (null != rs) { + rs.close(); } - String value = sb.toString(); - - SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection.prepareStatement(sql); - - pstmt.setString(1, value); - pstmt.execute(); } @BeforeAll @@ -117,31 +140,65 @@ public static void beforeAll() throws SQLException { dropProcedure(); - stmt.executeUpdate("IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvpName + "') " + " drop type " + tvpName); - Utils.dropTableIfExists(srcTable, stmt); - Utils.dropTableIfExists(desTable, stmt); + stmt.executeUpdate( + "IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvp_varcharMax + "') " + " drop type " + tvp_varcharMax); + Utils.dropTableIfExists(srcTable_varcharMax, stmt); + Utils.dropTableIfExists(desTable_varcharMax, stmt); + + stmt.executeUpdate( + "IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvp_time_6 + "') " + " drop type " + tvp_time_6); + Utils.dropTableIfExists(srcTable_time_6, stmt); + Utils.dropTableIfExists(desTable_time_6, stmt); - String sql = "create table " + srcTable + " (c1 varchar(max) null);"; + String sql = "create table " + srcTable_varcharMax + " (c1 varchar(max) null);"; + stmt.execute(sql); + sql = "create table " + desTable_varcharMax + " (c1 varchar(max) null);"; stmt.execute(sql); - sql = "create table " + desTable + " (c1 varchar(max) null);"; + sql = "create table " + srcTable_time_6 + " (c1 time(6) null);"; + stmt.execute(sql); + sql = "create table " + desTable_time_6 + " (c1 time(6) null);"; stmt.execute(sql); - String TVPCreateCmd = "CREATE TYPE " + tvpName + " as table (c1 varchar(max) null)"; + String TVPCreateCmd = "CREATE TYPE " + tvp_varcharMax + " as table (c1 varchar(max) null)"; + stmt.executeUpdate(TVPCreateCmd); + + TVPCreateCmd = "CREATE TYPE " + tvp_time_6 + " as table (c1 time(6) null)"; stmt.executeUpdate(TVPCreateCmd); createPreocedure(); - populateSourceTable(); + populateCharSrcTable(); + populateTime6SrcTable(); + } + + private static void populateCharSrcTable() throws SQLException { + String sql = "insert into " + srcTable_varcharMax + " values (?)"; + + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < 4001; i++) { + sb.append("a"); + } + String value = sb.toString(); + + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection.prepareStatement(sql); + + pstmt.setString(1, value); + pstmt.execute(); + } + + private static void populateTime6SrcTable() throws SQLException { + String sql = "insert into " + srcTable_time_6 + " values ('2017-05-12 " + expectedTime6value + "')"; + connection.createStatement().execute(sql); } private static void dropProcedure() throws SQLException { - Utils.dropProcedureIfExists(procedureName, stmt); + Utils.dropProcedureIfExists(spName_varcharMax, stmt); } private static void createPreocedure() throws SQLException { - String sql = "CREATE PROCEDURE " + procedureName + " @InputData " + tvpName + " READONLY " + " AS " + " BEGIN " + " INSERT INTO " + desTable - + " SELECT * FROM @InputData" + " END"; + String sql = "CREATE PROCEDURE " + spName_varcharMax + " @InputData " + tvp_varcharMax + " READONLY " + " AS " + " BEGIN " + " INSERT INTO " + + desTable_varcharMax + " SELECT * FROM @InputData" + " END"; stmt.execute(sql); } @@ -149,9 +206,16 @@ private static void createPreocedure() throws SQLException { @AfterAll public static void terminateVariation() throws SQLException { dropProcedure(); - stmt.executeUpdate("IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvpName + "') " + " drop type " + tvpName); - Utils.dropTableIfExists(srcTable, stmt); - Utils.dropTableIfExists(desTable, stmt); + stmt.executeUpdate( + "IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvp_varcharMax + "') " + " drop type " + tvp_varcharMax); + Utils.dropTableIfExists(srcTable_varcharMax, stmt); + Utils.dropTableIfExists(desTable_varcharMax, stmt); + + stmt.executeUpdate( + "IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvp_time_6 + "') " + " drop type " + tvp_time_6); + Utils.dropTableIfExists(srcTable_time_6, stmt); + Utils.dropTableIfExists(desTable_time_6, stmt); + if (null != connection) { connection.close(); } From f76d872c522e206d3698b5aff9ce972e0e670578 Mon Sep 17 00:00:00 2001 From: v-xiangs Date: Mon, 29 May 2017 13:34:16 -0700 Subject: [PATCH 3/3] add comment --- src/main/java/com/microsoft/sqlserver/jdbc/TVP.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/TVP.java b/src/main/java/com/microsoft/sqlserver/jdbc/TVP.java index 4332a4e55..7896215a3 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/TVP.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/TVP.java @@ -112,6 +112,8 @@ Object[] getRowData() throws SQLServerException { Object[] rowData = new Object[colCount]; for (int i = 0; i < colCount; i++) { try { + // for Time types, getting Timestamp instead of Time, because this value will be converted to String later on. If the value is a + // time object, the millisecond would be removed. if (java.sql.Types.TIME == sourceResultSet.getMetaData().getColumnType(i + 1)) { rowData[i] = sourceResultSet.getTimestamp(i + 1); }