From a0502f2b2b7244c01950180dea9881c4c2a0f50e Mon Sep 17 00:00:00 2001 From: v-xiangs Date: Wed, 22 Mar 2017 11:47:54 -0700 Subject: [PATCH 1/3] make pricision equal to the maximum among (precision - scale) plus the maximum scale --- .../microsoft/sqlserver/jdbc/SQLServerDataColumn.java | 1 + .../microsoft/sqlserver/jdbc/SQLServerDataTable.java | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataColumn.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataColumn.java index 74cffe6d0..7877cf3ab 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataColumn.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataColumn.java @@ -16,6 +16,7 @@ public final class SQLServerDataColumn { int javaSqlType; int precision = 0; int scale = 0; + int numberOfDigitsIntegerPart = 0; /** * Initializes a new instance of SQLServerDataColumn with the column name and type. diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataTable.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataTable.java index a0fc760f1..ec8cc9a39 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataTable.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataTable.java @@ -161,8 +161,17 @@ public synchronized void addRow(Object... values) throws SQLServerException { currentColumnMetadata.precision = precision; isColumnMetadataUpdated = true; } - if (isColumnMetadataUpdated) + + int numberOfDigitsIntegerPart = precision - bd.scale(); + if (numberOfDigitsIntegerPart > currentColumnMetadata.numberOfDigitsIntegerPart) { + currentColumnMetadata.numberOfDigitsIntegerPart = numberOfDigitsIntegerPart; + isColumnMetadataUpdated = true; + } + + if (isColumnMetadataUpdated) { + currentColumnMetadata.precision = currentColumnMetadata.scale + currentColumnMetadata.numberOfDigitsIntegerPart; columnMetadata.put(pair.getKey(), currentColumnMetadata); + } } rowValues[pair.getKey()] = bd; break; From 56da27ff93fb8237738e7f1a25a6d8ba9ebe5272 Mon Sep 17 00:00:00 2001 From: v-xiangs Date: Wed, 22 Mar 2017 12:31:02 -0700 Subject: [PATCH 2/3] added test --- .../sqlserver/jdbc/tvp/TVPNumericTest.java | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPNumericTest.java diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPNumericTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPNumericTest.java new file mode 100644 index 000000000..bc4fed492 --- /dev/null +++ b/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPNumericTest.java @@ -0,0 +1,125 @@ +/* + * Microsoft JDBC Driver for SQL Server + * + * Copyright(c) Microsoft Corporation All rights reserved. + * + * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package com.microsoft.sqlserver.jdbc.tvp; + +import java.sql.SQLException; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.platform.runner.JUnitPlatform; +import org.junit.runner.RunWith; + +import com.microsoft.sqlserver.jdbc.SQLServerDataTable; +import com.microsoft.sqlserver.jdbc.SQLServerException; +import com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement; +import com.microsoft.sqlserver.testframework.AbstractTest; +import com.microsoft.sqlserver.testframework.DBConnection; +import com.microsoft.sqlserver.testframework.DBResultSet; +import com.microsoft.sqlserver.testframework.DBStatement; + +@RunWith(JUnitPlatform.class) +public class TVPNumericTest extends AbstractTest { + + private static DBConnection conn = null; + static DBStatement stmt = null; + static DBResultSet rs = null; + static SQLServerDataTable tvp = null; + static String expectecValue1 = "hello"; + static String expectecValue2 = "world"; + static String expectecValue3 = "again"; + private static String tvpName = "numericTVP"; + private static String charTable = "tvpNumericTable"; + private static String procedureName = "procedureThatCallsTVP"; + + /** + * Test a previous failure regarding to numeric precision. Issue #211 + * + * @throws SQLServerException + */ + @Test + public void testNumericPresicionIssue_211() throws SQLServerException { + tvp = new SQLServerDataTable(); + tvp.addColumnMetadata("c1", java.sql.Types.NUMERIC); + + tvp.addRow(12.12); + tvp.addRow(1.123); + + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection + .prepareStatement("INSERT INTO " + charTable + " select * from ? ;"); + pstmt.setStructured(1, tvpName, tvp); + + pstmt.execute(); + + if (null != pstmt) { + pstmt.close(); + } + } + + @BeforeEach + private void testSetup() throws SQLException { + conn = new DBConnection(connectionString); + stmt = conn.createStatement(); + + dropProcedure(); + dropTables(); + dropTVPS(); + + createTVPS(); + createTables(); + createPreocedure(); + } + + private void dropProcedure() throws SQLException { + String sql = " IF EXISTS (select * from sysobjects where id = object_id(N'" + procedureName + "') and OBJECTPROPERTY(id, N'IsProcedure') = 1)" + + " DROP PROCEDURE " + procedureName; + stmt.execute(sql); + } + + private static void dropTables() throws SQLException { + stmt.executeUpdate("if object_id('" + charTable + "','U') is not null" + " drop table " + charTable); + } + + private static void dropTVPS() throws SQLException { + stmt.executeUpdate("IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvpName + "') " + " drop type " + tvpName); + } + + private static void createPreocedure() throws SQLException { + String sql = "CREATE PROCEDURE " + procedureName + " @InputData " + tvpName + " READONLY " + " AS " + " BEGIN " + " INSERT INTO " + charTable + + " SELECT * FROM @InputData" + " END"; + + stmt.execute(sql); + } + + private void createTables() throws SQLException { + String sql = "create table " + charTable + " (c1 numeric(6,3) null);"; + stmt.execute(sql); + } + + private void createTVPS() throws SQLException { + String TVPCreateCmd = "CREATE TYPE " + tvpName + " as table (c1 numeric(6,3) null)"; + stmt.executeUpdate(TVPCreateCmd); + } + + @AfterEach + private void terminateVariation() throws SQLException { + if (null != conn) { + conn.close(); + } + if (null != stmt) { + stmt.close(); + } + if (null != rs) { + rs.close(); + } + if (null != tvp) { + tvp.clear(); + } + } + +} \ No newline at end of file From 3e9b6e1aef798b8c9beba0d07c86338d9e85f9ab Mon Sep 17 00:00:00 2001 From: v-xiangs Date: Tue, 28 Mar 2017 14:57:04 -0700 Subject: [PATCH 3/3] added comment --- .../java/com/microsoft/sqlserver/jdbc/SQLServerDataTable.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataTable.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataTable.java index ec8cc9a39..d0fb9b589 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataTable.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataTable.java @@ -162,6 +162,7 @@ public synchronized void addRow(Object... values) throws SQLServerException { isColumnMetadataUpdated = true; } + // precision equal: the maximum number of digits in integer part + the maximum scale int numberOfDigitsIntegerPart = precision - bd.scale(); if (numberOfDigitsIntegerPart > currentColumnMetadata.numberOfDigitsIntegerPart) { currentColumnMetadata.numberOfDigitsIntegerPart = numberOfDigitsIntegerPart;