From 926ad0091677252ba2d0fef3a7f0a13401c74d87 Mon Sep 17 00:00:00 2001 From: v-afrafi Date: Thu, 12 Jan 2017 18:31:58 -0800 Subject: [PATCH 01/28] bvt updates --- .../microsoft/sqlserver/jdbc/bvt/bvtTest.java | 1373 +++++++++-------- .../sqlserver/jdbc/bvt/bvtTestSetup.java | 73 + .../sqlserver/testframework/DBColumn.java | 2 +- .../sqlserver/testframework/DBConnection.java | 177 ++- .../sqlserver/testframework/DBResultSet.java | 181 +++ .../testframework/DBResultSetMetaData.java | 108 ++ .../sqlserver/testframework/DBStatement.java | 20 +- .../sqlserver/testframework/DBTable.java | 37 +- 8 files changed, 1252 insertions(+), 719 deletions(-) create mode 100644 src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTestSetup.java create mode 100644 src/test/java/com/microsoft/sqlserver/testframework/DBResultSetMetaData.java diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTest.java index 321f4f230..d85b0c51f 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTest.java @@ -1,137 +1,173 @@ /* * Microsoft JDBC Driver for SQL Server * - * Copyright(c) 2016 Microsoft Corporation - * All rights reserved. + * Copyright(c) 2016 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. + * 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.bvt; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import java.math.BigDecimal; import java.sql.Connection; import java.sql.DatabaseMetaData; -import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; -import java.sql.Statement; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.junit.AfterClass; import org.junit.BeforeClass; -import org.junit.Test; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.platform.runner.JUnitPlatform; +import org.junit.runner.RunWith; import com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement; +import com.microsoft.sqlserver.jdbc.bvt.bvt_ResultSet; +import com.microsoft.sqlserver.testframework.AbstractTest; +import com.microsoft.sqlserver.testframework.DBConnection; +import com.microsoft.sqlserver.testframework.DBResultSet; +import com.microsoft.sqlserver.testframework.DBStatement; +import com.microsoft.sqlserver.testframework.DBTable; + +@RunWith(JUnitPlatform.class) +@DisplayName("BVT Test") +public class bvtTest extends bvtTestSetup { + private static boolean cursor = false; + private static boolean querytimeout = false; + // private static String connectionUrl = ""; + private static Connection con; + private static String driverNamePattern = "Microsoft JDBC Driver \\d.\\d for SQL Server"; + // private static String table1 = "stmt_test_bvt"; + // private static String table2 = "rs_test_bvt"; + // private static Statement stmt = null; + private static DBResultSet rs = null; + private static SQLServerPreparedStatement pstmt = null; + private static bvt_ResultSet bvt_rs = null; + private static DBConnection conn = null; + private static DBStatement stmt = null; + +// private static DBTable table1 = null; +// private static DBTable table2 = null; + +// @BeforeClass +// public static void init() throws SQLException { +// // try { +// // Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); +// // } +// // catch (ClassNotFoundException e) { +// // e.printStackTrace(); +// // } +// +// // Statement stmt = null; +// try { +// // stmt = conn().createStatement(); +// conn = new DBConnection(connectionString); +// stmt = conn.createStatement(); +// +// // create tables +// table1 = new DBTable(true); +// stmt.createTable(table1); +// table2 = new DBTable(true); +// stmt.createTable(table2); +// +// // // CREATE the table +// // stmt.executeUpdate(Tables.dropTable(table1)); +// // stmt.executeUpdate(Tables.createTable(table1)); +// // // CREATE the data to populate the table with +// // Values.createData(); +// // Tables.populate(table1, stmt); +// // +// // stmt.executeUpdate(Tables.dropTable(table2)); +// // stmt.executeUpdate(Tables.createTable(table2)); +// // Tables.populate(table2, stmt); +// } +// finally { +// if (null != stmt) { +// stmt.close(); +// } +// terminateVariation(); +// } +// } -public class bvtTest { - private static boolean cursor = false; - private static boolean querytimeout = false; - private static String connectionUrl = ""; - private static Connection con; - private static String driverNamePattern = "Microsoft JDBC Driver \\d.\\d for SQL Server"; - private static String table1 = "stmt_test_bvt"; - private static String table2 = "rs_test_bvt"; - private static Statement stmt = null; - private static ResultSet rs = null; - private static SQLServerPreparedStatement pstmt = null; - private static bvt_ResultSet bvt_rs = null; - - @BeforeClass - public static void init() throws SQLException { - try { - Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } - - Statement stmt = null; - try { - stmt = conn().createStatement(); - - // CREATE the table - stmt.executeUpdate(Tables.dropTable(table1)); - stmt.executeUpdate(Tables.createTable(table1)); - // CREATE the data to populate the table with - Values.createData(); - Tables.populate(table1, stmt); - - stmt.executeUpdate(Tables.dropTable(table2)); - stmt.executeUpdate(Tables.createTable(table2)); - Tables.populate(table2, stmt); - } finally { - if (null != stmt) { - stmt.close(); - } - terminateVariation(); - } - } + /////////////////////////////////////////////////////////////////// + //// Connect to specified server and close the connection + ///////////////////////////////////////////////////////////////////// + @Test + @DisplayName("test connection") + public void testConnection() throws SQLException { + try { + conn = new DBConnection(connectionString); + conn.close(); + } + finally { + terminateVariation(); + } + } + + ///////////////////////////////////////////////////////////////////// + //// Verify isClosed() + ///////////////////////////////////////////////////////////////////// + @Test + public void testConnectionIsClosed() throws SQLException { + try { + conn = new DBConnection(connectionString); + assertTrue("BVT connection should not be closed", !conn.isClosed()); + conn.close(); + assertTrue("BVT connection should not be open", conn.isClosed()); + } + finally { + terminateVariation(); + } + } + + ///////////////////////////////////////////////////////////////////// + //// Verify Driver Name and Version from MetaData + ///////////////////////////////////////////////////////////////////// + @Test + public void testDriverNameAndDriverVersion() throws SQLException { + try { + conn = new DBConnection(connectionString); + DatabaseMetaData metaData = conn.getMetaData(); + Pattern p = Pattern.compile(driverNamePattern); + Matcher m = p.matcher(metaData.getDriverName()); + assertTrue("Driver name is not a correct format! ", m.find()); + String[] parts = metaData.getDriverVersion().split("\\."); + if (parts.length != 4) + assertTrue("Driver version number should be four parts! ", true); + } + finally { + terminateVariation(); + } + } - /////////////////////////////////////////////////////////////////// - //// Connect to specified server and close the connection - ///////////////////////////////////////////////////////////////////// - @Test - public void testConnection() throws SQLException { - try { - conn().close(); - } finally { - terminateVariation(); - } - } + /////////////////////////////////////////////////////////////////// + // Create a statement, call close + /////////////////////////////////////////////////////////////////// + @Test + public void testCreateStatement() throws SQLException { - ///////////////////////////////////////////////////////////////////// - //// Verify isClosed() - ///////////////////////////////////////////////////////////////////// - @Test - public void testConnectionIsClosed() throws SQLException { - try { - Connection conn = conn(); - assertTrue("BVT connection should not be closed", !conn.isClosed()); - conn.close(); - assertTrue("BVT connection should not be open", conn.isClosed()); - } finally { - terminateVariation(); - } - } + try { + conn = new DBConnection(connectionString); + stmt = conn.createStatement(); + // SELECT * FROM + String query = "SELECT * FROM " + table1.getEscapedTableName() + ";"; + rs = stmt.executeQuery(query); + rs.verify(table1); + // bvt_rs = new bvt_ResultSet(rs); - ///////////////////////////////////////////////////////////////////// - //// Verify Driver Name and Version from MetaData - ///////////////////////////////////////////////////////////////////// - @Test - public void testDriverNameAndDriverVersion() throws SQLException { - try { - DatabaseMetaData metaData = conn().getMetaData(); - Pattern p = Pattern.compile(driverNamePattern); - Matcher m = p.matcher(metaData.getDriverName()); - assertTrue("Driver name is not a correct format! ", m.find()); - String[] parts = metaData.getDriverVersion().split("\\."); - if (parts.length != 4) - assertTrue("Driver version number should be four parts! ", true); - } finally { - terminateVariation(); - } - } + // close and verify - @Test - public void testCreateStatement() throws SQLException { + // bvt_rs.verify(); - try { - stmt = conn().createStatement(); - // SELECT * FROM - String query = Tables.select(table1); - rs = stmt.executeQuery(query); - bvt_rs = new bvt_ResultSet(rs); + } + finally { - // close and verify - bvt_rs.verify(); - } finally { - terminateVariation(); - } - } + terminateVariation(); + } + } /////////////////////////////////////////////////////////////////// // Create a statement with a query timeout @@ -139,540 +175,593 @@ public void testCreateStatement() throws SQLException { // ResultSet.CONCUR_READ_ONLY, executeQuery // verify cursor by using next and previous and verify data /////////////////////////////////////////////////////////////////// - @Test - public void testCreateStatementWithQueryTimeout() throws SQLException { - - querytimeout = true; - - try { - stmt = conn().createStatement(); - assertEquals(10, stmt.getQueryTimeout()); - } finally { - terminateVariation(); - querytimeout = false; - } - } - - /////////////////////////////////////////////////////////////////// - // Create a statement - // ResultSet.Type_forward_only, - // ResultSet.CONCUR_READ_ONLY, executeQuery - // verify cursor by using next and previous and verify data - /////////////////////////////////////////////////////////////////// - @Test - public void testStmtForwardOnlyReadOnly() throws SQLException, ClassNotFoundException { - - try { - stmt = conn().createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); - - // SELECT * FROM ORDER BY - String pk = Tables.primaryKey(); - String query = Tables.select_Orderby(table1, pk); - rs = stmt.executeQuery(query); - - bvt_rs = new bvt_ResultSet(rs); - // Verify resultset behavior - bvt_rs.next(); - bvt_rs.verifyCurrentRow(); - bvt_rs.next(); - bvt_rs.verifyCurrentRow(); - try { - bvt_rs.previous(); - assertTrue("Previous should have thrown an exception", false); - } catch (SQLException ex) { - // expected exception - } - bvt_rs.verify(); - } finally { - terminateVariation(); - } - } - - /////////////////////////////////////////////////////////////////// - // Create a statement - // ResultSet.SCROLL_INSENSITIVE, - // ResultSet.CONCUR_READ_ONLY, executeQuery - // verify cursor by using next, afterlast and previous and verify data - /////////////////////////////////////////////////////////////////// - @Test - public void testStmtScrollInsensitiveReadOnly() throws SQLException, ClassNotFoundException { - try { - stmt = conn().createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); - - // SELECT * FROM ORDER BY , - String c1 = Tables.primaryKey(); - String c2 = "[c1_char(512)]"; - - Tables.select(table1); - Tables.orderby(c1); - Tables.orderby(c2); - - rs = stmt.executeQuery(Tables.query); - bvt_rs = new bvt_ResultSet(rs); - - // Verify resultset behavior - bvt_rs.next(); - bvt_rs.verifyCurrentRow(); - bvt_rs.afterLast(); - bvt_rs.previous(); - bvt_rs.verifyCurrentRow(); - bvt_rs.verify(); - } finally { - terminateVariation(); - } - } - - ///////////////////////////////////////////////////////////////// - // Create a statement - // ResultSet.SCROLL_SENSITIVE, - // ResultSet.CONCUR_READ_ONLY, executeQuery - // verify cursor by using next and absolute and verify data - /////////////////////////////////////////////////////////////////// - @Test - public void testStmtScrollSensitiveReadOnly() throws SQLException { - - try { - stmt = conn().createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); - - // SELECT * FROM ORDER BY - String pk = Tables.primaryKey(); - String query = Tables.select_Orderby(table1, pk); - rs = stmt.executeQuery(query); - bvt_rs = new bvt_ResultSet(rs); - - // Verify resultset behavior - bvt_rs.next(); - bvt_rs.next(); - bvt_rs.verifyCurrentRow(); - bvt_rs.absolute(3); - bvt_rs.verifyCurrentRow(); - bvt_rs.absolute(1); - bvt_rs.verify(); - } finally { - terminateVariation(); - } - } - - /////////////////////////////////////////////////////////////////// - // Create a statement - // ResultSet.Type_forward_only, - // ResultSet.CONCUR_UPDATABLE, executeQuery - // verify cursor by using next and previous and verify data - /////////////////////////////////////////////////////////////////// - @Test - public void testStmtForwardOnlyUpdateable() throws SQLException { - - try { - stmt = conn().createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); - - // SELECT * FROM ORDER BY - String pk = Tables.primaryKey(); - String query = Tables.select_Orderby(table1, pk); - rs = stmt.executeQuery(query); - bvt_rs = new bvt_ResultSet(rs); - - // Verify resultset behavior - bvt_rs.next(); - bvt_rs.verifyCurrentRow(); - bvt_rs.next(); - bvt_rs.verifyCurrentRow(); - try { - bvt_rs.previous(); - assertTrue("Previous should have thrown an exception", false); - } catch (SQLException ex) { - // expected exception - } - bvt_rs.verify(); - } finally { - terminateVariation(); - } - } - - /////////////////////////////////////////////////////////////////// - // Create a statement - // ResultSet.SCROLL_SENSITIVE, - // ResultSet.CONCUR_UPDATABLE, executeQuery - // verify cursor by using next and previous and verify data - /////////////////////////////////////////////////////////////////// - @Test - public void testStmtScrollSensitiveUpdatable() throws SQLException { - - try { - stmt = conn().createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); - - // SELECT * FROM ORDER BY - String pk = Tables.primaryKey(); - String query = Tables.select_Orderby(table1, pk); - rs = stmt.executeQuery(query); - bvt_rs = new bvt_ResultSet(rs); - - // Verify resultset behavior - bvt_rs.next(); - bvt_rs.next(); - bvt_rs.verifyCurrentRow(); - bvt_rs.absolute(3); - bvt_rs.verifyCurrentRow(); - bvt_rs.absolute(1); - bvt_rs.verify(); - } finally { - terminateVariation(); - } - } - - /////////////////////////////////////////////////////////////////// - // Create a statement - // TYPE_SS_SCROLL_DYNAMIC, - // CONCUR_SS_OPTIMISTIC_CC, executeQuery - // verify cursor by using next and previous and verify data - /////////////////////////////////////////////////////////////////// - @Test - public void testStmtSS_ScrollDynamicOptimistic_CC() throws SQLException { - - try { - int TYPE_SS_SCROLL_DYNAMIC = 1006; - int CONCUR_SS_OPTIMISTIC_CC = 1008; - stmt = conn().createStatement(TYPE_SS_SCROLL_DYNAMIC, CONCUR_SS_OPTIMISTIC_CC); - - // SELECT * FROM ORDER BY , ASC|DESC - String c1 = Tables.primaryKey(); - String c2 = "[c1_char(512)]"; - - Tables.select(table1); - Tables.orderby(c1); - Tables.orderby(c2); - - rs = stmt.executeQuery(Tables.query); - bvt_rs = new bvt_ResultSet(rs); - - // Verify resultset behavior - bvt_rs.next(); - bvt_rs.afterLast(); - bvt_rs.previous(); - bvt_rs.verify(); - } finally { - terminateVariation(); - } - } - - /////////////////////////////////////////////////////////////////// - // Create a statement - // TYPE_SS_SEVER_CURSOR_FORWARD_ONLY, - // CONCUR_READ_ONLY, executeQuery - // verify cursor by using next and verify data - /////////////////////////////////////////////////////////////////// - @Test - public void testStmtSS_SEVER_CURSOR_FORWARD_ONLY() throws SQLException { - - try { - int TYPE_SS_SEVER_CURSOR_FORWARD_ONLY = 2004; - int CONCUR_READ_ONLY = 1008; - stmt = conn().createStatement(TYPE_SS_SEVER_CURSOR_FORWARD_ONLY, CONCUR_READ_ONLY); - - String c1 = Tables.primaryKey(); - String c2 = "[c1_char(512)]"; - - Tables.select(table1); - Tables.orderby(c1); - Tables.orderby(c2); - - rs = stmt.executeQuery(Tables.query); - bvt_rs = new bvt_ResultSet(rs); - - // Verify resultset behavior - bvt_rs.next(); - bvt_rs.verify(); - } finally { - terminateVariation(); - } - - } - - /////////////////////////////////////////////////////////////////// - // Create a preparedstatement, call close - /////////////////////////////////////////////////////////////////// - @Test - public void testCreatepreparedStatement() throws SQLException { - - try { - String pk = Tables.primaryKey(); - String query = "SELECT * from " + table1 + " where c30_smallmoney = ? order by " + pk; - - pstmt = (SQLServerPreparedStatement) conn().prepareStatement(query); - pstmt.setSmallMoney(1, new BigDecimal("214748.3647")); - - rs = pstmt.executeQuery(); - bvt_rs = new bvt_ResultSet(rs); - bvt_rs.verify(); - } finally { - terminateVariation(); - } - } - - /////////////////////////////////////////////////////////////////// - // Verify resultset using ResultSetMetaData - /////////////////////////////////////////////////////////////////// - @Test - public void testResultSet() throws SQLException { - - try { - stmt = conn().createStatement(); - // SELECT * FROM ORDER BY - String pk = Tables.primaryKey(); - String query = Tables.select_Orderby(table2, pk); - rs = stmt.executeQuery(query); - bvt_rs = new bvt_ResultSet(rs); - - // verify resultSet - bvt_rs.verify(); - } finally { - terminateVariation(); - } - } - - /////////////////////////////////////////////////////////////////// - // Verify resultset and close resultSet - /////////////////////////////////////////////////////////////////// - @Test - public void testResultSetAndClose() throws SQLException { - - try { - stmt = conn().createStatement(); - - // SELECT * FROM ORDER BY - String pk = Tables.primaryKey(); - String query = Tables.select_Orderby(table2, pk); - rs = stmt.executeQuery(query); - } finally { - terminateVariation(); - } - } - - /////////////////////////////////////////////////////////////////// - // Verify two concurrent resultsets from same connection, - // separate statements - /////////////////////////////////////////////////////////////////// - @Test - public void testTwoResultsetsDifferentStmt() throws SQLException { - - Statement stmt1 = null; - Statement stmt2 = null; - ResultSet rs1 = null; - ResultSet rs2 = null; - bvt_ResultSet bvt_rs1 = null; - bvt_ResultSet bvt_rs2 = null; - try { - stmt1 = conn().createStatement(); - stmt2 = conn().createStatement(); - - // SELECT * FROM ORDER BY - String pk = Tables.primaryKey(); - String query = Tables.select_Orderby(table2, pk); - rs1 = stmt1.executeQuery(query); - - String query2 = Tables.select_Orderby(table1, pk); - rs2 = stmt2.executeQuery(query2); - bvt_rs1 = new bvt_ResultSet(rs1); - bvt_rs2 = new bvt_ResultSet(rs2); - - // Interleave resultset calls - bvt_rs1.next(); - bvt_rs1.verifyCurrentRow(); - bvt_rs2.next(); - bvt_rs2.verifyCurrentRow(); - bvt_rs1.next(); - bvt_rs1.verifyCurrentRow(); - bvt_rs1.verify(); - bvt_rs1.close(); - bvt_rs2.next(); - bvt_rs2.verify(); - } finally { - if (null != bvt_rs2) { - bvt_rs2.close(); - } - if (null != rs1) { - rs1.close(); - } - if (null != rs2) { - rs2.close(); - } - if (null != stmt1) { - stmt1.close(); - } - if (null != stmt2) { - stmt2.close(); - } - terminateVariation(); - } - } - - /////////////////////////////////////////////////////////////////// - // Verify two concurrent resultsets from same connection, - // same statement - /////////////////////////////////////////////////////////////////// - @Test - public void testTwoResultsetsSameStmt() throws SQLException { - - ResultSet rs1 = null; - ResultSet rs2 = null; - try { - stmt = conn().createStatement(); - - // SELECT * FROM ORDER BY - String pk = Tables.primaryKey(); - String query = Tables.select_Orderby(table2, pk); - rs1 = stmt.executeQuery(query); - - // SELECT * FROM ORDER BY - String query2 = Tables.select_Orderby(table1, pk); - rs2 = stmt.executeQuery(query2); - - bvt_ResultSet bvt_rs1 = new bvt_ResultSet(rs1); - bvt_ResultSet bvt_rs2 = new bvt_ResultSet(rs2); - - // Interleave resultset calls. rs is expected to be closed - try { - bvt_rs1.next(); - } catch (SQLException e) { - assertEquals(e.toString(), - "com.microsoft.sqlserver.jdbc.SQLServerException: The result set is closed."); - } - bvt_rs2.next(); - bvt_rs2.verifyCurrentRow(); - try { - bvt_rs1.next(); - } catch (SQLException e) { - assertEquals(e.toString(), - "com.microsoft.sqlserver.jdbc.SQLServerException: The result set is closed."); - } - bvt_rs1.close(); - bvt_rs2.next(); - bvt_rs2.verify(); - } finally { - if (null != rs1) { - rs1.close(); - } - if (null != rs2) { - rs2.close(); - } - terminateVariation(); - } - } - - /////////////////////////////////////////////////////////////////// - // Verify resultset closed after statement is closed - /////////////////////////////////////////////////////////////////// - @Test - public void testResultSetAndCloseStmt() throws SQLException { - try { - stmt = conn().createStatement(); - - // SELECT * FROM ORDER BY - String pk = Tables.primaryKey(); - String query = Tables.select_Orderby(table2, pk); - rs = stmt.executeQuery(query); - bvt_rs = new bvt_ResultSet(rs); - - // close statement and verify resultSet - stmt.close(); // this should close the resultSet - try { - bvt_rs.next(); - } catch (SQLException e) { - assertEquals(e.toString(), - "com.microsoft.sqlserver.jdbc.SQLServerException: The result set is closed."); - } - } finally { - terminateVariation(); - } - } - - /////////////////////////////////////////////////////////////////// - // Verify resultset using SelectMethod - /////////////////////////////////////////////////////////////////// - @Test - public void testResultSetSelectMethod() throws SQLException { - - // guarantees selectMethod=cursor - cursor = true; - try { - stmt = conn().createStatement(); - - // SELECT * FROM ORDER BY - String pk = Tables.primaryKey(); - String query = Tables.select_Orderby(table2, pk); - rs = stmt.executeQuery(query); - bvt_rs = new bvt_ResultSet(rs); - - // verify resultSet - bvt_rs.verify(); - cursor = false; - } finally { - terminateVariation(); - } - } - - @AfterClass - public static void terminate() throws SQLException { - - try { - stmt = conn().createStatement(); - stmt.executeUpdate(Tables.dropTable(table2)); - stmt.executeUpdate(Tables.dropTable(table1)); - } finally { - terminateVariation(); - } - } - - public static String getConnectionURL() { - connectionUrl = System.getenv("mssql_jdbc_test_connection_properties"); - - if(null == connectionUrl){ - fail("Please setup environment variable mssql_jdbc_test_connection_properties"); - } - - if (cursor){ - connectionUrl += ";selectMethod=cursor;"; - } - - if (querytimeout){ - connectionUrl += ";queryTimeout=10"; - } - - return connectionUrl; - } - - public static Connection conn() { - - connectionUrl = getConnectionURL(); - // Establish the connection. - try { - - Connection con = DriverManager.getConnection(connectionUrl); - return con; - // Handle any errors that may have occurred. - } catch (SQLException e) { - fail("Please make sure the environment variable mssql_jdbc_test_connection_properties is set with correct connection properties.\n" - + e.toString()); - } - return null; - } - - public static void terminateVariation() throws SQLException { - if (con != null && !con.isClosed()) { - try { - con.close(); - } catch (SQLException e) { - fail("Connection close threw : " + e.toString()); - } finally { - if (null != bvt_rs) - bvt_rs.close(); - if (null != rs) - rs.close(); - if (null != stmt) - stmt.close(); - if (null != pstmt) - pstmt.close(); - } - } - } + @Test + public void testCreateStatementWithQueryTimeout() throws SQLException { + + querytimeout = true; + + try { + conn = new DBConnection(connectionString); + stmt = conn.createStatement(); + assertEquals(10, stmt.getQueryTimeout()); + } + finally { + terminateVariation(); + querytimeout = false; + } + } + + // + // /////////////////////////////////////////////////////////////////// + // // Create a statement + // // ResultSet.Type_forward_only, + // // ResultSet.CONCUR_READ_ONLY, executeQuery + // // verify cursor by using next and previous and verify data + // /////////////////////////////////////////////////////////////////// + // @Test + // public void testStmtForwardOnlyReadOnly() throws SQLException, ClassNotFoundException { + // + // try { + // stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + // + // // SELECT * FROM ORDER BY + // String query = "SELECT * FROM "+ table1.getEscapedTableName(); + // rs = stmt.executeQuery(query); + // + // + // rs.next(); + // rs.verifyCurrentRow(table1); + // rs.next(); + // rs.verifyCurrentRow(); + // + // try{ + // rs.previous(); + // assertTrue("Previous should have thrown an exception", false); + // } + // catch (SQLException ex) { + // // expected exception + // } + // rs.verify(); + // } + // finally { + // terminateVariation(); + // } + // + //// bvt_rs = new bvt_ResultSet(rs); + //// // Verify resultset behavior + //// bvt_rs.next(); + //// bvt_rs.verifyCurrentRow(); + //// bvt_rs.next(); + //// bvt_rs.verifyCurrentRow(); + //// try { + //// bvt_rs.previous(); + //// assertTrue("Previous should have thrown an exception", false); + //// } + //// catch (SQLException ex) { + //// // expected exception + //// } + //// bvt_rs.verify(); + //// } + //// finally { + //// terminateVariation(); + //// } + // } + // + /////////////////////////////////////////////////////////////////// + // Create a statement + // ResultSet.SCROLL_INSENSITIVE, + // ResultSet.CONCUR_READ_ONLY, executeQuery + // verify cursor by using next, afterlast and previous and verify data + /////////////////////////////////////////////////////////////////// + @Test + public void testStmtScrollInsensitiveReadOnly() throws SQLException, ClassNotFoundException { + try { + stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); + + // SELECT * FROM ORDER BY , +// String c1 = Tables.primaryKey(); +// String c2 = "[c1_char(512)]"; +// +// Tables.select(table1); +// Tables.orderby(c1); +// Tables.orderby(c2); + + String query = "SELECT * FROM" + table1.getEscapedTableName(); +// rs = stmt.executeQuery(Tables.query); + rs = stmt.executeQuery(query); + rs.next(); + rs.verifyCurrentRow(); + rs.afterLast(); + rs.verifyCurrentRow(); + rs.verify(table1); +// bvt_rs = new bvt_ResultSet(rs); + + // Verify resultset behavior +// bvt_rs.next(); +// bvt_rs.verifyCurrentRow(); +// bvt_rs.afterLast(); +// bvt_rs.previous(); +// bvt_rs.verifyCurrentRow(); +// bvt_rs.verify(); + } + finally { + terminateVariation(); + } + } + // + // ///////////////////////////////////////////////////////////////// + // // Create a statement + // // ResultSet.SCROLL_SENSITIVE, + // // ResultSet.CONCUR_READ_ONLY, executeQuery + // // verify cursor by using next and absolute and verify data + // /////////////////////////////////////////////////////////////////// + @Test + public void testStmtScrollSensitiveReadOnly() throws SQLException { + + try { + stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); + + // SELECT * FROM ORDER BY +// String pk = Tables.primaryKey(); +// String query = Tables.select_Orderby(table1, pk); + String query = "SELECT * FROM "+ table1.getEscapedTableName(); + rs = stmt.executeQuery(query); + rs.next(); + rs.next(); + rs.verifyCurrentRow(); + rs.absolute(3); + rs.verifyCurrentRow(); + rs.absolute(1); + rs.verify(table1); +// bvt_rs = new bvt_ResultSet(rs); + + // Verify resultset behavior +// bvt_rs.next(); +// bvt_rs.next(); +// bvt_rs.verifyCurrentRow(); +// bvt_rs.absolute(3); +// bvt_rs.verifyCurrentRow(); +// bvt_rs.absolute(1); +// bvt_rs.verify(); + } + finally { + terminateVariation(); + } + } + // + // /////////////////////////////////////////////////////////////////// + // // Create a statement + // // ResultSet.Type_forward_only, + // // ResultSet.CONCUR_UPDATABLE, executeQuery + // // verify cursor by using next and previous and verify data + // /////////////////////////////////////////////////////////////////// + // @Test + // public void testStmtForwardOnlyUpdateable() throws SQLException { + // + // try { + // stmt = conn().createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); + // + // // SELECT * FROM ORDER BY + // String pk = Tables.primaryKey(); + // String query = Tables.select_Orderby(table1, pk); + // rs = stmt.executeQuery(query); + // bvt_rs = new bvt_ResultSet(rs); + // + // // Verify resultset behavior + // bvt_rs.next(); + // bvt_rs.verifyCurrentRow(); + // bvt_rs.next(); + // bvt_rs.verifyCurrentRow(); + // try { + // bvt_rs.previous(); + // assertTrue("Previous should have thrown an exception", false); + // } + // catch (SQLException ex) { + // // expected exception + // } + // bvt_rs.verify(); + // } + // finally { + // terminateVariation(); + // } + // } + // + // /////////////////////////////////////////////////////////////////// + // // Create a statement + // // ResultSet.SCROLL_SENSITIVE, + // // ResultSet.CONCUR_UPDATABLE, executeQuery + // // verify cursor by using next and previous and verify data + // /////////////////////////////////////////////////////////////////// + // @Test + // public void testStmtScrollSensitiveUpdatable() throws SQLException { + // + // try { + // stmt = conn().createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); + // + // // SELECT * FROM ORDER BY + // String pk = Tables.primaryKey(); + // String query = Tables.select_Orderby(table1, pk); + // rs = stmt.executeQuery(query); + // bvt_rs = new bvt_ResultSet(rs); + // + // // Verify resultset behavior + // bvt_rs.next(); + // bvt_rs.next(); + // bvt_rs.verifyCurrentRow(); + // bvt_rs.absolute(3); + // bvt_rs.verifyCurrentRow(); + // bvt_rs.absolute(1); + // bvt_rs.verify(); + // } + // finally { + // terminateVariation(); + // } + // } + // + // /////////////////////////////////////////////////////////////////// + // // Create a statement + // // TYPE_SS_SCROLL_DYNAMIC, + // // CONCUR_SS_OPTIMISTIC_CC, executeQuery + // // verify cursor by using next and previous and verify data + // /////////////////////////////////////////////////////////////////// + // @Test + // public void testStmtSS_ScrollDynamicOptimistic_CC() throws SQLException { + // + // try { + // int TYPE_SS_SCROLL_DYNAMIC = 1006; + // int CONCUR_SS_OPTIMISTIC_CC = 1008; + // stmt = conn().createStatement(TYPE_SS_SCROLL_DYNAMIC, CONCUR_SS_OPTIMISTIC_CC); + // + // // SELECT * FROM
ORDER BY , ASC|DESC + // String c1 = Tables.primaryKey(); + // String c2 = "[c1_char(512)]"; + // + // Tables.select(table1); + // Tables.orderby(c1); + // Tables.orderby(c2); + // + // rs = stmt.executeQuery(Tables.query); + // bvt_rs = new bvt_ResultSet(rs); + // + // // Verify resultset behavior + // bvt_rs.next(); + // bvt_rs.afterLast(); + // bvt_rs.previous(); + // bvt_rs.verify(); + // } + // finally { + // terminateVariation(); + // } + // } + // + // /////////////////////////////////////////////////////////////////// + // // Create a statement + // // TYPE_SS_SEVER_CURSOR_FORWARD_ONLY, + // // CONCUR_READ_ONLY, executeQuery + // // verify cursor by using next and verify data + // /////////////////////////////////////////////////////////////////// + // @Test + // public void testStmtSS_SEVER_CURSOR_FORWARD_ONLY() throws SQLException { + // + // try { + // int TYPE_SS_SEVER_CURSOR_FORWARD_ONLY = 2004; + // int CONCUR_READ_ONLY = 1008; + // stmt = conn().createStatement(TYPE_SS_SEVER_CURSOR_FORWARD_ONLY, CONCUR_READ_ONLY); + // + // String c1 = Tables.primaryKey(); + // String c2 = "[c1_char(512)]"; + // + // Tables.select(table1); + // Tables.orderby(c1); + // Tables.orderby(c2); + // + // rs = stmt.executeQuery(Tables.query); + // bvt_rs = new bvt_ResultSet(rs); + // + // // Verify resultset behavior + // bvt_rs.next(); + // bvt_rs.verify(); + // } + // finally { + // terminateVariation(); + // } + // + // } + // + // /////////////////////////////////////////////////////////////////// + // // Create a preparedstatement, call close + // /////////////////////////////////////////////////////////////////// + // @Test + // public void testCreatepreparedStatement() throws SQLException { + // + // try { + // String pk = Tables.primaryKey(); + // String query = "SELECT * from " + table1 + " where c30_smallmoney = ? order by " + pk; + // + // pstmt = (SQLServerPreparedStatement) conn().prepareStatement(query); + // pstmt.setSmallMoney(1, new BigDecimal("214748.3647")); + // + // rs = pstmt.executeQuery(); + // bvt_rs = new bvt_ResultSet(rs); + // bvt_rs.verify(); + // } + // finally { + // terminateVariation(); + // } + // } + // + // /////////////////////////////////////////////////////////////////// + // // Verify resultset using ResultSetMetaData + // /////////////////////////////////////////////////////////////////// + // @Test + // public void testResultSet() throws SQLException { + // + // try { + // stmt = conn().createStatement(); + // // SELECT * FROM ORDER BY + // String pk = Tables.primaryKey(); + // String query = Tables.select_Orderby(table2, pk); + // rs = stmt.executeQuery(query); + // bvt_rs = new bvt_ResultSet(rs); + // + // // verify resultSet + // bvt_rs.verify(); + // } + // finally { + // terminateVariation(); + // } + // } + // + // /////////////////////////////////////////////////////////////////// + // // Verify resultset and close resultSet + // /////////////////////////////////////////////////////////////////// + // @Test + // public void testResultSetAndClose() throws SQLException { + // + // try { + // stmt = conn().createStatement(); + // + // // SELECT * FROM ORDER BY + // String pk = Tables.primaryKey(); + // String query = Tables.select_Orderby(table2, pk); + // rs = stmt.executeQuery(query); + // } + // finally { + // terminateVariation(); + // } + // } + // + // /////////////////////////////////////////////////////////////////// + // // Verify two concurrent resultsets from same connection, + // // separate statements + // /////////////////////////////////////////////////////////////////// + // @Test + // public void testTwoResultsetsDifferentStmt() throws SQLException { + // + // Statement stmt1 = null; + // Statement stmt2 = null; + // ResultSet rs1 = null; + // ResultSet rs2 = null; + // bvt_ResultSet bvt_rs1 = null; + // bvt_ResultSet bvt_rs2 = null; + // try { + // stmt1 = conn().createStatement(); + // stmt2 = conn().createStatement(); + // + // // SELECT * FROM ORDER BY + // String pk = Tables.primaryKey(); + // String query = Tables.select_Orderby(table2, pk); + // rs1 = stmt1.executeQuery(query); + // + // String query2 = Tables.select_Orderby(table1, pk); + // rs2 = stmt2.executeQuery(query2); + // bvt_rs1 = new bvt_ResultSet(rs1); + // bvt_rs2 = new bvt_ResultSet(rs2); + // + // // Interleave resultset calls + // bvt_rs1.next(); + // bvt_rs1.verifyCurrentRow(); + // bvt_rs2.next(); + // bvt_rs2.verifyCurrentRow(); + // bvt_rs1.next(); + // bvt_rs1.verifyCurrentRow(); + // bvt_rs1.verify(); + // bvt_rs1.close(); + // bvt_rs2.next(); + // bvt_rs2.verify(); + // } + // finally { + // if (null != bvt_rs2) { + // bvt_rs2.close(); + // } + // if (null != rs1) { + // rs1.close(); + // } + // if (null != rs2) { + // rs2.close(); + // } + // if (null != stmt1) { + // stmt1.close(); + // } + // if (null != stmt2) { + // stmt2.close(); + // } + // terminateVariation(); + // } + // } + // + // /////////////////////////////////////////////////////////////////// + // // Verify two concurrent resultsets from same connection, + // // same statement + // /////////////////////////////////////////////////////////////////// + // @Test + // public void testTwoResultsetsSameStmt() throws SQLException { + // + // ResultSet rs1 = null; + // ResultSet rs2 = null; + // try { + // stmt = conn().createStatement(); + // + // // SELECT * FROM ORDER BY + // String pk = Tables.primaryKey(); + // String query = Tables.select_Orderby(table2, pk); + // rs1 = stmt.executeQuery(query); + // + // // SELECT * FROM ORDER BY + // String query2 = Tables.select_Orderby(table1, pk); + // rs2 = stmt.executeQuery(query2); + // + // bvt_ResultSet bvt_rs1 = new bvt_ResultSet(rs1); + // bvt_ResultSet bvt_rs2 = new bvt_ResultSet(rs2); + // + // // Interleave resultset calls. rs is expected to be closed + // try { + // bvt_rs1.next(); + // } + // catch (SQLException e) { + // assertEquals(e.toString(), "com.microsoft.sqlserver.jdbc.SQLServerException: The result set is closed."); + // } + // bvt_rs2.next(); + // bvt_rs2.verifyCurrentRow(); + // try { + // bvt_rs1.next(); + // } + // catch (SQLException e) { + // assertEquals(e.toString(), "com.microsoft.sqlserver.jdbc.SQLServerException: The result set is closed."); + // } + // bvt_rs1.close(); + // bvt_rs2.next(); + // bvt_rs2.verify(); + // } + // finally { + // if (null != rs1) { + // rs1.close(); + // } + // if (null != rs2) { + // rs2.close(); + // } + // terminateVariation(); + // } + // } + // + // /////////////////////////////////////////////////////////////////// + // // Verify resultset closed after statement is closed + // /////////////////////////////////////////////////////////////////// + // @Test + // public void testResultSetAndCloseStmt() throws SQLException { + // try { + // stmt = conn().createStatement(); + // + // // SELECT * FROM ORDER BY + // String pk = Tables.primaryKey(); + // String query = Tables.select_Orderby(table2, pk); + // rs = stmt.executeQuery(query); + // bvt_rs = new bvt_ResultSet(rs); + // + // // close statement and verify resultSet + // stmt.close(); // this should close the resultSet + // try { + // bvt_rs.next(); + // } + // catch (SQLException e) { + // assertEquals(e.toString(), "com.microsoft.sqlserver.jdbc.SQLServerException: The result set is closed."); + // } + // } + // finally { + // terminateVariation(); + // } + // } + // + // /////////////////////////////////////////////////////////////////// + // // Verify resultset using SelectMethod + // /////////////////////////////////////////////////////////////////// + // @Test + // public void testResultSetSelectMethod() throws SQLException { + // + // // guarantees selectMethod=cursor + // cursor = true; + // try { + // stmt = conn().createStatement(); + // + // // SELECT * FROM ORDER BY + // String pk = Tables.primaryKey(); + // String query = Tables.select_Orderby(table2, pk); + // rs = stmt.executeQuery(query); + // bvt_rs = new bvt_ResultSet(rs); + // + // // verify resultSet + // bvt_rs.verify(); + // cursor = false; + // } + // finally { + // terminateVariation(); + // } + // } + + @AfterClass + public static void terminate() throws SQLException { + + try { + stmt = conn.createStatement(); + // stmt.executeUpdate(Tables.dropTable(table2)); + // stmt.executeUpdate(Tables.dropTable(table1)); + } + finally { + terminateVariation(); + } + } + + // public static String getConnectionURL() { + // connectionUrl = System.getenv("mssql_jdbc_test_connection_properties"); + // + // if (null == connectionUrl) { + // fail("Please setup environment variable mssql_jdbc_test_connection_properties"); + // } + // + // if (cursor) { + // connectionUrl += ";selectMethod=cursor;"; + // } + // + // if (querytimeout) { + // connectionUrl += ";queryTimeout=10"; + // } + // + // return connectionUrl; + // } + // + // public static Connection conn() { + // + // connectionUrl = getConnectionURL(); + // // Establish the connection. + // try { + // + // Connection con = DriverManager.getConnection(connectionUrl); + // return con; + // // Handle any errors that may have occurred. + // } + // catch (SQLException e) { + // fail("Please make sure the environment variable mssql_jdbc_test_connection_properties is set with correct connection properties.\n" + // + e.toString()); + // } + // return null; + // } + + public static void terminateVariation() throws SQLException { + if (conn != null && !conn.isClosed()) { + try { + conn.close(); + } + finally { + if (null != bvt_rs) + bvt_rs.close(); + if (null != rs) + rs.close(); + if (null != stmt) + stmt.close(); + if (null != pstmt) + pstmt.close(); + } + } + } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTestSetup.java b/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTestSetup.java new file mode 100644 index 000000000..6a3c91072 --- /dev/null +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTestSetup.java @@ -0,0 +1,73 @@ +/** + * + */ +package com.microsoft.sqlserver.jdbc.bvt; + +import java.sql.SQLException; + +import org.junit.BeforeClass; +import org.junit.jupiter.api.BeforeAll; +import org.junit.platform.runner.JUnitPlatform; +import org.junit.runner.RunWith; + +import com.microsoft.sqlserver.testframework.AbstractTest; +import com.microsoft.sqlserver.testframework.DBConnection; +import com.microsoft.sqlserver.testframework.DBStatement; +import com.microsoft.sqlserver.testframework.DBTable; + +/** + * @author v-afrafi + * + */ +@RunWith(JUnitPlatform.class) +public class bvtTestSetup extends AbstractTest { + private static DBConnection conn = null; + private static DBStatement stmt = null; + + static DBTable table1; + static DBTable table2; + @BeforeAll + public static void init() throws SQLException { + // try { + // Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); + // } + // catch (ClassNotFoundException e) { + // e.printStackTrace(); + // } + + // Statement stmt = null; + try { + // stmt = conn().createStatement(); + conn = new DBConnection(connectionString); + stmt = conn.createStatement(); + + // create tables + table1 = new DBTable(true); + stmt.createTable(table1); + stmt.populateTable(table1); + table2 = new DBTable(true); + stmt.createTable(table2); + stmt.populateTable(table2); + + + // // CREATE the table + // stmt.executeUpdate(Tables.dropTable(table1)); + // stmt.executeUpdate(Tables.createTable(table1)); + // // CREATE the data to populate the table with + // Values.createData(); + // Tables.populate(table1, stmt); + // + // stmt.executeUpdate(Tables.dropTable(table2)); + // stmt.executeUpdate(Tables.createTable(table2)); + // Tables.populate(table2, stmt); + } + finally { + if (null != stmt) { + stmt.close(); + } +// terminateVariation(); + } + } + + +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBColumn.java b/src/test/java/com/microsoft/sqlserver/testframework/DBColumn.java index 4228564ac..a0becc965 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBColumn.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBColumn.java @@ -88,7 +88,7 @@ void setSqlType(SqlType sqlType) { void populateValues(int rows) { columnValues = new ArrayList(); for (int i = 0; i < rows; i++) - columnValues.add(sqlType.createdata()); + columnValues.add(sqlType.createdata()); } /** diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBConnection.java b/src/test/java/com/microsoft/sqlserver/testframework/DBConnection.java index 35b4a4d2a..2268644c2 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBConnection.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBConnection.java @@ -28,8 +28,10 @@ import static org.junit.jupiter.api.Assertions.fail; import java.sql.Connection; +import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; +import java.sql.Statement; import com.microsoft.sqlserver.jdbc.SQLServerConnection; @@ -38,59 +40,83 @@ */ public class DBConnection extends AbstractParentWrapper { - // TODO: add Isolation Level - // TODO: add auto commit - // TODO: add connection Savepoint and rollback - // TODO: add additional connection properties - // TODO: add DataSource support - private SQLServerConnection connection = null; - - /** - * establishes connection using the input - * - * @param connectionString - */ - public DBConnection(String connectionString) { - super(null, null, "connection"); - getConnection(connectionString); - } - - /** - * establish connection - * - * @param connectionString - */ - void getConnection(String connectionString) { - try { - connection = PrepUtil.getConnection(connectionString); - setInternal(connection); - } catch (SQLException ex) { - fail(ex.getMessage()); - } catch (ClassNotFoundException ex) { - fail(ex.getMessage()); - } - } - - @Override - void setInternal(Object internal) { - this.internal = internal; - } - - /** - * - * @return Statement wrapper - */ - public DBStatement createStatement() { - try { - DBStatement dbstatement = new DBStatement(this); - return dbstatement.createStatement(); - } catch (SQLException ex) { - fail(ex.getMessage()); - } - return null; - } + // TODO: add Isolation Level + // TODO: add auto commit + // TODO: add connection Savepoint and rollback + // TODO: add additional connection properties + // TODO: add DataSource support + private SQLServerConnection connection = null; + private boolean _closed = false; + private boolean _closeCalled = false; + public int _holdability = ResultSet.HOLD_CURSORS_OVER_COMMIT; + /** + * establishes connection using the input + * + * @param connectionString + */ + public DBConnection(String connectionString) { + super(null, null, "connection"); + getConnection(connectionString); + } + + /** + * establish connection + * + * @param connectionString + */ + void getConnection(String connectionString) { + try { + connection = PrepUtil.getConnection(connectionString); + setInternal(connection); + } + catch (SQLException ex) { + fail(ex.getMessage()); + } + catch (ClassNotFoundException ex) { + fail(ex.getMessage()); + } + } + + @Override + void setInternal(Object internal) { + this.internal = internal; + } + + /** + * + * @return Statement wrapper + */ + public DBStatement createStatement() { + try { + DBStatement dbstatement = new DBStatement(this); + return dbstatement.createStatement(); + } + catch (SQLException ex) { + fail(ex.getMessage()); + } + return null; + } + + /** + * + * @param type + * @param concurrency + * @return + * @throws SQLException + */ + public DBStatement createStatement(int type, int concurrency) throws SQLException { + Statement product = ((Connection) product()).createStatement(type, concurrency); + DBStatement wrapper = new DBStatement(this, product, type, concurrency, _holdability); + + // State + wrapper._cursortype = type; + wrapper._concurrency = concurrency; + + return wrapper; + } + /** * clsoe connection */ @@ -103,19 +129,46 @@ public void close() { } } + /** + * checks if the connection is closed. + * + * @return true if connection is closed. + * @throws SQLException + */ + public boolean isClosed() { + boolean current = false; + try { + current = connection.isClosed(); + } + catch (SQLException ex) { + fail(ex.getMessage()); + } + return current; + } - public static boolean isSqlAzure(Connection con) throws SQLException { - boolean isSqlAzure = false; + /** + * Retrieves metaData + * + * @return + * @throws SQLException + */ + public DatabaseMetaData getMetaData() throws SQLException { + DatabaseMetaData product = connection.getMetaData(); + return product; + } - ResultSet rs = con.createStatement().executeQuery("SELECT CAST(SERVERPROPERTY('EngineEdition') as INT)"); - rs.next(); - int engineEdition = rs.getInt(1); - rs.close(); - if (ENGINE_EDITION_FOR_SQL_AZURE == engineEdition) { - isSqlAzure = true; - } + public static boolean isSqlAzure(Connection con) throws SQLException { + boolean isSqlAzure = false; - return isSqlAzure; - } + ResultSet rs = con.createStatement().executeQuery("SELECT CAST(SERVERPROPERTY('EngineEdition') as INT)"); + rs.next(); + int engineEdition = rs.getInt(1); + rs.close(); + if (ENGINE_EDITION_FOR_SQL_AZURE == engineEdition) { + isSqlAzure = true; + } + + return isSqlAzure; + } } diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java index 04b069b04..6a8e791a6 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java @@ -25,8 +25,14 @@ package com.microsoft.sqlserver.testframework; +import java.math.BigDecimal; import java.sql.ResultSet; +import java.sql.ResultSetMetaData; import java.sql.SQLException; +import java.util.ArrayList; + + +import static org.junit.jupiter.api.Assertions.fail; /** * wrapper class for ResultSet @@ -39,6 +45,10 @@ public class DBResultSet extends AbstractParentWrapper { // TODO: add cursors // TODO: add resultSet level holdability // TODO: add concurrency control + public DBTable currentTable; + public static final int VERIFY_MOVERS_NEXT = 0x100; + public int _currentrow = 0; // The row this rowset is currently pointing to + ResultSet resultSet = null; DBResultSet(DBStatement dbstatement, ResultSet internal) { @@ -63,6 +73,8 @@ public void close() throws SQLException { * @throws SQLException */ public boolean next() throws SQLException { +// if(_currentrow < DBTa) + _currentrow++; return resultSet.next(); } @@ -85,4 +97,173 @@ public Object getObject(int index) throws SQLException { public void updateObject(int index) throws SQLException { // TODO: update object based on cursor type } + + /** + * + * @throws SQLException + */ + public void verify(DBTable table) throws SQLException { + currentTable = table; + DBResultSetMetaData metaData = this.getMetaData(); + metaData.verify(); + + while (this.next()) + this.verifyCurrentRow(); + } + + /** + * @throws SQLException + * + */ + public void verifyCurrentRow() throws SQLException{ + int size = ((ResultSet) product()).getMetaData().getColumnCount(); + + Class _class = Object.class; + for ( int i=0; i< size; i++) + verifydata(i, _class, null); + + } + + public void verifydata(int ordinal, Class coercion, Object arg) throws SQLException + { + Object backendData = this.currentrow().get(ordinal); + + //getXXX - default mapping + Object retrieved = this.getXXX(ordinal +1 , coercion); + + //Verify + verifydata(ordinal, coercion, backendData, retrieved); + } + + public void verifydata(int ordinal, Class coercion, Object backendData, Object retrieved) throws SQLException + { + + if (backendData != null) { + if (retrieved instanceof BigDecimal) { + if (((BigDecimal) retrieved).compareTo(new BigDecimal("" + backendData)) != 0) + fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved + + " , inserted value is " + backendData); + + } else if (retrieved instanceof Float) { + if (Float.compare(new Float("" + backendData), (float) retrieved) != 0) + fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved + + " ,inserted value is " + backendData); + } else if (retrieved instanceof Double) { + if (Double.compare(new Double("" + backendData), (double) retrieved) != 0) + fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved + + " , inserted value is " + backendData); + } else if (retrieved instanceof byte[]) { + if (!parseByte((byte[]) retrieved).contains("" + backendData)) + fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved + + " , inserted value is " + backendData); + } else if (retrieved instanceof String) { + if (!(((String) retrieved).trim()).equalsIgnoreCase(((String) backendData).trim())) + fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved + + " , inserted value is " + backendData); + } else if (retrieved instanceof Boolean) { + if ( retrieved.equals(true) && !backendData.equals(1)) + { + fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved + + " , inserted value is " + backendData); + } + else if ( retrieved.equals(false) && !backendData.equals(0)) + { + fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved + + " , inserted value is " + backendData); + } + } else if (!(("" + retrieved).equalsIgnoreCase("" + backendData))) + fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved + " , inserted value is " + + backendData); + } + // if data is null + else { + if (retrieved != backendData) + fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved + " , inserted value is " + + backendData); + } + + } + + + public ArrayList currentrow(){ + return currentTable.getAllRows().get(_currentrow -1); + } + + private Object getXXX(int idx, Class coercion) throws SQLException { + if (coercion == Object.class) { + return this.getObject(idx); + } + return null; + } + + /** + * + * @return + */ + public DBResultSetMetaData getMetaData() { + ResultSetMetaData product = null; + DBResultSetMetaData wrapper = null; + try { + product = resultSet.getMetaData(); + wrapper = new DBResultSetMetaData(parent, product, name); + } + catch (SQLException e) { + fail(e.getMessage()); + } + + return wrapper; + } + + /** + * + * @return + * @throws SQLException + */ + public int getRow() throws SQLException + { + int product = ((ResultSet) product()).getRow(); + return product; + } + + /** + * + * @return + * @throws SQLException + */ + public boolean previous() throws SQLException + { + + boolean validrow = ((ResultSet) product()).previous(); + + if (_currentrow > 0) + { + _currentrow--; + } + return (validrow); + } + + /** + * + * @throws SQLException + */ + public void afterLast() throws SQLException + { + ((ResultSet) product()).afterLast(); + _currentrow = DBTable.getTotalRows() + 1; + } + + public boolean absolute(int x) throws SQLException + { + boolean validrow = ((ResultSet) product()).absolute(x); + return validrow; + } + + private static String parseByte(byte[] bytes) { + StringBuffer parsedByte = new StringBuffer(); + parsedByte.append("0x"); + for (byte b : bytes) { + parsedByte.append(String.format("%02X", b)); + } + return parsedByte.toString(); + } } diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetMetaData.java b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetMetaData.java new file mode 100644 index 000000000..c51f7843f --- /dev/null +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetMetaData.java @@ -0,0 +1,108 @@ +/** + * + */ +package com.microsoft.sqlserver.testframework; + +import java.sql.ResultSet; +import com.microsoft.sqlserver.jdbc.SQLServerResultSetMetaData; +import java.sql.SQLException; +import static org.junit.Assert.fail; + + +/** + * @author v-afrafi + * + */ +public class DBResultSetMetaData extends AbstractParentWrapper { + + /** + * @param parent + * @param internal + * @param name + */ + DBResultSetMetaData(AbstractParentWrapper parent, Object internal, String name) { + super(parent, internal, name); + // TODO Auto-generated constructor stub + } + + public void verify() throws SQLException { + // getColumnCount + int columns = this.getColumnCount(); + + // Loop through the columns + for (int i = 1; i <= columns; i++) { + // Note: Just calling these performs the verification, in each method + this.getColumnName(i); + this.getColumnType(i); + this.getColumnTypeName(i); + this.getScale(i); + this.isCaseSensitive(i); + this.isAutoIncrement(i); + this.isCurrency(i); + this.isNullable(i); + this.isSigned(i); + + } + } + + public int getColumnCount() throws SQLException { + int current = 0; + try { + current = ( (SQLServerResultSetMetaData) product()).getColumnCount(); + } + catch (SQLException e) { + fail(e.toString()); + } + return current; + } + + public String getColumnName(int index) throws SQLException { + String current = ( (SQLServerResultSetMetaData) product()).getColumnName(index); + return current; + } + + public int getColumnType(int index) throws SQLException { + int current = ( (SQLServerResultSetMetaData) product()).getColumnType(index); + return current; + } + + public String getColumnTypeName(int index) throws SQLException { + String current = ( (SQLServerResultSetMetaData) product()).getColumnTypeName(index); + return current; + } + + public int getPrecision(int x) throws SQLException { + int current = ( (SQLServerResultSetMetaData) product()).getPrecision(x); + return current; + } + + public int getScale(int x) throws SQLException { + int current = ( (SQLServerResultSetMetaData) product()).getScale(x); + return current; + } + + public boolean isCaseSensitive(int x) throws SQLException { + boolean current = ( (SQLServerResultSetMetaData) product()).isCaseSensitive(x); + return current; + } + + public boolean isCurrency(int x) throws SQLException { + boolean current = ( (SQLServerResultSetMetaData) product()).isCurrency(x); + return current; + } + + public boolean isAutoIncrement(int x) throws SQLException { + boolean current = ( (SQLServerResultSetMetaData) product()).isAutoIncrement(x); + return current; + } + + public int isNullable(int x) throws SQLException { + int current = ( (SQLServerResultSetMetaData) product()).isNullable(x); + return current; + } + + public boolean isSigned(int x) throws SQLException { + boolean current = ( (SQLServerResultSetMetaData) product()).isSigned(x); + return current; + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBStatement.java b/src/test/java/com/microsoft/sqlserver/testframework/DBStatement.java index 199ddd8f2..fdc3c5d6f 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBStatement.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBStatement.java @@ -46,10 +46,17 @@ public class DBStatement extends AbstractParentWrapper { Statement statement = null; DBResultSet dbresultSet = null; - + public int _cursortype = ResultSet.TYPE_FORWARD_ONLY; + public int _concurrency = ResultSet.CONCUR_READ_ONLY; + public int _holdability = ResultSet.CLOSE_CURSORS_AT_COMMIT; + DBStatement(DBConnection dbConnection) { super(dbConnection, null, "statement"); } + + DBStatement(DBConnection parent, Statement internal, int type, int concurrency, int holdability) { + super(parent, null, "statement"); + } DBStatement statement() { return this; @@ -134,4 +141,15 @@ public boolean dropTable(DBTable table) { void setInternal(Object internal) { this.internal = internal; } + + /** + * + * @return + * @throws SQLException + */ + public int getQueryTimeout() throws SQLException + { + int current = ((Statement) product()).getQueryTimeout(); + return current; + } } diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java b/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java index e93a83af4..53dc441f7 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java @@ -49,15 +49,15 @@ public class DBTable extends AbstractSQLGenerator { String escapedTableName; List columns; int totalColumns; - int totalRows = 2; // default row count set to 2 + static int totalRows = 2; // default row count set to 2 DBSchema schema; - + ArrayList> rows; + ArrayList currentrow; /** * Initializes {@link DBTable} with tableName, schema, and {@link DBColumns} * * @param autoGenerateSchema - * true : generates schema with all available - * dataTypes in SqlType class + * true : generates schema with all available dataTypes in SqlType class */ public DBTable(boolean autoGenerateSchema) { @@ -68,14 +68,15 @@ public DBTable(boolean autoGenerateSchema) { addColumns(); } else { - this.columns = new ArrayList(); + this.columns = new ArrayList(); } this.totalColumns = columns.size(); + this.currentrow = new ArrayList(); + this.rows = new ArrayList>(); } /** - * Similar to {@link DBTable#DBTable(boolean)}, but uses existing list of - * columns Used internally to clone schema + * Similar to {@link DBTable#DBTable(boolean)}, but uses existing list of columns Used internally to clone schema * * @param DBTable */ @@ -123,7 +124,7 @@ public String getEscapedTableName() { * * @return total rows in the table */ - public int getTotalRows() { + public static int getTotalRows() { return totalRows; } @@ -251,22 +252,27 @@ String populateTableSql() { for (int colNum = 0; colNum < totalColumns; colNum++) { // TODO: add betterway to enclose data - if (JDBCType.CHAR == getColumn(colNum).getSqlType().getJdbctype() - || JDBCType.VARCHAR == getColumn(colNum).getSqlType().getJdbctype() + if (JDBCType.CHAR == getColumn(colNum).getSqlType().getJdbctype() || JDBCType.VARCHAR == getColumn(colNum).getSqlType().getJdbctype() || JDBCType.NCHAR == getColumn(colNum).getSqlType().getJdbctype() || JDBCType.NVARCHAR == getColumn(colNum).getSqlType().getJdbctype() || JDBCType.TIMESTAMP == getColumn(colNum).getSqlType().getJdbctype() || JDBCType.DATE == getColumn(colNum).getSqlType().getJdbctype() - || JDBCType.TIME == getColumn(colNum).getSqlType().getJdbctype()) + || JDBCType.TIME == getColumn(colNum).getSqlType().getJdbctype()) { sb.add("'" + String.valueOf(getColumn(colNum).getRowValue(i)) + "'"); - else + currentrow.add(getColumn(colNum).getRowValue(i)); + } + else { sb.add(String.valueOf(getColumn(colNum).getRowValue(i))); + currentrow.add(getColumn(colNum).getRowValue(i)); + } if (colNum < totalColumns - 1) { sb.add(COMMA); } } - sb.add(CLOSE_BRACKET); + sb.add(CLOSE_BRACKET); + rows.add(currentrow); + currentrow = new ArrayList(); } return (sb.toString()); @@ -333,4 +339,9 @@ public void addColumn(SqlType sqlType) { DBColumn getColumn(int index) { return columns.get(index); } + + public ArrayList> getAllRows() { + return rows; + } + } From 5809103fec99ef52941039378167f3b0dee9f41b Mon Sep 17 00:00:00 2001 From: v-xiangs Date: Fri, 13 Jan 2017 12:22:51 -0800 Subject: [PATCH 02/28] clean rounding --- src/main/java/com/microsoft/sqlserver/jdbc/DDC.java | 2 +- src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/DDC.java b/src/main/java/com/microsoft/sqlserver/jdbc/DDC.java index 43df0490e..6e7b167c0 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/DDC.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/DDC.java @@ -412,7 +412,7 @@ private static byte[] convertToBytes(BigDecimal value, int scale, int numBytes) { boolean isNeg = value.signum() < 0; - value = value.setScale(scale, RoundingMode.DOWN); + value = value.setScale(scale); BigInteger bigInt = value.unscaledValue(); diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java b/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java index f86017041..9da033093 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java @@ -4926,7 +4926,7 @@ void writeTVPRows(TVP value) throws SQLServerException BigDecimal bdValue = new BigDecimal(currentColumnStringValue); // setScale of all BigDecimal value based on metadata sent - bdValue = bdValue.setScale(columnPair.getValue().scale, RoundingMode.HALF_UP); + bdValue = bdValue.setScale(columnPair.getValue().scale); byte[] valueBytes = DDC.convertBigDecimalToBytes(bdValue, bdValue.scale()); // 1-byte for sign and 16-byte for integer From 9d0c483210efde7f18fe6c0a2b064f79075a2854 Mon Sep 17 00:00:00 2001 From: v-afrafi Date: Fri, 13 Jan 2017 17:32:29 -0800 Subject: [PATCH 03/28] bvt and testframework updates --- .../microsoft/sqlserver/jdbc/bvt/bvtTest.java | 962 ++++++++---------- .../sqlserver/testframework/DBConnection.java | 28 +- .../testframework/DBPreparedStatement.java | 78 ++ .../sqlserver/testframework/DBResultSet.java | 307 +++++- .../testframework/DBResultSetMetaData.java | 127 ++- .../sqlserver/testframework/DBStatement.java | 7 + .../sqlserver/testframework/DBTable.java | 18 +- .../testframework/sqlType/SqlChar.java | 19 +- 8 files changed, 894 insertions(+), 652 deletions(-) create mode 100644 src/test/java/com/microsoft/sqlserver/testframework/DBPreparedStatement.java diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTest.java index d85b0c51f..a510f2e37 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTest.java @@ -10,6 +10,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import java.math.BigDecimal; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.ResultSet; @@ -28,6 +29,7 @@ import com.microsoft.sqlserver.jdbc.bvt.bvt_ResultSet; import com.microsoft.sqlserver.testframework.AbstractTest; import com.microsoft.sqlserver.testframework.DBConnection; +import com.microsoft.sqlserver.testframework.DBPreparedStatement; import com.microsoft.sqlserver.testframework.DBResultSet; import com.microsoft.sqlserver.testframework.DBStatement; import com.microsoft.sqlserver.testframework.DBTable; @@ -35,63 +37,12 @@ @RunWith(JUnitPlatform.class) @DisplayName("BVT Test") public class bvtTest extends bvtTestSetup { - private static boolean cursor = false; - private static boolean querytimeout = false; - // private static String connectionUrl = ""; - private static Connection con; private static String driverNamePattern = "Microsoft JDBC Driver \\d.\\d for SQL Server"; - // private static String table1 = "stmt_test_bvt"; - // private static String table2 = "rs_test_bvt"; - // private static Statement stmt = null; private static DBResultSet rs = null; - private static SQLServerPreparedStatement pstmt = null; - private static bvt_ResultSet bvt_rs = null; + private static DBPreparedStatement pstmt = null; private static DBConnection conn = null; private static DBStatement stmt = null; -// private static DBTable table1 = null; -// private static DBTable table2 = null; - -// @BeforeClass -// public static void init() throws SQLException { -// // try { -// // Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); -// // } -// // catch (ClassNotFoundException e) { -// // e.printStackTrace(); -// // } -// -// // Statement stmt = null; -// try { -// // stmt = conn().createStatement(); -// conn = new DBConnection(connectionString); -// stmt = conn.createStatement(); -// -// // create tables -// table1 = new DBTable(true); -// stmt.createTable(table1); -// table2 = new DBTable(true); -// stmt.createTable(table2); -// -// // // CREATE the table -// // stmt.executeUpdate(Tables.dropTable(table1)); -// // stmt.executeUpdate(Tables.createTable(table1)); -// // // CREATE the data to populate the table with -// // Values.createData(); -// // Tables.populate(table1, stmt); -// // -// // stmt.executeUpdate(Tables.dropTable(table2)); -// // stmt.executeUpdate(Tables.createTable(table2)); -// // Tables.populate(table2, stmt); -// } -// finally { -// if (null != stmt) { -// stmt.close(); -// } -// terminateVariation(); -// } -// } - /////////////////////////////////////////////////////////////////// //// Connect to specified server and close the connection ///////////////////////////////////////////////////////////////////// @@ -156,12 +107,6 @@ public void testCreateStatement() throws SQLException { String query = "SELECT * FROM " + table1.getEscapedTableName() + ";"; rs = stmt.executeQuery(query); rs.verify(table1); - // bvt_rs = new bvt_ResultSet(rs); - - // close and verify - - // bvt_rs.verify(); - } finally { @@ -178,75 +123,52 @@ public void testCreateStatement() throws SQLException { @Test public void testCreateStatementWithQueryTimeout() throws SQLException { - querytimeout = true; - try { - conn = new DBConnection(connectionString); + conn = new DBConnection(connectionString + ";querytimeout=10"); stmt = conn.createStatement(); assertEquals(10, stmt.getQueryTimeout()); } finally { terminateVariation(); - querytimeout = false; + + } + } + + /////////////////////////////////////////////////////////////////// + // Create a statement + // ResultSet.Type_forward_only, + // ResultSet.CONCUR_READ_ONLY, executeQuery + // verify cursor by using next and previous and verify data + /////////////////////////////////////////////////////////////////// + @Test + public void testStmtForwardOnlyReadOnly() throws SQLException, ClassNotFoundException { + + try { + conn = new DBConnection(connectionString); + stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + + String query = "SELECT * FROM " + table1.getEscapedTableName(); + rs = stmt.executeQuery(query); + + rs.next(); + rs.verifyCurrentRow(table1); + rs.next(); + rs.verifyCurrentRow(table1); + + try { + rs.previous(); + assertTrue("Previous should have thrown an exception", false); + } + catch (SQLException ex) { + // expected exception + } + rs.verify(table1); + } + finally { + terminateVariation(); } } - // - // /////////////////////////////////////////////////////////////////// - // // Create a statement - // // ResultSet.Type_forward_only, - // // ResultSet.CONCUR_READ_ONLY, executeQuery - // // verify cursor by using next and previous and verify data - // /////////////////////////////////////////////////////////////////// - // @Test - // public void testStmtForwardOnlyReadOnly() throws SQLException, ClassNotFoundException { - // - // try { - // stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); - // - // // SELECT * FROM ORDER BY - // String query = "SELECT * FROM "+ table1.getEscapedTableName(); - // rs = stmt.executeQuery(query); - // - // - // rs.next(); - // rs.verifyCurrentRow(table1); - // rs.next(); - // rs.verifyCurrentRow(); - // - // try{ - // rs.previous(); - // assertTrue("Previous should have thrown an exception", false); - // } - // catch (SQLException ex) { - // // expected exception - // } - // rs.verify(); - // } - // finally { - // terminateVariation(); - // } - // - //// bvt_rs = new bvt_ResultSet(rs); - //// // Verify resultset behavior - //// bvt_rs.next(); - //// bvt_rs.verifyCurrentRow(); - //// bvt_rs.next(); - //// bvt_rs.verifyCurrentRow(); - //// try { - //// bvt_rs.previous(); - //// assertTrue("Previous should have thrown an exception", false); - //// } - //// catch (SQLException ex) { - //// // expected exception - //// } - //// bvt_rs.verify(); - //// } - //// finally { - //// terminateVariation(); - //// } - // } - // /////////////////////////////////////////////////////////////////// // Create a statement // ResultSet.SCROLL_INSENSITIVE, @@ -256,39 +178,23 @@ public void testCreateStatementWithQueryTimeout() throws SQLException { @Test public void testStmtScrollInsensitiveReadOnly() throws SQLException, ClassNotFoundException { try { + conn = new DBConnection(connectionString); stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); - // SELECT * FROM ORDER BY , -// String c1 = Tables.primaryKey(); -// String c2 = "[c1_char(512)]"; -// -// Tables.select(table1); -// Tables.orderby(c1); -// Tables.orderby(c2); - String query = "SELECT * FROM" + table1.getEscapedTableName(); -// rs = stmt.executeQuery(Tables.query); rs = stmt.executeQuery(query); rs.next(); - rs.verifyCurrentRow(); + rs.verifyCurrentRow(table1); rs.afterLast(); - rs.verifyCurrentRow(); + rs.previous(); + rs.verifyCurrentRow(table1); rs.verify(table1); -// bvt_rs = new bvt_ResultSet(rs); - - // Verify resultset behavior -// bvt_rs.next(); -// bvt_rs.verifyCurrentRow(); -// bvt_rs.afterLast(); -// bvt_rs.previous(); -// bvt_rs.verifyCurrentRow(); -// bvt_rs.verify(); } finally { terminateVariation(); } } - // + // ///////////////////////////////////////////////////////////////// // // Create a statement // // ResultSet.SCROLL_SENSITIVE, @@ -299,467 +205,399 @@ public void testStmtScrollInsensitiveReadOnly() throws SQLException, ClassNotFou public void testStmtScrollSensitiveReadOnly() throws SQLException { try { + conn = new DBConnection(connectionString); stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); + String query = "SELECT * FROM " + table1.getEscapedTableName(); + rs = stmt.executeQuery(query); + rs.next(); + rs.next(); + rs.verifyCurrentRow(table1); + rs.absolute(3); + rs.verifyCurrentRow(table1); + rs.absolute(1); + rs.verify(table1); + + } + finally { + terminateVariation(); + } + } + + /////////////////////////////////////////////////////////////////// + // Create a statement + // ResultSet.Type_forward_only, + // ResultSet.CONCUR_UPDATABLE, executeQuery + // verify cursor by using next and previous and verify data + /////////////////////////////////////////////////////////////////// + @Test + public void testStmtForwardOnlyUpdateable() throws SQLException { + + try { + conn = new DBConnection(connectionString); + stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); + + String query = "SELECT * FROM " + table1.getEscapedTableName(); + rs = stmt.executeQuery(query); + rs.next(); + + // Verify resultset behavior + rs.next(); + rs.verifyCurrentRow(table1); + rs.next(); + rs.verifyCurrentRow(table1); + try { + rs.previous(); + assertTrue("Previous should have thrown an exception", false); + } + catch (SQLException ex) { + // expected exception + } + rs.verify(table1); + } + finally { + terminateVariation(); + } + } + + /////////////////////////////////////////////////////////////////// + // Create a statement + // ResultSet.SCROLL_SENSITIVE, + // ResultSet.CONCUR_UPDATABLE, executeQuery + // verify cursor by using next and previous and verify data + /////////////////////////////////////////////////////////////////// + @Test + public void testStmtScrollSensitiveUpdatable() throws SQLException { + + try { + conn = new DBConnection(connectionString); + stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); + // SELECT * FROM ORDER BY -// String pk = Tables.primaryKey(); -// String query = Tables.select_Orderby(table1, pk); - String query = "SELECT * FROM "+ table1.getEscapedTableName(); + // DBResultSet.currentTable = table1; + String query = "SELECT * FROM " + table1.getEscapedTableName(); rs = stmt.executeQuery(query); + // bvt_rs = new bvt_ResultSet(rs); + + // Verify resultset behavior rs.next(); rs.next(); - rs.verifyCurrentRow(); + rs.verifyCurrentRow(table1); rs.absolute(3); - rs.verifyCurrentRow(); + rs.verifyCurrentRow(table1); rs.absolute(1); rs.verify(table1); -// bvt_rs = new bvt_ResultSet(rs); + } + finally { + terminateVariation(); + } + } + + /////////////////////////////////////////////////////////////////// + // Create a statement + // TYPE_SS_SCROLL_DYNAMIC, + // CONCUR_SS_OPTIMISTIC_CC, executeQuery + // verify cursor by using next and previous and verify data + /////////////////////////////////////////////////////////////////// + @Test + public void testStmtSS_ScrollDynamicOptimistic_CC() throws SQLException { + + try { + int TYPE_SS_SCROLL_DYNAMIC = 1006; + int CONCUR_SS_OPTIMISTIC_CC = 1008; + conn = new DBConnection(connectionString); + stmt = conn.createStatement(TYPE_SS_SCROLL_DYNAMIC, CONCUR_SS_OPTIMISTIC_CC); + + String query = "SELECT * FROM " + table1.getEscapedTableName(); + rs = stmt.executeQuery(query); // Verify resultset behavior -// bvt_rs.next(); -// bvt_rs.next(); -// bvt_rs.verifyCurrentRow(); -// bvt_rs.absolute(3); -// bvt_rs.verifyCurrentRow(); -// bvt_rs.absolute(1); -// bvt_rs.verify(); + rs.next(); + rs.afterLast(); + rs.previous(); + rs.verify(table1); + } + finally { + terminateVariation(); + } + } + + /////////////////////////////////////////////////////////////////// + // Create a statement + // TYPE_SS_SEVER_CURSOR_FORWARD_ONLY, + // CONCUR_READ_ONLY, executeQuery + // verify cursor by using next and verify data + /////////////////////////////////////////////////////////////////// + @Test + public void testStmtSS_SEVER_CURSOR_FORWARD_ONLY() throws SQLException { + + try { + int TYPE_SS_SEVER_CURSOR_FORWARD_ONLY = 2004; + int CONCUR_READ_ONLY = 1008; + conn = new DBConnection(connectionString); + stmt = conn.createStatement(TYPE_SS_SEVER_CURSOR_FORWARD_ONLY, CONCUR_READ_ONLY); + + // DBResultSet.currentTable = table1; + String query = "SELECT * FROM " + table1.getEscapedTableName(); + + rs = stmt.executeQuery(query); + + // Verify resultset behavior + rs.next(); + rs.verify(table1); + } + finally { + terminateVariation(); + } + + } + + /////////////////////////////////////////////////////////////////// + // Create a preparedstatement, call close + /////////////////////////////////////////////////////////////////// + @Test + public void testCreatepreparedStatement() throws SQLException { + + try { + conn = new DBConnection(connectionString); + String colName = table1.getColumnName(7); + String value = rs.getRow(0).get(7).toString(); + + String query = "SELECT * from " + table1.getEscapedTableName() + " where [" + colName + "] = ? "; + + pstmt = conn.prepareStatement(query); + pstmt.setObject(1, new BigDecimal(value)); + // + rs = pstmt.executeQuery(); + rs.verify(table1); + } + finally { + terminateVariation(); + } + } + + /////////////////////////////////////////////////////////////////// + // Verify resultset using ResultSetMetaData + /////////////////////////////////////////////////////////////////// + @Test + public void testResultSet() throws SQLException { + + try { + conn = new DBConnection(connectionString); + stmt = conn.createStatement(); + // SELECT * FROM ORDER BY + String query = "SELECT * FROM " + table1.getEscapedTableName(); + rs = stmt.executeQuery(query); + + // verify resultSet + rs.verify(table1); + } + finally { + terminateVariation(); + } + } + + /////////////////////////////////////////////////////////////////// + // Verify resultset and close resultSet + /////////////////////////////////////////////////////////////////// + @Test + public void testResultSetAndClose() throws SQLException { + + try { + DBResultSet rs = null; + conn = new DBConnection(connectionString); + stmt = conn.createStatement(); + + String query = "SELECT * FROM " + table1.getEscapedTableName(); + rs = stmt.executeQuery(query); + rs.currentTable = table1; + + rs.verify(table1); + stmt.close(); + } + finally { + terminateVariation(); + } + } + + /////////////////////////////////////////////////////////////////// + // Verify two concurrent resultsets from same connection, + // separate statements + /////////////////////////////////////////////////////////////////// + @Test + public void testTwoResultsetsDifferentStmt() throws SQLException { + + DBStatement stmt1 = null; + DBStatement stmt2 = null; + DBResultSet rs1 = null; + DBResultSet rs2 = null; + try { + conn = new DBConnection(connectionString); + stmt1 = conn.createStatement(); + stmt2 = conn.createStatement(); + + // SELECT * FROM ORDER BY + + String query = "SELECT * FROM " + table1.getEscapedTableName(); + rs1 = stmt1.executeQuery(query); + rs1.currentTable = table1; + + String query2 = "SELECT * FROM " + table2.getEscapedTableName(); + rs2 = stmt2.executeQuery(query2); + rs2.currentTable = table2; + + // Interleave resultset calls + rs1.next(); + rs1.verifyCurrentRow(table1); + rs2.next(); + rs2.verifyCurrentRow(table2); + rs1.next(); + rs1.verifyCurrentRow(table1); + rs1.verify(table1); + rs1.close(); + rs2.next(); + rs2.verify(table2); + } + finally { + if (null != rs1) { + rs1.close(); + } + if (null != rs2) { + rs2.close(); + } + if (null != stmt1) { + stmt1.close(); + } + if (null != stmt2) { + stmt2.close(); + } + terminateVariation(); + } + } + + /////////////////////////////////////////////////////////////////// + // Verify two concurrent resultsets from same connection, + // same statement + /////////////////////////////////////////////////////////////////// + @Test + public void testTwoResultsetsSameStmt() throws SQLException { + + DBResultSet rs1 = null; + DBResultSet rs2 = null; + try { + conn = new DBConnection(connectionString); + stmt = conn.createStatement(); + + // SELECT * FROM ORDER BY + String query = "SELECT * FROM " + table1.getEscapedTableName(); + rs1 = stmt.executeQuery(query); + + // SELECT * FROM ORDER BY + String query2 = "SELECT * FROM " + table2.getEscapedTableName(); + rs2 = stmt.executeQuery(query2); + + // Interleave resultset calls. rs is expected to be closed + try { + rs1.next(); + } + catch (SQLException e) { + assertEquals(e.toString(), "com.microsoft.sqlserver.jdbc.SQLServerException: The result set is closed."); + } + rs2.next(); + rs2.verifyCurrentRow(table2); + try { + rs1.next(); + } + catch (SQLException e) { + assertEquals(e.toString(), "com.microsoft.sqlserver.jdbc.SQLServerException: The result set is closed."); + } + rs1.close(); + rs2.next(); + rs2.verify(table2); + } + finally { + if (null != rs1) { + rs1.close(); + } + if (null != rs2) { + rs2.close(); + } + terminateVariation(); + } + } + + /////////////////////////////////////////////////////////////////// + // Verify resultset closed after statement is closed + /////////////////////////////////////////////////////////////////// + @Test + public void testResultSetAndCloseStmt() throws SQLException { + try { + conn = new DBConnection(connectionString); + stmt = conn.createStatement(); + + // SELECT * FROM ORDER BY + String query = "SELECT * FROM " + table1.getEscapedTableName(); + rs = stmt.executeQuery(query); + + // close statement and verify resultSet + stmt.close(); // this should close the resultSet + try { + rs.next(); + } + catch (SQLException e) { + assertEquals(e.toString(), "com.microsoft.sqlserver.jdbc.SQLServerException: The result set is closed."); + } + } + finally { + terminateVariation(); + } + } + + /////////////////////////////////////////////////////////////////// + // Verify resultset using SelectMethod + /////////////////////////////////////////////////////////////////// + @Test + public void testResultSetSelectMethod() throws SQLException { + + try { + conn = new DBConnection(connectionString + ";selectMethod=cursor;"); + stmt = conn.createStatement(); + + // SELECT * FROM ORDER BY + String query = "SELECT * FROM " + table1.getEscapedTableName(); + rs = stmt.executeQuery(query); + + // verify resultSet + rs.verify(table1); } finally { terminateVariation(); } } - // - // /////////////////////////////////////////////////////////////////// - // // Create a statement - // // ResultSet.Type_forward_only, - // // ResultSet.CONCUR_UPDATABLE, executeQuery - // // verify cursor by using next and previous and verify data - // /////////////////////////////////////////////////////////////////// - // @Test - // public void testStmtForwardOnlyUpdateable() throws SQLException { - // - // try { - // stmt = conn().createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); - // - // // SELECT * FROM ORDER BY - // String pk = Tables.primaryKey(); - // String query = Tables.select_Orderby(table1, pk); - // rs = stmt.executeQuery(query); - // bvt_rs = new bvt_ResultSet(rs); - // - // // Verify resultset behavior - // bvt_rs.next(); - // bvt_rs.verifyCurrentRow(); - // bvt_rs.next(); - // bvt_rs.verifyCurrentRow(); - // try { - // bvt_rs.previous(); - // assertTrue("Previous should have thrown an exception", false); - // } - // catch (SQLException ex) { - // // expected exception - // } - // bvt_rs.verify(); - // } - // finally { - // terminateVariation(); - // } - // } - // - // /////////////////////////////////////////////////////////////////// - // // Create a statement - // // ResultSet.SCROLL_SENSITIVE, - // // ResultSet.CONCUR_UPDATABLE, executeQuery - // // verify cursor by using next and previous and verify data - // /////////////////////////////////////////////////////////////////// - // @Test - // public void testStmtScrollSensitiveUpdatable() throws SQLException { - // - // try { - // stmt = conn().createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); - // - // // SELECT * FROM ORDER BY - // String pk = Tables.primaryKey(); - // String query = Tables.select_Orderby(table1, pk); - // rs = stmt.executeQuery(query); - // bvt_rs = new bvt_ResultSet(rs); - // - // // Verify resultset behavior - // bvt_rs.next(); - // bvt_rs.next(); - // bvt_rs.verifyCurrentRow(); - // bvt_rs.absolute(3); - // bvt_rs.verifyCurrentRow(); - // bvt_rs.absolute(1); - // bvt_rs.verify(); - // } - // finally { - // terminateVariation(); - // } - // } - // - // /////////////////////////////////////////////////////////////////// - // // Create a statement - // // TYPE_SS_SCROLL_DYNAMIC, - // // CONCUR_SS_OPTIMISTIC_CC, executeQuery - // // verify cursor by using next and previous and verify data - // /////////////////////////////////////////////////////////////////// - // @Test - // public void testStmtSS_ScrollDynamicOptimistic_CC() throws SQLException { - // - // try { - // int TYPE_SS_SCROLL_DYNAMIC = 1006; - // int CONCUR_SS_OPTIMISTIC_CC = 1008; - // stmt = conn().createStatement(TYPE_SS_SCROLL_DYNAMIC, CONCUR_SS_OPTIMISTIC_CC); - // - // // SELECT * FROM
ORDER BY , ASC|DESC - // String c1 = Tables.primaryKey(); - // String c2 = "[c1_char(512)]"; - // - // Tables.select(table1); - // Tables.orderby(c1); - // Tables.orderby(c2); - // - // rs = stmt.executeQuery(Tables.query); - // bvt_rs = new bvt_ResultSet(rs); - // - // // Verify resultset behavior - // bvt_rs.next(); - // bvt_rs.afterLast(); - // bvt_rs.previous(); - // bvt_rs.verify(); - // } - // finally { - // terminateVariation(); - // } - // } - // - // /////////////////////////////////////////////////////////////////// - // // Create a statement - // // TYPE_SS_SEVER_CURSOR_FORWARD_ONLY, - // // CONCUR_READ_ONLY, executeQuery - // // verify cursor by using next and verify data - // /////////////////////////////////////////////////////////////////// - // @Test - // public void testStmtSS_SEVER_CURSOR_FORWARD_ONLY() throws SQLException { - // - // try { - // int TYPE_SS_SEVER_CURSOR_FORWARD_ONLY = 2004; - // int CONCUR_READ_ONLY = 1008; - // stmt = conn().createStatement(TYPE_SS_SEVER_CURSOR_FORWARD_ONLY, CONCUR_READ_ONLY); - // - // String c1 = Tables.primaryKey(); - // String c2 = "[c1_char(512)]"; - // - // Tables.select(table1); - // Tables.orderby(c1); - // Tables.orderby(c2); - // - // rs = stmt.executeQuery(Tables.query); - // bvt_rs = new bvt_ResultSet(rs); - // - // // Verify resultset behavior - // bvt_rs.next(); - // bvt_rs.verify(); - // } - // finally { - // terminateVariation(); - // } - // - // } - // - // /////////////////////////////////////////////////////////////////// - // // Create a preparedstatement, call close - // /////////////////////////////////////////////////////////////////// - // @Test - // public void testCreatepreparedStatement() throws SQLException { - // - // try { - // String pk = Tables.primaryKey(); - // String query = "SELECT * from " + table1 + " where c30_smallmoney = ? order by " + pk; - // - // pstmt = (SQLServerPreparedStatement) conn().prepareStatement(query); - // pstmt.setSmallMoney(1, new BigDecimal("214748.3647")); - // - // rs = pstmt.executeQuery(); - // bvt_rs = new bvt_ResultSet(rs); - // bvt_rs.verify(); - // } - // finally { - // terminateVariation(); - // } - // } - // - // /////////////////////////////////////////////////////////////////// - // // Verify resultset using ResultSetMetaData - // /////////////////////////////////////////////////////////////////// - // @Test - // public void testResultSet() throws SQLException { - // - // try { - // stmt = conn().createStatement(); - // // SELECT * FROM ORDER BY - // String pk = Tables.primaryKey(); - // String query = Tables.select_Orderby(table2, pk); - // rs = stmt.executeQuery(query); - // bvt_rs = new bvt_ResultSet(rs); - // - // // verify resultSet - // bvt_rs.verify(); - // } - // finally { - // terminateVariation(); - // } - // } - // - // /////////////////////////////////////////////////////////////////// - // // Verify resultset and close resultSet - // /////////////////////////////////////////////////////////////////// - // @Test - // public void testResultSetAndClose() throws SQLException { - // - // try { - // stmt = conn().createStatement(); - // - // // SELECT * FROM ORDER BY - // String pk = Tables.primaryKey(); - // String query = Tables.select_Orderby(table2, pk); - // rs = stmt.executeQuery(query); - // } - // finally { - // terminateVariation(); - // } - // } - // - // /////////////////////////////////////////////////////////////////// - // // Verify two concurrent resultsets from same connection, - // // separate statements - // /////////////////////////////////////////////////////////////////// - // @Test - // public void testTwoResultsetsDifferentStmt() throws SQLException { - // - // Statement stmt1 = null; - // Statement stmt2 = null; - // ResultSet rs1 = null; - // ResultSet rs2 = null; - // bvt_ResultSet bvt_rs1 = null; - // bvt_ResultSet bvt_rs2 = null; - // try { - // stmt1 = conn().createStatement(); - // stmt2 = conn().createStatement(); - // - // // SELECT * FROM ORDER BY - // String pk = Tables.primaryKey(); - // String query = Tables.select_Orderby(table2, pk); - // rs1 = stmt1.executeQuery(query); - // - // String query2 = Tables.select_Orderby(table1, pk); - // rs2 = stmt2.executeQuery(query2); - // bvt_rs1 = new bvt_ResultSet(rs1); - // bvt_rs2 = new bvt_ResultSet(rs2); - // - // // Interleave resultset calls - // bvt_rs1.next(); - // bvt_rs1.verifyCurrentRow(); - // bvt_rs2.next(); - // bvt_rs2.verifyCurrentRow(); - // bvt_rs1.next(); - // bvt_rs1.verifyCurrentRow(); - // bvt_rs1.verify(); - // bvt_rs1.close(); - // bvt_rs2.next(); - // bvt_rs2.verify(); - // } - // finally { - // if (null != bvt_rs2) { - // bvt_rs2.close(); - // } - // if (null != rs1) { - // rs1.close(); - // } - // if (null != rs2) { - // rs2.close(); - // } - // if (null != stmt1) { - // stmt1.close(); - // } - // if (null != stmt2) { - // stmt2.close(); - // } - // terminateVariation(); - // } - // } - // - // /////////////////////////////////////////////////////////////////// - // // Verify two concurrent resultsets from same connection, - // // same statement - // /////////////////////////////////////////////////////////////////// - // @Test - // public void testTwoResultsetsSameStmt() throws SQLException { - // - // ResultSet rs1 = null; - // ResultSet rs2 = null; - // try { - // stmt = conn().createStatement(); - // - // // SELECT * FROM ORDER BY - // String pk = Tables.primaryKey(); - // String query = Tables.select_Orderby(table2, pk); - // rs1 = stmt.executeQuery(query); - // - // // SELECT * FROM ORDER BY - // String query2 = Tables.select_Orderby(table1, pk); - // rs2 = stmt.executeQuery(query2); - // - // bvt_ResultSet bvt_rs1 = new bvt_ResultSet(rs1); - // bvt_ResultSet bvt_rs2 = new bvt_ResultSet(rs2); - // - // // Interleave resultset calls. rs is expected to be closed - // try { - // bvt_rs1.next(); - // } - // catch (SQLException e) { - // assertEquals(e.toString(), "com.microsoft.sqlserver.jdbc.SQLServerException: The result set is closed."); - // } - // bvt_rs2.next(); - // bvt_rs2.verifyCurrentRow(); - // try { - // bvt_rs1.next(); - // } - // catch (SQLException e) { - // assertEquals(e.toString(), "com.microsoft.sqlserver.jdbc.SQLServerException: The result set is closed."); - // } - // bvt_rs1.close(); - // bvt_rs2.next(); - // bvt_rs2.verify(); - // } - // finally { - // if (null != rs1) { - // rs1.close(); - // } - // if (null != rs2) { - // rs2.close(); - // } - // terminateVariation(); - // } - // } - // - // /////////////////////////////////////////////////////////////////// - // // Verify resultset closed after statement is closed - // /////////////////////////////////////////////////////////////////// - // @Test - // public void testResultSetAndCloseStmt() throws SQLException { - // try { - // stmt = conn().createStatement(); - // - // // SELECT * FROM ORDER BY - // String pk = Tables.primaryKey(); - // String query = Tables.select_Orderby(table2, pk); - // rs = stmt.executeQuery(query); - // bvt_rs = new bvt_ResultSet(rs); - // - // // close statement and verify resultSet - // stmt.close(); // this should close the resultSet - // try { - // bvt_rs.next(); - // } - // catch (SQLException e) { - // assertEquals(e.toString(), "com.microsoft.sqlserver.jdbc.SQLServerException: The result set is closed."); - // } - // } - // finally { - // terminateVariation(); - // } - // } - // - // /////////////////////////////////////////////////////////////////// - // // Verify resultset using SelectMethod - // /////////////////////////////////////////////////////////////////// - // @Test - // public void testResultSetSelectMethod() throws SQLException { - // - // // guarantees selectMethod=cursor - // cursor = true; - // try { - // stmt = conn().createStatement(); - // - // // SELECT * FROM ORDER BY - // String pk = Tables.primaryKey(); - // String query = Tables.select_Orderby(table2, pk); - // rs = stmt.executeQuery(query); - // bvt_rs = new bvt_ResultSet(rs); - // - // // verify resultSet - // bvt_rs.verify(); - // cursor = false; - // } - // finally { - // terminateVariation(); - // } - // } @AfterClass public static void terminate() throws SQLException { try { stmt = conn.createStatement(); - // stmt.executeUpdate(Tables.dropTable(table2)); - // stmt.executeUpdate(Tables.dropTable(table1)); } finally { terminateVariation(); } } - // public static String getConnectionURL() { - // connectionUrl = System.getenv("mssql_jdbc_test_connection_properties"); - // - // if (null == connectionUrl) { - // fail("Please setup environment variable mssql_jdbc_test_connection_properties"); - // } - // - // if (cursor) { - // connectionUrl += ";selectMethod=cursor;"; - // } - // - // if (querytimeout) { - // connectionUrl += ";queryTimeout=10"; - // } - // - // return connectionUrl; - // } - // - // public static Connection conn() { - // - // connectionUrl = getConnectionURL(); - // // Establish the connection. - // try { - // - // Connection con = DriverManager.getConnection(connectionUrl); - // return con; - // // Handle any errors that may have occurred. - // } - // catch (SQLException e) { - // fail("Please make sure the environment variable mssql_jdbc_test_connection_properties is set with correct connection properties.\n" - // + e.toString()); - // } - // return null; - // } - public static void terminateVariation() throws SQLException { if (conn != null && !conn.isClosed()) { try { conn.close(); } finally { - if (null != bvt_rs) - bvt_rs.close(); if (null != rs) rs.close(); if (null != stmt) stmt.close(); - if (null != pstmt) - pstmt.close(); + // if (null != pstmt) + // pstmt.close(); } } } diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBConnection.java b/src/test/java/com/microsoft/sqlserver/testframework/DBConnection.java index 2268644c2..30476b35e 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBConnection.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBConnection.java @@ -29,6 +29,7 @@ import java.sql.Connection; import java.sql.DatabaseMetaData; +import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; @@ -107,14 +108,21 @@ public DBStatement createStatement() { * @throws SQLException */ public DBStatement createStatement(int type, int concurrency) throws SQLException { - Statement product = ((Connection) product()).createStatement(type, concurrency); - DBStatement wrapper = new DBStatement(this, product, type, concurrency, _holdability); + DBStatement dbstatement = new DBStatement(this); + return dbstatement.createStatement(type, concurrency); - // State - wrapper._cursortype = type; - wrapper._concurrency = concurrency; - - return wrapper; + } + + /** + * + * @param query + * @return + * @throws SQLException + */ + public DBPreparedStatement prepareStatement(String query) throws SQLException + { + DBPreparedStatement dbpstmt = new DBPreparedStatement(this, internal, "preparedStatement"); + return dbpstmt.prepareStatement(query); } /** @@ -157,6 +165,12 @@ public DatabaseMetaData getMetaData() throws SQLException { return product; } + /** + * + * @param con + * @return + * @throws SQLException + */ public static boolean isSqlAzure(Connection con) throws SQLException { boolean isSqlAzure = false; diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBPreparedStatement.java b/src/test/java/com/microsoft/sqlserver/testframework/DBPreparedStatement.java new file mode 100644 index 000000000..501048981 --- /dev/null +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBPreparedStatement.java @@ -0,0 +1,78 @@ +/** + * + */ +package com.microsoft.sqlserver.testframework; + +import java.math.BigDecimal; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import com.microsoft.sqlserver.testframework.sqlType.SqlDateTimeOffset; +/** + * @author v-afrafi + * + */ +public class DBPreparedStatement extends AbstractParentWrapper { + + PreparedStatement pstmt = null; + DBResultSet dbresultSet = null; + + /** + * @param parent + * @param internal + * @param name + */ + DBPreparedStatement(AbstractParentWrapper parent, Object internal, String name) { + super(parent, internal, name); + } + + /** + * @throws SQLException + * + */ + DBPreparedStatement prepareStatement(String query) throws SQLException { + pstmt = ( (Connection) product()).prepareStatement(query); + setInternal(pstmt); + return this; + } + + @Override + void setInternal(Object internal) { + this.internal = internal; + } + + /** + * @param i + * @param bigDecimal + * @throws SQLException + */ + public void setObject(int parameterIndex, Object targetObject) throws SQLException { + + ((PreparedStatement) product()).setObject(parameterIndex, targetObject); + + } + + public DBResultSet executeQuery() throws SQLException + { + ResultSet rs = null; + rs = pstmt.executeQuery(); + dbresultSet = new DBResultSet(this, rs); +// DBResultSet product = ((PreparedStatement) product()).executeQuery(); + return dbresultSet; + + } +// //Used to return the appropriate object given the framework wrapper +// public Object getTargetObject(Object value) +// { +// if(value instanceof sqlDateTimeOffset) +// { +// return ((DBDateTimeOffset)value).product(); +// } +// else +// { +// return value; +// } +// } + +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java index 6a8e791a6..525f35f4a 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java @@ -26,12 +26,19 @@ package com.microsoft.sqlserver.testframework; import java.math.BigDecimal; +import java.sql.Date; +import java.sql.JDBCType; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; +import java.sql.Time; +import java.sql.Timestamp; import java.util.ArrayList; +import java.util.Calendar; +import com.sun.org.apache.xpath.internal.operations.Bool; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; /** @@ -45,16 +52,24 @@ public class DBResultSet extends AbstractParentWrapper { // TODO: add cursors // TODO: add resultSet level holdability // TODO: add concurrency control - public DBTable currentTable; + public DBTable currentTable; public static final int VERIFY_MOVERS_NEXT = 0x100; - public int _currentrow = 0; // The row this rowset is currently pointing to + public int _currentrow = -1; // The row this rowset is currently pointing to ResultSet resultSet = null; - + DBResultSetMetaData metaData; + DBResultSet(DBStatement dbstatement, ResultSet internal) { super(dbstatement, internal, "resultSet"); resultSet = internal; } + + DBResultSet(DBPreparedStatement dbpstmt, ResultSet internal) { + super(dbpstmt, internal, "resultSet"); + resultSet = internal; + } + + /** * Close the ResultSet object @@ -104,22 +119,23 @@ public void updateObject(int index) throws SQLException { */ public void verify(DBTable table) throws SQLException { currentTable = table; - DBResultSetMetaData metaData = this.getMetaData(); + metaData = this.getMetaData(); metaData.verify(); while (this.next()) - this.verifyCurrentRow(); + this.verifyCurrentRow(table); } /** * @throws SQLException * */ - public void verifyCurrentRow() throws SQLException{ - int size = ((ResultSet) product()).getMetaData().getColumnCount(); + public void verifyCurrentRow(DBTable table) throws SQLException{ + currentTable = table; + int totalColumns = ((ResultSet) product()).getMetaData().getColumnCount(); Class _class = Object.class; - for ( int i=0; i< size; i++) + for ( int i=0; i< totalColumns; i++) verifydata(i, _class, null); } @@ -137,56 +153,144 @@ public void verifydata(int ordinal, Class coercion, Object arg) throws SQLExcept public void verifydata(int ordinal, Class coercion, Object backendData, Object retrieved) throws SQLException { - - if (backendData != null) { - if (retrieved instanceof BigDecimal) { - if (((BigDecimal) retrieved).compareTo(new BigDecimal("" + backendData)) != 0) - fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved - + " , inserted value is " + backendData); - - } else if (retrieved instanceof Float) { - if (Float.compare(new Float("" + backendData), (float) retrieved) != 0) - fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved - + " ,inserted value is " + backendData); - } else if (retrieved instanceof Double) { - if (Double.compare(new Double("" + backendData), (double) retrieved) != 0) - fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved - + " , inserted value is " + backendData); - } else if (retrieved instanceof byte[]) { - if (!parseByte((byte[]) retrieved).contains("" + backendData)) - fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved - + " , inserted value is " + backendData); - } else if (retrieved instanceof String) { - if (!(((String) retrieved).trim()).equalsIgnoreCase(((String) backendData).trim())) - fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved - + " , inserted value is " + backendData); - } else if (retrieved instanceof Boolean) { - if ( retrieved.equals(true) && !backendData.equals(1)) - { - fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved - + " , inserted value is " + backendData); - } - else if ( retrieved.equals(false) && !backendData.equals(0)) - { - fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved - + " , inserted value is " + backendData); - } - } else if (!(("" + retrieved).equalsIgnoreCase("" + backendData))) - fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved + " , inserted value is " - + backendData); - } - // if data is null - else { - if (retrieved != backendData) - fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved + " , inserted value is " - + backendData); + metaData = this.getMetaData(); + switch (metaData.getColumnType(ordinal + 1)) { + case java.sql.Types.BIGINT: + assertTrue((((Long) backendData).longValue() == ((Long) retrieved).longValue()), "Unexpected bigint value"); + break; + + case java.sql.Types.INTEGER: + assertTrue((((Integer) backendData).intValue() == ((Integer) retrieved).intValue()), "Unexpected int value"); + break; + + case java.sql.Types.SMALLINT: + case java.sql.Types.TINYINT: + assertTrue((((Short) backendData).shortValue() == ((Short) retrieved).shortValue()), "Unexpected smallint/tinyint value"); + break; + + case java.sql.Types.BIT: + if (backendData.equals(1)) + backendData = true; + else backendData = false; + assertTrue(( (((Boolean) backendData)).booleanValue() == ((Boolean) retrieved).booleanValue()), "Unexpected bit value"); + break; + + case java.sql.Types.DECIMAL: + case java.sql.Types.NUMERIC: + assertTrue(0 == (((BigDecimal) backendData).compareTo((BigDecimal) retrieved)), + "Unexpected decimal/numeric/money/smallmoney value"); + break; + + case java.sql.Types.DOUBLE: + assertTrue((((Double) backendData).doubleValue() == ((Double) retrieved).doubleValue()), "Unexpected float value"); + break; + + case java.sql.Types.REAL: + assertTrue((((Float) backendData).floatValue() == ((Float) retrieved).floatValue()), "Unexpected real value"); + break; + + case java.sql.Types.VARCHAR: + case java.sql.Types.NVARCHAR: + System.out.println("-----> b: "+ backendData.toString().trim()); + System.out.println("-----> r: " + retrieved.toString().trim()); + System.out.println(backendData.toString().trim().equalsIgnoreCase(retrieved.toString().trim())); + assertTrue((((String) backendData).equals((String) retrieved)), "Unexpected varchar/nvarchar value "); + break; + + case java.sql.Types.CHAR: + case java.sql.Types.NCHAR: +// assertTrue((((String) backendData).trim().equalsIgnoreCase(((String) retrieved).trim())), "Unexpected char/nchar value "); + break; + + case java.sql.Types.TIMESTAMP: + if (metaData.getColumnTypeName(ordinal +1).equalsIgnoreCase("datetime")) + { + assertTrue((((Timestamp) roundDatetimeValue(backendData) ).getTime() == (((Timestamp) retrieved).getTime())), + "Unexpected datetime value"); + break; + } + else if (metaData.getColumnTypeName(ordinal +1).equalsIgnoreCase("smalldatetime")) + { + assertTrue((((Timestamp) roundSmallDateTimeValue(backendData) ).getTime() == (((Timestamp) retrieved).getTime())), + "Unexpected smalldatetime value"); + break; + } + else +// assertTrue((""+ ((java.util.Date) backendData).getTime()).equalsIgnoreCase("" +retrieved.getTime()), +// "Unexpected datetime2 value"); + break; + + case java.sql.Types.DATE: + assertTrue((("" +backendData).equalsIgnoreCase(""+ retrieved)), "Unexpected date value"); + break; + + case java.sql.Types.TIME: +// assertTrue((backendData) == ((Time) retrieved).getTime(), "Unexpected time value "); + break; + + case microsoft.sql.Types.DATETIMEOFFSET: +// assertTrue(0 == ((microsoft.sql.DateTimeOffset) backendData).compareTo((microsoft.sql.DateTimeOffset) retrieved), +// "Unexpected time value "); + break; + + default: + fail("Unhandled JDBCType " + JDBCType.valueOf(metaData.getColumnType(ordinal + 1))); + break; } +// if (backendData != null) { +// if (retrieved instanceof BigDecimal) { +// if (((BigDecimal) retrieved).compareTo(new BigDecimal("" + backendData)) != 0) +// fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved +// + " , inserted value is " + backendData); +// +// } else if (retrieved instanceof Float) { +// if (Float.compare(new Float("" + backendData), (float) retrieved) != 0) +// fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved +// + " ,inserted value is " + backendData); +// } else if (retrieved instanceof Double) { +// if (Double.compare(new Double("" + backendData), (double) retrieved) != 0) +// fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved +// + " , inserted value is " + backendData); +// } else if (retrieved instanceof byte[]) { +// if (!parseByte((byte[]) retrieved).contains("" + backendData)) +// fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved +// + " , inserted value is " + backendData); +// } else if (retrieved instanceof String) { +// if (!(((String) retrieved).trim()).equalsIgnoreCase(((String) backendData).trim())) +// fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved +// + " , inserted value is " + backendData); +// } else if (retrieved instanceof Boolean) { +// if ( retrieved.equals(true) && !backendData.equals(1)) +// { +// fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved +// + " , inserted value is " + backendData); +// } +// else if ( retrieved.equals(false) && !backendData.equals(0)) +// { +// fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved +// + " , inserted value is " + backendData); +// } +// } else if (!(("" + retrieved).equalsIgnoreCase("" + backendData))) +// fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved + " , inserted value is " +// + backendData); +// } +// // if data is null +// else { +// if (retrieved != backendData) +// fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved + " , inserted value is " +// + backendData); +// } + } public ArrayList currentrow(){ - return currentTable.getAllRows().get(_currentrow -1); + return currentTable.getAllRows().get(_currentrow ); + } + + public ArrayList getRow(int index){ + return currentTable.getAllRows().get(index ); } private Object getXXX(int idx, Class coercion) throws SQLException { @@ -249,12 +353,13 @@ public boolean previous() throws SQLException public void afterLast() throws SQLException { ((ResultSet) product()).afterLast(); - _currentrow = DBTable.getTotalRows() + 1; + _currentrow = DBTable.getTotalRows() ; } public boolean absolute(int x) throws SQLException { boolean validrow = ((ResultSet) product()).absolute(x); + _currentrow = x-1; return validrow; } @@ -266,4 +371,100 @@ private static String parseByte(byte[] bytes) { } return parsedByte.toString(); } + + + public static Object roundSmallDateTimeValue(Object value) + { + if(value == null) + { + return null; + } + + Calendar cal; + java.sql.Timestamp ts = null; + int nanos = -1; + + if(value instanceof Calendar) + { + cal = (Calendar)value; + } + else + { + ts = (java.sql.Timestamp)value; + cal = Calendar.getInstance(); + cal.setTimeInMillis(ts.getTime()); + nanos = ts.getNanos(); + } + + //round to the nearest minute + double seconds = cal.get(Calendar.SECOND) + (nanos == -1 ? ((double)cal.get(Calendar.MILLISECOND) / 1000) : ((double)nanos / 1000000000)); + if(seconds > 29.998) + { + cal.set(Calendar.MINUTE, cal.get(Calendar.MINUTE) + 1); + } + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + nanos = 0; + + //required to force computation + cal.getTimeInMillis(); + + //return appropriate value + if(value instanceof Calendar) + { + return cal; + } + else + { + ts.setTime(cal.getTimeInMillis()); + ts.setNanos(nanos); + return ts; + } + } + + public static Object roundDatetimeValue(Object value) + { + if(value == null) + return null; + Timestamp ts = value instanceof Timestamp ? (Timestamp)value : new Timestamp(((Calendar)value).getTimeInMillis()); + int millis = ts.getNanos() / 1000000; + int lastDigit = (int)(millis % 10); + switch(lastDigit) + { + //0, 1 -> 0 + case 1: ts.setNanos((millis - 1) * 1000000); + break; + + //2, 3, 4 -> 3 + case 2: ts.setNanos((millis + 1) * 1000000); + break; + case 4: ts.setNanos((millis - 1) * 1000000); + break; + + //5, 6, 7, 8 -> 7 + case 5: ts.setNanos((millis + 2) * 1000000); + break; + case 6: ts.setNanos((millis + 1) * 1000000); + break; + case 8: ts.setNanos((millis - 1) * 1000000); + break; + + //9 -> 0 with overflow + case 9: ts.setNanos(0); + ts.setTime(ts.getTime() + millis + 1); + break; + + //default, i.e. 0, 3, 7 -> 0, 3, 7 + //don't change the millis but make sure that any + //sub-millisecond digits are zeroed out + default: ts.setNanos((millis) * 1000000); + } + if(value instanceof Calendar) + { + ((Calendar)value).setTimeInMillis(ts.getTime()); + ((Calendar)value).getTimeInMillis(); + return value; + } + return ts; + } } diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetMetaData.java b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetMetaData.java index c51f7843f..7ed1e2baa 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetMetaData.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetMetaData.java @@ -1,13 +1,35 @@ -/** - * - */ +// --------------------------------------------------------------------------------------------------------------------------------- +// File: DBResultSetMetaData.java +// +// +// Microsoft JDBC Driver for SQL Server +// Copyright(c) Microsoft Corporation +// All rights reserved. +// MIT License +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), +// to deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, +// and / or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions : +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +// --------------------------------------------------------------------------------------------------------------------------------- + package com.microsoft.sqlserver.testframework; -import java.sql.ResultSet; -import com.microsoft.sqlserver.jdbc.SQLServerResultSetMetaData; -import java.sql.SQLException; import static org.junit.Assert.fail; +import java.sql.SQLException; + +import com.microsoft.sqlserver.jdbc.SQLServerResultSetMetaData; /** * @author v-afrafi @@ -25,6 +47,10 @@ public class DBResultSetMetaData extends AbstractParentWrapper { // TODO Auto-generated constructor stub } + /** + * + * @throws SQLException + */ public void verify() throws SQLException { // getColumnCount int columns = this.getColumnCount(); @@ -45,64 +71,129 @@ public void verify() throws SQLException { } } + /** + * + * @return + * @throws SQLException + */ public int getColumnCount() throws SQLException { int current = 0; try { - current = ( (SQLServerResultSetMetaData) product()).getColumnCount(); + current = ((SQLServerResultSetMetaData) product()).getColumnCount(); } catch (SQLException e) { - fail(e.toString()); + fail(e.toString()); } return current; } + /** + * + * @param index + * @return + * @throws SQLException + */ public String getColumnName(int index) throws SQLException { - String current = ( (SQLServerResultSetMetaData) product()).getColumnName(index); + String current = ((SQLServerResultSetMetaData) product()).getColumnName(index); return current; } + /** + * + * @param index + * @return + * @throws SQLException + */ public int getColumnType(int index) throws SQLException { - int current = ( (SQLServerResultSetMetaData) product()).getColumnType(index); + int current = ((SQLServerResultSetMetaData) product()).getColumnType(index); return current; } + /** + * + * @param index + * @return + * @throws SQLException + */ public String getColumnTypeName(int index) throws SQLException { - String current = ( (SQLServerResultSetMetaData) product()).getColumnTypeName(index); + String current = ((SQLServerResultSetMetaData) product()).getColumnTypeName(index); return current; } + /** + * + * @param x + * @return + * @throws SQLException + */ public int getPrecision(int x) throws SQLException { - int current = ( (SQLServerResultSetMetaData) product()).getPrecision(x); + int current = ((SQLServerResultSetMetaData) product()).getPrecision(x); return current; } + /** + * + * @param x + * @return + * @throws SQLException + */ public int getScale(int x) throws SQLException { - int current = ( (SQLServerResultSetMetaData) product()).getScale(x); + int current = ((SQLServerResultSetMetaData) product()).getScale(x); return current; } + /** + * + * @param x + * @return + * @throws SQLException + */ public boolean isCaseSensitive(int x) throws SQLException { - boolean current = ( (SQLServerResultSetMetaData) product()).isCaseSensitive(x); + boolean current = ((SQLServerResultSetMetaData) product()).isCaseSensitive(x); return current; } + /** + * + * @param x + * @return + * @throws SQLException + */ public boolean isCurrency(int x) throws SQLException { - boolean current = ( (SQLServerResultSetMetaData) product()).isCurrency(x); + boolean current = ((SQLServerResultSetMetaData) product()).isCurrency(x); return current; } + /** + * + * @param x + * @return + * @throws SQLException + */ public boolean isAutoIncrement(int x) throws SQLException { - boolean current = ( (SQLServerResultSetMetaData) product()).isAutoIncrement(x); + boolean current = ((SQLServerResultSetMetaData) product()).isAutoIncrement(x); return current; } + /** + * + * @param x + * @return + * @throws SQLException + */ public int isNullable(int x) throws SQLException { - int current = ( (SQLServerResultSetMetaData) product()).isNullable(x); + int current = ((SQLServerResultSetMetaData) product()).isNullable(x); return current; } + /** + * + * @param x + * @return + * @throws SQLException + */ public boolean isSigned(int x) throws SQLException { - boolean current = ( (SQLServerResultSetMetaData) product()).isSigned(x); + boolean current = ((SQLServerResultSetMetaData) product()).isSigned(x); return current; } } diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBStatement.java b/src/test/java/com/microsoft/sqlserver/testframework/DBStatement.java index fdc3c5d6f..24f1126af 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBStatement.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBStatement.java @@ -68,6 +68,13 @@ DBStatement createStatement() throws SQLServerException { setInternal(statement); return this; } + + DBStatement createStatement(int type, int concurrency) throws SQLServerException { + // TODO: add cursor and holdability + statement = ((SQLServerConnection) parent().product()).createStatement(type, concurrency); + setInternal(statement); + return this; + } /** * diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java b/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java index 53dc441f7..d21a82711 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java @@ -49,10 +49,11 @@ public class DBTable extends AbstractSQLGenerator { String escapedTableName; List columns; int totalColumns; - static int totalRows = 2; // default row count set to 2 + static int totalRows = 3; // default row count set to 2 DBSchema schema; ArrayList> rows; ArrayList currentrow; + /** * Initializes {@link DBTable} with tableName, schema, and {@link DBColumns} * @@ -68,7 +69,7 @@ public DBTable(boolean autoGenerateSchema) { addColumns(); } else { - this.columns = new ArrayList(); + this.columns = new ArrayList(); } this.totalColumns = columns.size(); this.currentrow = new ArrayList(); @@ -253,14 +254,19 @@ String populateTableSql() { // TODO: add betterway to enclose data if (JDBCType.CHAR == getColumn(colNum).getSqlType().getJdbctype() || JDBCType.VARCHAR == getColumn(colNum).getSqlType().getJdbctype() - || JDBCType.NCHAR == getColumn(colNum).getSqlType().getJdbctype() - || JDBCType.NVARCHAR == getColumn(colNum).getSqlType().getJdbctype() +// || JDBCType.NCHAR == getColumn(colNum).getSqlType().getJdbctype() +// || JDBCType.NVARCHAR == getColumn(colNum).getSqlType().getJdbctype() || JDBCType.TIMESTAMP == getColumn(colNum).getSqlType().getJdbctype() || JDBCType.DATE == getColumn(colNum).getSqlType().getJdbctype() || JDBCType.TIME == getColumn(colNum).getSqlType().getJdbctype()) { sb.add("'" + String.valueOf(getColumn(colNum).getRowValue(i)) + "'"); currentrow.add(getColumn(colNum).getRowValue(i)); } + else if (JDBCType.NCHAR == getColumn(colNum).getSqlType().getJdbctype() + || JDBCType.NVARCHAR == getColumn(colNum).getSqlType().getJdbctype()) { + sb.add("N'" + String.valueOf(getColumn(colNum).getRowValue(i)) + "'"); + currentrow.add(getColumn(colNum).getRowValue(i)); + } else { sb.add(String.valueOf(getColumn(colNum).getRowValue(i))); currentrow.add(getColumn(colNum).getRowValue(i)); @@ -270,7 +276,7 @@ String populateTableSql() { sb.add(COMMA); } } - sb.add(CLOSE_BRACKET); + sb.add(CLOSE_BRACKET); rows.add(currentrow); currentrow = new ArrayList(); } @@ -339,7 +345,7 @@ public void addColumn(SqlType sqlType) { DBColumn getColumn(int index) { return columns.get(index); } - + public ArrayList> getAllRows() { return rows; } diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlChar.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlChar.java index f0e57193a..536eb3694 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlChar.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlChar.java @@ -26,15 +26,15 @@ package com.microsoft.sqlserver.testframework.sqlType; import java.sql.JDBCType; +import java.util.Random; import java.util.concurrent.ThreadLocalRandom; import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang3.RandomStringUtils; /* - * Restricting the size of char/varchar to 4000 and nchar/nvarchar to 2000 to - * accommodate SQL Sever limitation of having of having maximum allowable table - * row size to 8060 + * Restricting the size of char/varchar to 4000 and nchar/nvarchar to 2000 to accommodate SQL Sever limitation of having of having maximum allowable + * table row size to 8060 */ public class SqlChar extends SqlType { @@ -43,13 +43,20 @@ public SqlChar() { } SqlChar(String name, JDBCType jdbctype, int precision) { - super(name, jdbctype, precision, 0, SqlTypeValue.CHAR.minValue, SqlTypeValue.CHAR.maxValue, - SqlTypeValue.CHAR.nullValue, VariableLengthType.Precision); + super(name, jdbctype, precision, 0, SqlTypeValue.CHAR.minValue, SqlTypeValue.CHAR.maxValue, SqlTypeValue.CHAR.nullValue, + VariableLengthType.Precision); generatePrecision(); } public Object createdata() { int dataLength = ThreadLocalRandom.current().nextInt(precision); - return StringEscapeUtils.escapeSql(RandomStringUtils.randomAscii(dataLength)); + String str = RandomStringUtils.randomAscii(dataLength); + String newStr = str.replace("'", ""); +// System.out.println("str " +str); +// System.out.println("new " +newStr); + return newStr; +// return (RandomStringUtils.randomAscii(dataLength).replace("'", "\\'")); +// return StringEscapeUtils.escapeSql(RandomStringUtils.randomAscii(dataLength)); + } } \ No newline at end of file From d7a623a6eb09018b98dd3c7ac8740bb7910cd518 Mon Sep 17 00:00:00 2001 From: v-xiangs Date: Mon, 16 Jan 2017 11:47:48 -0800 Subject: [PATCH 04/28] update connection test headers --- .../sqlserver/jdbc/connection/ConnectionDriverTest.java | 7 +++++++ .../sqlserver/jdbc/connection/DBMetadataTest.java | 7 +++++++ .../jdbc/connection/NativeMSSQLDataSourceTest.java | 7 +++++++ .../microsoft/sqlserver/jdbc/connection/PoolingTest.java | 7 +++++++ .../microsoft/sqlserver/jdbc/connection/TimeoutTest.java | 7 +++++++ .../microsoft/sqlserver/jdbc/connection/WarningTest.java | 7 +++++++ 6 files changed, 42 insertions(+) diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/connection/ConnectionDriverTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/connection/ConnectionDriverTest.java index c813481dd..d8d31d74e 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/connection/ConnectionDriverTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/connection/ConnectionDriverTest.java @@ -1,3 +1,10 @@ +/* + * Microsoft JDBC Driver for SQL Server + * + * Copyright(c) 2016 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.connection; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/connection/DBMetadataTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/connection/DBMetadataTest.java index 7192ef18c..4491f70f8 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/connection/DBMetadataTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/connection/DBMetadataTest.java @@ -1,3 +1,10 @@ +/* + * Microsoft JDBC Driver for SQL Server + * + * Copyright(c) 2016 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.connection; import java.sql.Connection; diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/connection/NativeMSSQLDataSourceTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/connection/NativeMSSQLDataSourceTest.java index 901f10d13..02266e9d3 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/connection/NativeMSSQLDataSourceTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/connection/NativeMSSQLDataSourceTest.java @@ -1,3 +1,10 @@ +/* + * Microsoft JDBC Driver for SQL Server + * + * Copyright(c) 2016 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.connection; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/connection/PoolingTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/connection/PoolingTest.java index 236ff688b..038fe68ec 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/connection/PoolingTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/connection/PoolingTest.java @@ -1,3 +1,10 @@ +/* + * Microsoft JDBC Driver for SQL Server + * + * Copyright(c) 2016 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.connection; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/connection/TimeoutTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/connection/TimeoutTest.java index dcf7ceb4f..dc6c9e5f8 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/connection/TimeoutTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/connection/TimeoutTest.java @@ -1,3 +1,10 @@ +/* + * Microsoft JDBC Driver for SQL Server + * + * Copyright(c) 2016 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.connection; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/connection/WarningTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/connection/WarningTest.java index 67acf4632..aae2ffd3b 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/connection/WarningTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/connection/WarningTest.java @@ -1,3 +1,10 @@ +/* + * Microsoft JDBC Driver for SQL Server + * + * Copyright(c) 2016 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.connection; import static org.junit.jupiter.api.Assertions.assertEquals; From 3ff97583b5e54ec03ed4f93e0c31d9948d8927e0 Mon Sep 17 00:00:00 2001 From: v-afrafi Date: Tue, 17 Jan 2017 13:39:33 -0800 Subject: [PATCH 05/28] bvt test updates --- .../microsoft/sqlserver/jdbc/bvt/Tables.java | 95 ----- .../microsoft/sqlserver/jdbc/bvt/Values.java | 327 ----------------- .../microsoft/sqlserver/jdbc/bvt/bvtTest.java | 24 +- .../sqlserver/jdbc/bvt/bvtTestSetup.java | 74 ++-- .../sqlserver/jdbc/bvt/bvt_ResultSet.java | 181 --------- .../testframework/DBPreparedStatement.java | 72 ++-- .../sqlserver/testframework/DBResultSet.java | 346 ++++++++---------- .../testframework/DBResultSetMetaData.java | 3 +- .../sqlserver/testframework/DBTable.java | 9 +- .../testframework/sqlType/SqlChar.java | 11 +- .../testframework/sqlType/SqlNChar.java | 27 +- .../testframework/sqlType/SqlType.java | 34 +- 12 files changed, 277 insertions(+), 926 deletions(-) delete mode 100644 src/test/java/com/microsoft/sqlserver/jdbc/bvt/Tables.java delete mode 100644 src/test/java/com/microsoft/sqlserver/jdbc/bvt/Values.java delete mode 100644 src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvt_ResultSet.java diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bvt/Tables.java b/src/test/java/com/microsoft/sqlserver/jdbc/bvt/Tables.java deleted file mode 100644 index 1783f0d2b..000000000 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bvt/Tables.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) 2016 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.bvt; -import static org.junit.Assert.fail; - -import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; - -public class Tables { - static String query = ""; - static String name = ""; - private static String create_Table_sql = ""; - private static String drop_Table_Query = ""; - private static final String primary_key = "[c26_int]"; - - public static String createTable(String tableName) { - create_Table_sql = "CREATE TABLE " + tableName + "([c1_char(512)] char(512)," + " [c2_date] date, " - + "[c3_decimal(28,4)] decimal(28,4)," + " [c4_money] money," + " [c5_time] time, " - + "[c6_uniqueidentifier] uniqueidentifier," + " [c7_varchar(max)] varchar(max), " - + "[c8_nvarchar(max)] nvarchar(max)," + " [c9_smallint] smallint, " - + "[c10_numeric(28,4)] numeric(28,4), " + "[c11_ntext] ntext, " - + "[c12_varbinary(max)] varbinary(max), " + "[c13_nchar(512)] nchar(512), " - + "[c14_datetimeoffset(7)] datetimeoffset(7), " + "[c15_xml] xml," - + " [c16_smalldatetime] smalldatetime," + " [c17_varbinary(512)] varbinary(512), " + "[c18_bit] bit, " - + "[c19_varchar(512)] varchar(512), " + "[c20_real] real, " + "[c21_tinyint] tinyint," - + " [c22_float] float, " + "[c23_text] text, " + "[c24_binary(512)] binary(512)," - + " [c25_datetime2] datetime2," + " [c26_int] int NOT NULL PRIMARY KEY, " + "[c27_datetime] datetime," - + " [c28_bigint] bigint," + " [c29_nvarchar(512)] nvarchar(512), " + "[c30_smallmoney] smallmoney," - + "[c31_int] int" + ")"; - return create_Table_sql; - } - - public static String dropTable(String tableName) { - drop_Table_Query = "if object_id('" + tableName + "','U') is not null" + " drop table " + tableName; - return drop_Table_Query; - } - - public static String select(String tableName) { - return query = "SELECt * FROM " + tableName; - } - - public static String select_Orderby(String tableName, String column) { - return "SELECt * FROM " + tableName + " order by " + column; - } - - public static String orderby(String column) { - - if (query.contains("order")) - return query = query + ", " + column; - else - return query = query + " order by " + column; - - } - - public static String primaryKey() { - return primary_key; - } - - public static void populate(String tableName, Statement stmt) { - ArrayList valuesPerRow = null; - for (int i = 0; i < Values.getRowNumbers(); i++) { - valuesPerRow = Values.getTableValues(i); - String populate_query = createInsertSQL(tableName, valuesPerRow); - try { - stmt.executeUpdate(populate_query); - } catch (SQLException e) { - fail(e.toString()); - } - } - } - - private static String createInsertSQL(String tableName, ArrayList valuesPerRow) { - String sql = "INSERT into " + tableName + " values (" + "'" + valuesPerRow.get(0) + "', '" + valuesPerRow.get(1) - + "', " + valuesPerRow.get(2) + "," + valuesPerRow.get(3) + ", '" + valuesPerRow.get(4) + "','" - + valuesPerRow.get(5) + "','" + valuesPerRow.get(6) + "','" + valuesPerRow.get(7) + "', " - + valuesPerRow.get(8) + ", " + valuesPerRow.get(9) + ",N'" + valuesPerRow.get(10) + "', " - + valuesPerRow.get(11) + ", '" + valuesPerRow.get(12) + "',' " + valuesPerRow.get(13) + "',' " - + valuesPerRow.get(14) + "','" + valuesPerRow.get(15) + "'," + valuesPerRow.get(16) + ",'" - + valuesPerRow.get(17) + "','" + valuesPerRow.get(18) + "'," + valuesPerRow.get(19) + ", " - + valuesPerRow.get(20) + ", " + valuesPerRow.get(21) + ",'" + valuesPerRow.get(22) + "', " - + valuesPerRow.get(23) + ",' " + valuesPerRow.get(24) + "', " + valuesPerRow.get(25) + ",' " - + valuesPerRow.get(26) + "', " + valuesPerRow.get(27) + ", '" + valuesPerRow.get(28) + "', " - + valuesPerRow.get(29) + ", " + valuesPerRow.get(30) + " )"; - - return sql; - } -} diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bvt/Values.java b/src/test/java/com/microsoft/sqlserver/jdbc/bvt/Values.java deleted file mode 100644 index 492a31ac9..000000000 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bvt/Values.java +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) 2016 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.bvt; - -import java.math.BigDecimal; -import java.sql.Date; -import java.sql.Time; -import java.sql.Timestamp; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Random; -import java.util.UUID; - -import microsoft.sql.DateTimeOffset; - -public class Values { - - private static ArrayList valuesPerRow; - private static ArrayList> tableValues; - private static String normalCharSet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - private static int rowNumbers; - private static long max; - private static long min; - private static long avg; - private static final char[] hexdigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', - 'F' }; - private static Random r = new Random(); - - public static int getRowNumbers() { - return rowNumbers; - } - - public static void createData() { - - String[] char512 = { generateCharTypes("512", false), generateCharTypes("1", false), - generateCharTypes("225", false) }; - - Date[] date = { Date.valueOf("9999-12-31"), Date.valueOf("0001-01-01"), Date.valueOf("2011-01-11") }; - - BigDecimal[] decimal = { new BigDecimal("999999999999999999999999.9999"), - new BigDecimal("-999999999999999999999999.9999"), new BigDecimal("1234.1234") }; - - BigDecimal[] money = { new BigDecimal("922337203685477.5807"), new BigDecimal("-922337203685477.5808"), - new BigDecimal("-522337203685477.1234") }; - - max = Timestamp.valueOf("9999-12-31 23:59:59").getTime(); - min = Timestamp.valueOf("0001-01-01 00:00:00").getTime(); - avg = Timestamp.valueOf("2011-01-11 00:00:00").getTime(); - Time[] time = { Time.valueOf("23:59:59"), Time.valueOf("00:00:00"), Time.valueOf("05:23:00") }; - - String[] guid = { "" + UUID.randomUUID(), "" + UUID.randomUUID(), "" + UUID.randomUUID() }; - - String[] varcharMax = { generateCharTypes("max", false), generateCharTypes("1", false), - generateCharTypes("225", false) }; - - String[] nVarcharMax = { generateNCharTypes("max", false), generateNCharTypes("1", false), - generateNCharTypes("225", false) }; - - Short[] smallint = { new Short(Short.MAX_VALUE), new Short(Short.MIN_VALUE), 5 }; - - BigDecimal[] numeric = { new BigDecimal("999999999999999999999999.9999"), - new BigDecimal("-999999999999999999999999.9999"), new BigDecimal("1234.1234") }; - - String[] ntext = { "林ན་དགོས་ཏེ།ངག་ཕྱོαβγδεζη", "जंतुआपेड़पौधाकेमिलल太陽系の年齢もま", "放我放问역사적으" }; - - String[] varbinaryMax = { "0x" + toString(generateBinaryTypes("max", false)), - "0x" + toString(generateBinaryTypes("max", false)), - "0x" + toString(generateBinaryTypes("max", false)) }; - - String[] nchar512 = { generateNCharTypes("512", false), generateNCharTypes("0", false), - generateNCharTypes("225", false) }; - - DateTimeOffset maxDTS = calculateDateTimeOffsetMinMax("max", 7, "9999-12-31 23:59:59"); - DateTimeOffset minDTS = calculateDateTimeOffsetMinMax("min", 7, "0001-01-01 00:00:00"); - DateTimeOffset[] dto = { maxDTS, minDTS, minDTS }; - - String[] xml = { "1EMP", - "1EMP", - "1EMP" }; - - max = Timestamp.valueOf("2079-06-06 23:59:00").getTime(); - min = Timestamp.valueOf("1900-01-01 00:00:00").getTime(); - Timestamp[] smallDatetime = { new Timestamp(max), new Timestamp(min), new Timestamp(min) }; - - String[] varbinary512 = { "0x633234", "0x633234", "0x633234" }; - - max = Timestamp.valueOf("9999-12-31 23:59:59.997").getTime(); - min = Timestamp.valueOf("1753-01-01 00:00:00.000").getTime(); - Timestamp[] Datetime = { new Timestamp(max), new Timestamp(min), new Timestamp(min) }; - - max = Timestamp.valueOf("9999-12-31 23:59:59").getTime(); - min = Timestamp.valueOf("0001-01-01 00:00:00").getTime(); - Timestamp[] Datetime2 = { new Timestamp(max), new Timestamp(min), new Timestamp(min) }; - - Float[] real = { Float.valueOf("3.4E38"), Float.valueOf("-3.4E38"), Float.valueOf("10.0") }; - - Short[] tinyint = { Short.valueOf("255"), Short.valueOf("0"), Short.valueOf("125") }; - - Double[] floatVal = { new Double(+1.79E308), new Double(-1.79E308), new Double(10.0) }; - - String[] text = { "text", "text", "text" }; - - String[] binary512 = { "0x" + toString(generateBinaryTypes("512", false)), - "0x" + toString(generateBinaryTypes("512", false)), - "0x" + toString(generateBinaryTypes("512", false)) }; - - Integer[] intVal = { new Integer(Integer.MAX_VALUE), new Integer(Integer.MIN_VALUE), 10 }; - - Long[] bigInt = { new Long(Long.MAX_VALUE), new Long(Long.MIN_VALUE), (long) 10 }; - - String[] nvarchar512 = { generateNCharTypes("512", false), generateNCharTypes("0", false), - generateNCharTypes("225", false) }; - - BigDecimal[] smallmoney = { new BigDecimal("214748.3647"), new BigDecimal("-214748.3648"), - new BigDecimal("10.0000") }; - - String[] bit = { "true", "false", "true" }; - - String[] varchar512 = { generateCharTypes("512", false), generateCharTypes("1", false), - generateCharTypes("225", false) }; - - tableValues = new ArrayList>(); - rowNumbers = 0; - - for (int i = 0; i < 3; i++) { - valuesPerRow = new ArrayList(); - - valuesPerRow.add(char512[i]); - valuesPerRow.add(date[i]); - valuesPerRow.add(decimal[i]); - valuesPerRow.add(money[i]); - valuesPerRow.add(time[i]); - valuesPerRow.add(guid[i]); - valuesPerRow.add(varcharMax[i]); - valuesPerRow.add(nVarcharMax[i]); - valuesPerRow.add(smallint[i]); - valuesPerRow.add(numeric[i]); - valuesPerRow.add(ntext[i]); - valuesPerRow.add(varbinaryMax[i]); - valuesPerRow.add(nchar512[i]); - valuesPerRow.add(dto[i]); - valuesPerRow.add(xml[i]); - valuesPerRow.add(smallDatetime[i]); - valuesPerRow.add(varbinary512[i]); - valuesPerRow.add(bit[i]); - valuesPerRow.add(varchar512[i]); - valuesPerRow.add(real[i]); - valuesPerRow.add(tinyint[i]); - valuesPerRow.add(floatVal[i]); - valuesPerRow.add(text[i]); - valuesPerRow.add(binary512[i]); - valuesPerRow.add(Datetime2[i]); - valuesPerRow.add((i + 1)); - valuesPerRow.add(Datetime[i]); - valuesPerRow.add(bigInt[i]); - valuesPerRow.add(nvarchar512[i]); - valuesPerRow.add(smallmoney[i]); - valuesPerRow.add(intVal[i]); - - tableValues.add(valuesPerRow); - rowNumbers++; - } - } - - public static ArrayList getTableValues(int index) { - return tableValues.get(index); - } - - private static String generateCharTypes(String columnLength, boolean nullable) { - String charSet = normalCharSet; - return buildCharOrNChar(columnLength, nullable, charSet, 8001); - } - - private static String generateNCharTypes(String columnLength, boolean nullable) { - String charSet = normalCharSet; - - return buildCharOrNChar(columnLength, nullable, charSet, 4001); - } - - private static String buildCharOrNChar(String columnLength, boolean nullable, String charSet, int maxBound) { - if (nullable) { - return null; - } - - int minimumLength = 0; - int length; - if (columnLength.toLowerCase().equals("max")) { - // 50% chance of return value longer than 8000/4000 - if (r.nextBoolean()) { - length = r.nextInt(100000) + maxBound; - return buildRandomString(length, charSet); - } else { - length = r.nextInt(maxBound - minimumLength) + minimumLength; - ; - return buildRandomString(length, charSet); - } - } else { - int columnLengthInt = Integer.parseInt(columnLength); - length = columnLengthInt; - return buildRandomString(length, charSet); - } - } - - private static String buildRandomString(int length, String charSet) { - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < length; i++) { - char c = pickRandomChar(charSet); - sb.append(c); - } - return sb.toString(); - } - - private static char pickRandomChar(String charSet) { - int charSetLength = charSet.length(); - int randomIndex = r.nextInt(charSetLength); - return charSet.charAt(randomIndex); - } - - public static byte[] generateBinaryTypes(String columnLength, boolean nullable) { - int maxBound = 8001; - - if (nullable) { - return null; - } - - int minimumLength = 0; - int length; - if (columnLength.toLowerCase().equals("max")) { - // 50% chance of return value longer than 8000/4000 - if (r.nextBoolean()) { - length = r.nextInt(100000) + maxBound; - byte[] bytes = new byte[length]; - r.nextBytes(bytes); - return bytes; - } else { - length = r.nextInt(maxBound - minimumLength) + minimumLength; - byte[] bytes = new byte[length]; - r.nextBytes(bytes); - return bytes; - } - } else { - int columnLengthInt = Integer.parseInt(columnLength); - length = columnLengthInt; - byte[] bytes = new byte[length]; - r.nextBytes(bytes); - return bytes; - } - } - - public static String toString(byte[] bytes) { - if (null == bytes) - return null; - - StringBuffer buffer = new StringBuffer(); - - // 0xFF => "FF" (it takes two characters to represent one byte) - for (int i = 0; i < bytes.length; i++) - toString(buffer, bytes[i]); - - return buffer.toString(); - } - - public static void toString(StringBuffer buffer, byte b) { - // 0xFF => "FF" (it takes two characters to represent one byte) - int i = b; - if (i < 0) - i = 256 + i; // Bytes are 'signed' in Java - - buffer.append(hexdigits[(i >> 4)]); - buffer.append(hexdigits[(i & 0xF)]); - } - - private static DateTimeOffset calculateDateTimeOffsetMinMax(String maxOrMin, Integer precision, String tsMinMax){ - int providedTimeZoneInMinutes; - if(maxOrMin.toLowerCase().equals("max")){ - providedTimeZoneInMinutes = 840; - } - else{ - providedTimeZoneInMinutes = -840; - } - - Timestamp tsMax = Timestamp.valueOf(tsMinMax); - - Calendar cal = Calendar.getInstance(); - long offset = cal.get(Calendar.ZONE_OFFSET); //in milliseconds - - //max Timestamp + difference of current time zone and GMT - provided time zone in milliseconds - tsMax = new Timestamp(tsMax.getTime() + offset - (providedTimeZoneInMinutes * 60 * 1000)); - - if(maxOrMin.toLowerCase().equals("max")){ - int precisionDigits = buildPrecision(precision, "9"); - tsMax.setNanos(precisionDigits); - } - - return microsoft.sql.DateTimeOffset.valueOf(tsMax, providedTimeZoneInMinutes); - } - - private static int buildPrecision(int precision, String charSet){ - String stringValue = calculatePrecisionDigits(precision, charSet); - return Integer.parseInt(stringValue); - } - - //setNanos(999999900) gives 00:00:00.9999999 - //so, this value has to be 9 digits - private static String calculatePrecisionDigits(int precision, String charSet){ - StringBuffer sb = new StringBuffer(); - for(int i = 0; i < precision; i++){ - char c = pickRandomChar(charSet); - sb.append(c); - } - - for(int i = sb.length(); i < 9; i++){ - sb.append("0"); - } - - return sb.toString(); - } - -} diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTest.java index a510f2e37..14fc4ebf2 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTest.java @@ -11,7 +11,6 @@ import static org.junit.Assert.assertTrue; import java.math.BigDecimal; -import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; @@ -19,20 +18,15 @@ import java.util.regex.Pattern; import org.junit.AfterClass; -import org.junit.BeforeClass; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.platform.runner.JUnitPlatform; import org.junit.runner.RunWith; -import com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement; -import com.microsoft.sqlserver.jdbc.bvt.bvt_ResultSet; -import com.microsoft.sqlserver.testframework.AbstractTest; import com.microsoft.sqlserver.testframework.DBConnection; import com.microsoft.sqlserver.testframework.DBPreparedStatement; import com.microsoft.sqlserver.testframework.DBResultSet; import com.microsoft.sqlserver.testframework.DBStatement; -import com.microsoft.sqlserver.testframework.DBTable; @RunWith(JUnitPlatform.class) @DisplayName("BVT Test") @@ -103,7 +97,6 @@ public void testCreateStatement() throws SQLException { try { conn = new DBConnection(connectionString); stmt = conn.createStatement(); - // SELECT * FROM String query = "SELECT * FROM " + table1.getEscapedTableName() + ";"; rs = stmt.executeQuery(query); rs.verify(table1); @@ -130,7 +123,6 @@ public void testCreateStatementWithQueryTimeout() throws SQLException { } finally { terminateVariation(); - } } @@ -273,11 +265,9 @@ public void testStmtScrollSensitiveUpdatable() throws SQLException { conn = new DBConnection(connectionString); stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); - // SELECT * FROM ORDER BY // DBResultSet.currentTable = table1; String query = "SELECT * FROM " + table1.getEscapedTableName(); rs = stmt.executeQuery(query); - // bvt_rs = new bvt_ResultSet(rs); // Verify resultset behavior rs.next(); @@ -337,7 +327,6 @@ public void testStmtSS_SEVER_CURSOR_FORWARD_ONLY() throws SQLException { conn = new DBConnection(connectionString); stmt = conn.createStatement(TYPE_SS_SEVER_CURSOR_FORWARD_ONLY, CONCUR_READ_ONLY); - // DBResultSet.currentTable = table1; String query = "SELECT * FROM " + table1.getEscapedTableName(); rs = stmt.executeQuery(query); @@ -361,13 +350,13 @@ public void testCreatepreparedStatement() throws SQLException { try { conn = new DBConnection(connectionString); String colName = table1.getColumnName(7); - String value = rs.getRow(0).get(7).toString(); + String value = DBResultSet.getRow(table1, 0).get(7).toString(); String query = "SELECT * from " + table1.getEscapedTableName() + " where [" + colName + "] = ? "; pstmt = conn.prepareStatement(query); pstmt.setObject(1, new BigDecimal(value)); - // + rs = pstmt.executeQuery(); rs.verify(table1); } @@ -385,7 +374,7 @@ public void testResultSet() throws SQLException { try { conn = new DBConnection(connectionString); stmt = conn.createStatement(); - // SELECT * FROM ORDER BY + String query = "SELECT * FROM " + table1.getEscapedTableName(); rs = stmt.executeQuery(query); @@ -404,7 +393,6 @@ public void testResultSet() throws SQLException { public void testResultSetAndClose() throws SQLException { try { - DBResultSet rs = null; conn = new DBConnection(connectionString); stmt = conn.createStatement(); @@ -436,8 +424,6 @@ public void testTwoResultsetsDifferentStmt() throws SQLException { stmt1 = conn.createStatement(); stmt2 = conn.createStatement(); - // SELECT * FROM ORDER BY - String query = "SELECT * FROM " + table1.getEscapedTableName(); rs1 = stmt1.executeQuery(query); rs1.currentTable = table1; @@ -488,11 +474,9 @@ public void testTwoResultsetsSameStmt() throws SQLException { conn = new DBConnection(connectionString); stmt = conn.createStatement(); - // SELECT * FROM ORDER BY String query = "SELECT * FROM " + table1.getEscapedTableName(); rs1 = stmt.executeQuery(query); - // SELECT * FROM ORDER BY String query2 = "SELECT * FROM " + table2.getEscapedTableName(); rs2 = stmt.executeQuery(query2); @@ -596,8 +580,6 @@ public static void terminateVariation() throws SQLException { rs.close(); if (null != stmt) stmt.close(); - // if (null != pstmt) - // pstmt.close(); } } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTestSetup.java b/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTestSetup.java index 6a3c91072..52f71d509 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTestSetup.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTestSetup.java @@ -1,11 +1,14 @@ -/** +/* + * Microsoft JDBC Driver for SQL Server + * + * Copyright(c) 2016 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.bvt; import java.sql.SQLException; -import org.junit.BeforeClass; import org.junit.jupiter.api.BeforeAll; import org.junit.platform.runner.JUnitPlatform; import org.junit.runner.RunWith; @@ -16,58 +19,39 @@ import com.microsoft.sqlserver.testframework.DBTable; /** - * @author v-afrafi - * + * + * Setting up the test */ @RunWith(JUnitPlatform.class) public class bvtTestSetup extends AbstractTest { private static DBConnection conn = null; private static DBStatement stmt = null; - + static DBTable table1; static DBTable table2; + @BeforeAll public static void init() throws SQLException { - // try { - // Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); - // } - // catch (ClassNotFoundException e) { - // e.printStackTrace(); - // } - - // Statement stmt = null; - try { - // stmt = conn().createStatement(); - conn = new DBConnection(connectionString); - stmt = conn.createStatement(); - - // create tables - table1 = new DBTable(true); - stmt.createTable(table1); - stmt.populateTable(table1); - table2 = new DBTable(true); - stmt.createTable(table2); - stmt.populateTable(table2); - - - // // CREATE the table - // stmt.executeUpdate(Tables.dropTable(table1)); - // stmt.executeUpdate(Tables.createTable(table1)); - // // CREATE the data to populate the table with - // Values.createData(); - // Tables.populate(table1, stmt); - // - // stmt.executeUpdate(Tables.dropTable(table2)); - // stmt.executeUpdate(Tables.createTable(table2)); - // Tables.populate(table2, stmt); - } - finally { - if (null != stmt) { - stmt.close(); - } -// terminateVariation(); - } - } + try { + conn = new DBConnection(connectionString); + stmt = conn.createStatement(); + // create tables + table1 = new DBTable(true); + stmt.createTable(table1); + stmt.populateTable(table1); + table2 = new DBTable(true); + stmt.createTable(table2); + stmt.populateTable(table2); + } + finally { + if (null != stmt) { + stmt.close(); + } + if (null != conn && !conn.isClosed()) { + conn.close(); + } + } + } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvt_ResultSet.java b/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvt_ResultSet.java deleted file mode 100644 index 9b6ce9588..000000000 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvt_ResultSet.java +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) 2016 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.bvt; -import static org.junit.Assert.fail; - -import java.math.BigDecimal; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.SQLException; -import java.util.ArrayList; - -public class bvt_ResultSet { - - private ResultSet rs; - private ResultSetMetaData metadata = null; - private int index; - - public bvt_ResultSet(ResultSet rs) { - this.rs = rs; - index = 0; - } - - public void setIndex(int index) { - this.index = index; - } - - public boolean next() throws SQLException { - boolean validrow = rs.next(); - if (validrow) - index++; - return (validrow); - } - - public boolean previous() throws SQLException { - boolean validrow = rs.previous(); - if (validrow) - index--; - return (validrow); - } - - public void afterLast() throws SQLException { - rs.afterLast(); - index = Values.getRowNumbers() + 1; - } - - public void close() throws SQLException { - rs.close(); - } - - public void absolute(int x) throws SQLException { - rs.absolute(x); - index = x; - } - - public void verify() throws SQLException { - - metadata = rs.getMetaData(); - metaData_Verify(); - - // Verify the data - while (next()) { - verifyCurrentRow(); - } - } - - private void metaData_Verify() { - - // getColumnCount - int columns; - try { - columns = metadata.getColumnCount(); - - // Loop through the columns - for (int i = 1; i <= columns; i++) { - // Note: Just calling these performs the verification, in each - // method - metadata.getColumnName(i); - metadata.getColumnType(i); - metadata.getColumnTypeName(i); - - // MetaData - metadata.getScale(i); - metadata.isCaseSensitive(i); - metadata.isAutoIncrement(i); - metadata.isCurrency(i); - metadata.isNullable(i); - metadata.isSigned(i); - - } - } catch (SQLException e) { - fail(e.toString()); - } - - } - - public void verifyCurrentRow() { - Class coercion = Object.class; - - ArrayList currentRow = Values.getTableValues(index - 1); - Object backendData = null; - - for (int i = 1; i <= currentRow.size(); i++) { - backendData = currentRow.get(i - 1); // currentRow is zero based - verifyData(i, coercion, backendData); - } - - } - - private void verifyData(int idx, Class coercion, Object backendData) { - - try { - // getXXX - default mapping - Object actual = getXXX(idx, coercion); - - // Verify - verifydata(backendData, actual, idx); - - } catch (SQLException e) { - fail(e.toString()); - } - - } - - private Object getXXX(int idx, Class coercion) throws SQLException { - if (coercion == Object.class) { - return rs.getObject(idx); - } - return null; - } - - private static void verifydata(Object backendData, Object actual, int idx) { - if (backendData != null) { - if (actual instanceof BigDecimal) { - if (((BigDecimal) actual).compareTo(new BigDecimal("" + backendData)) != 0) - fail(" Verification failed at index: " + idx + " , retrieved value: " + actual - + " , inserted value is " + backendData); - } else if (actual instanceof Float) { - if (Float.compare(new Float("" + backendData), (float) actual) != 0) - fail(" Verification failed at index: " + idx + " , retrieved value: " + actual - + " ,inserted value is " + backendData); - } else if (actual instanceof Double) { - if (Double.compare(new Double("" + backendData), (double) actual) != 0) - fail(" Verification failed at index: " + idx + " , retrieved value: " + actual - + " , inserted value is " + backendData); - } else if (actual instanceof byte[]) { - if (!parseByte((byte[]) actual).contains("" + backendData)) - fail(" Verification failed at index: " + idx + " , retrieved value: " + actual - + " , inserted value is " + backendData); - } else if (actual instanceof String) { - if (!(((String) actual).trim()).equalsIgnoreCase(((String) backendData).trim())) - fail(" Verification failed at index: " + idx + " , retrieved value: " + actual - + " , inserted value is " + backendData); - } else if (!(("" + actual).equalsIgnoreCase("" + backendData))) - fail(" Verification failed at index: " + idx + " , retrieved value: " + actual + " , inserted value is " - + backendData); - } - // if data is null - else { - if (actual != backendData) - fail(" Verification failed at index: " + idx + " , retrieved value: " + actual + " , inserted value is " - + backendData); - } - } - - private static String parseByte(byte[] bytes) { - StringBuffer parsedByte = new StringBuffer(); - parsedByte.append("0x"); - for (byte b : bytes) { - parsedByte.append(String.format("%02X", b)); - } - return parsedByte.toString(); - } - -} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBPreparedStatement.java b/src/test/java/com/microsoft/sqlserver/testframework/DBPreparedStatement.java index 501048981..8d6a5fc7c 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBPreparedStatement.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBPreparedStatement.java @@ -1,17 +1,38 @@ -/** - * - */ +// --------------------------------------------------------------------------------------------------------------------------------- +// File: DBPreparedStatement.java +// +// +// Microsoft JDBC Driver for SQL Server +// Copyright(c) Microsoft Corporation +// All rights reserved. +// MIT License +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), +// to deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, +// and / or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions : +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +// --------------------------------------------------------------------------------------------------------------------------------- + package com.microsoft.sqlserver.testframework; -import java.math.BigDecimal; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import com.microsoft.sqlserver.testframework.sqlType.SqlDateTimeOffset; + /** - * @author v-afrafi - * + * + * Wrapper class PreparedStatement */ public class DBPreparedStatement extends AbstractParentWrapper { @@ -32,7 +53,7 @@ public class DBPreparedStatement extends AbstractParentWrapper { * */ DBPreparedStatement prepareStatement(String query) throws SQLException { - pstmt = ( (Connection) product()).prepareStatement(query); + pstmt = ((Connection) product()).prepareStatement(query); setInternal(pstmt); return this; } @@ -45,34 +66,25 @@ void setInternal(Object internal) { /** * @param i * @param bigDecimal - * @throws SQLException + * @throws SQLException */ public void setObject(int parameterIndex, Object targetObject) throws SQLException { ((PreparedStatement) product()).setObject(parameterIndex, targetObject); } - - public DBResultSet executeQuery() throws SQLException - { - ResultSet rs = null; - rs = pstmt.executeQuery(); - dbresultSet = new DBResultSet(this, rs); -// DBResultSet product = ((PreparedStatement) product()).executeQuery(); - return dbresultSet; - + + /** + * + * @return + * @throws SQLException + */ + public DBResultSet executeQuery() throws SQLException { + ResultSet rs = null; + rs = pstmt.executeQuery(); + dbresultSet = new DBResultSet(this, rs); + return dbresultSet; + } -// //Used to return the appropriate object given the framework wrapper -// public Object getTargetObject(Object value) -// { -// if(value instanceof sqlDateTimeOffset) -// { -// return ((DBDateTimeOffset)value).product(); -// } -// else -// { -// return value; -// } -// } } diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java index 525f35f4a..9a2b1b93e 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java @@ -25,21 +25,23 @@ package com.microsoft.sqlserver.testframework; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + import java.math.BigDecimal; -import java.sql.Date; import java.sql.JDBCType; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Time; import java.sql.Timestamp; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.Calendar; -import com.sun.org.apache.xpath.internal.operations.Bool; - -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; +import microsoft.sql.DateTimeOffset; /** * wrapper class for ResultSet @@ -52,25 +54,23 @@ public class DBResultSet extends AbstractParentWrapper { // TODO: add cursors // TODO: add resultSet level holdability // TODO: add concurrency control - public DBTable currentTable; + public DBTable currentTable; public static final int VERIFY_MOVERS_NEXT = 0x100; public int _currentrow = -1; // The row this rowset is currently pointing to ResultSet resultSet = null; DBResultSetMetaData metaData; - + DBResultSet(DBStatement dbstatement, ResultSet internal) { super(dbstatement, internal, "resultSet"); resultSet = internal; } - + DBResultSet(DBPreparedStatement dbpstmt, ResultSet internal) { super(dbpstmt, internal, "resultSet"); resultSet = internal; } - - /** * Close the ResultSet object * @@ -88,7 +88,7 @@ public void close() throws SQLException { * @throws SQLException */ public boolean next() throws SQLException { -// if(_currentrow < DBTa) + // if(_currentrow < DBTa) _currentrow++; return resultSet.next(); } @@ -112,7 +112,7 @@ public Object getObject(int index) throws SQLException { public void updateObject(int index) throws SQLException { // TODO: update object based on cursor type } - + /** * * @throws SQLException @@ -125,34 +125,39 @@ public void verify(DBTable table) throws SQLException { while (this.next()) this.verifyCurrentRow(table); } - + /** - * @throws SQLException + * @throws SQLException * */ - public void verifyCurrentRow(DBTable table) throws SQLException{ + public void verifyCurrentRow(DBTable table) throws SQLException { currentTable = table; int totalColumns = ((ResultSet) product()).getMetaData().getColumnCount(); - + Class _class = Object.class; - for ( int i=0; i< totalColumns; i++) + for (int i = 0; i < totalColumns; i++) verifydata(i, _class, null); - + } - - public void verifydata(int ordinal, Class coercion, Object arg) throws SQLException - { - Object backendData = this.currentrow().get(ordinal); - - //getXXX - default mapping - Object retrieved = this.getXXX(ordinal +1 , coercion); - - //Verify - verifydata(ordinal, coercion, backendData, retrieved); + + /** + * + * @param ordinal + * @param coercion + * @param arg + * @throws SQLException + */ + public void verifydata(int ordinal, Class coercion, Object arg) throws SQLException { + Object backendData = this.currentrow().get(ordinal); + + // getXXX - default mapping + Object retrieved = this.getXXX(ordinal + 1, coercion); + + // Verify + verifydata(ordinal, coercion, backendData, retrieved); } - - public void verifydata(int ordinal, Class coercion, Object backendData, Object retrieved) throws SQLException - { + + public void verifydata(int ordinal, Class coercion, Object backendData, Object retrieved) throws SQLException { metaData = this.getMetaData(); switch (metaData.getColumnType(ordinal + 1)) { case java.sql.Types.BIGINT: @@ -171,14 +176,14 @@ public void verifydata(int ordinal, Class coercion, Object backendData, Object r case java.sql.Types.BIT: if (backendData.equals(1)) backendData = true; - else backendData = false; - assertTrue(( (((Boolean) backendData)).booleanValue() == ((Boolean) retrieved).booleanValue()), "Unexpected bit value"); + else + backendData = false; + assertTrue(((((Boolean) backendData)).booleanValue() == ((Boolean) retrieved).booleanValue()), "Unexpected bit value"); break; case java.sql.Types.DECIMAL: case java.sql.Types.NUMERIC: - assertTrue(0 == (((BigDecimal) backendData).compareTo((BigDecimal) retrieved)), - "Unexpected decimal/numeric/money/smallmoney value"); + assertTrue(0 == (((BigDecimal) backendData).compareTo((BigDecimal) retrieved)), "Unexpected decimal/numeric/money/smallmoney value"); break; case java.sql.Types.DOUBLE: @@ -191,108 +196,72 @@ public void verifydata(int ordinal, Class coercion, Object backendData, Object r case java.sql.Types.VARCHAR: case java.sql.Types.NVARCHAR: - System.out.println("-----> b: "+ backendData.toString().trim()); - System.out.println("-----> r: " + retrieved.toString().trim()); - System.out.println(backendData.toString().trim().equalsIgnoreCase(retrieved.toString().trim())); - assertTrue((((String) backendData).equals((String) retrieved)), "Unexpected varchar/nvarchar value "); + assertTrue((((String) backendData).trim().equalsIgnoreCase(((String) retrieved).trim())), "Unexpected varchar/nvarchar value "); break; case java.sql.Types.CHAR: case java.sql.Types.NCHAR: -// assertTrue((((String) backendData).trim().equalsIgnoreCase(((String) retrieved).trim())), "Unexpected char/nchar value "); + + assertTrue((((String) backendData).trim().equalsIgnoreCase(((String) retrieved).trim())), "Unexpected char/nchar value "); break; case java.sql.Types.TIMESTAMP: - if (metaData.getColumnTypeName(ordinal +1).equalsIgnoreCase("datetime")) - { - assertTrue((((Timestamp) roundDatetimeValue(backendData) ).getTime() == (((Timestamp) retrieved).getTime())), + if (metaData.getColumnTypeName(ordinal + 1).equalsIgnoreCase("datetime")) { + assertTrue((((Timestamp) roundDatetimeValue(backendData)).getTime() == (((Timestamp) retrieved).getTime())), "Unexpected datetime value"); break; } - else if (metaData.getColumnTypeName(ordinal +1).equalsIgnoreCase("smalldatetime")) - { - assertTrue((((Timestamp) roundSmallDateTimeValue(backendData) ).getTime() == (((Timestamp) retrieved).getTime())), + else if (metaData.getColumnTypeName(ordinal + 1).equalsIgnoreCase("smalldatetime")) { + assertTrue((((Timestamp) roundSmallDateTimeValue(backendData)).getTime() == (((Timestamp) retrieved).getTime())), "Unexpected smalldatetime value"); break; } - else -// assertTrue((""+ ((java.util.Date) backendData).getTime()).equalsIgnoreCase("" +retrieved.getTime()), -// "Unexpected datetime2 value"); + else + assertTrue(("" + Timestamp.valueOf((LocalDateTime) backendData)).equalsIgnoreCase("" + retrieved), "Unexpected datetime2 value"); break; case java.sql.Types.DATE: - assertTrue((("" +backendData).equalsIgnoreCase(""+ retrieved)), "Unexpected date value"); + assertTrue((("" + backendData).equalsIgnoreCase("" + retrieved)), "Unexpected date value"); break; case java.sql.Types.TIME: -// assertTrue((backendData) == ((Time) retrieved).getTime(), "Unexpected time value "); + assertTrue(("" + Time.valueOf((LocalTime) backendData)).equalsIgnoreCase("" + retrieved), "Unexpected time value "); break; case microsoft.sql.Types.DATETIMEOFFSET: -// assertTrue(0 == ((microsoft.sql.DateTimeOffset) backendData).compareTo((microsoft.sql.DateTimeOffset) retrieved), -// "Unexpected time value "); + assertTrue( + (("" + Timestamp.valueOf(((OffsetDateTime) backendData).toLocalDateTime())) + " " + + ((OffsetDateTime) backendData).getOffset()).equalsIgnoreCase("" + (DateTimeOffset) retrieved), + " unexpected DATETIMEOFFSET value"); break; default: fail("Unhandled JDBCType " + JDBCType.valueOf(metaData.getColumnType(ordinal + 1))); break; } - -// if (backendData != null) { -// if (retrieved instanceof BigDecimal) { -// if (((BigDecimal) retrieved).compareTo(new BigDecimal("" + backendData)) != 0) -// fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved -// + " , inserted value is " + backendData); -// -// } else if (retrieved instanceof Float) { -// if (Float.compare(new Float("" + backendData), (float) retrieved) != 0) -// fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved -// + " ,inserted value is " + backendData); -// } else if (retrieved instanceof Double) { -// if (Double.compare(new Double("" + backendData), (double) retrieved) != 0) -// fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved -// + " , inserted value is " + backendData); -// } else if (retrieved instanceof byte[]) { -// if (!parseByte((byte[]) retrieved).contains("" + backendData)) -// fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved -// + " , inserted value is " + backendData); -// } else if (retrieved instanceof String) { -// if (!(((String) retrieved).trim()).equalsIgnoreCase(((String) backendData).trim())) -// fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved -// + " , inserted value is " + backendData); -// } else if (retrieved instanceof Boolean) { -// if ( retrieved.equals(true) && !backendData.equals(1)) -// { -// fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved -// + " , inserted value is " + backendData); -// } -// else if ( retrieved.equals(false) && !backendData.equals(0)) -// { -// fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved -// + " , inserted value is " + backendData); -// } -// } else if (!(("" + retrieved).equalsIgnoreCase("" + backendData))) -// fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved + " , inserted value is " -// + backendData); -// } -// // if data is null -// else { -// if (retrieved != backendData) -// fail(" Verification failed at index: " + ordinal + " , retrieved value: " + retrieved + " , inserted value is " -// + backendData); -// } - + } - - - public ArrayList currentrow(){ - return currentTable.getAllRows().get(_currentrow ); + + /** + * Retrieves the current row of the table + * + * @return + */ + public ArrayList currentrow() { + return currentTable.getAllRows().get(_currentrow); } - - public ArrayList getRow(int index){ - return currentTable.getAllRows().get(index ); + + /** + * Get the indexed row from the backend data for the specific table + * + * @param table + * @param index + * @return + */ + public static ArrayList getRow(DBTable table, int index) { + return table.getAllRows().get(index); } - + private Object getXXX(int idx, Class coercion) throws SQLException { if (coercion == Object.class) { return this.getObject(idx); @@ -317,66 +286,55 @@ public DBResultSetMetaData getMetaData() { return wrapper; } - + /** * * @return * @throws SQLException */ - public int getRow() throws SQLException - { + public int getRow() throws SQLException { int product = ((ResultSet) product()).getRow(); return product; } - + /** * * @return * @throws SQLException */ - public boolean previous() throws SQLException - { - + public boolean previous() throws SQLException { + boolean validrow = ((ResultSet) product()).previous(); - if (_currentrow > 0) - { + if (_currentrow > 0) { _currentrow--; - } + } return (validrow); } - + /** * * @throws SQLException */ - public void afterLast() throws SQLException - { + public void afterLast() throws SQLException { ((ResultSet) product()).afterLast(); - _currentrow = DBTable.getTotalRows() ; + _currentrow = DBTable.getTotalRows(); } - - public boolean absolute(int x) throws SQLException - { - boolean validrow = ((ResultSet) product()).absolute(x); - _currentrow = x-1; + + /** + * + * @param x + * @return + * @throws SQLException + */ + public boolean absolute(int x) throws SQLException { + boolean validrow = ((ResultSet) product()).absolute(x); + _currentrow = x - 1; return validrow; } - private static String parseByte(byte[] bytes) { - StringBuffer parsedByte = new StringBuffer(); - parsedByte.append("0x"); - for (byte b : bytes) { - parsedByte.append(String.format("%02X", b)); - } - return parsedByte.toString(); - } - - - public static Object roundSmallDateTimeValue(Object value) - { - if(value == null) - { + private static Object roundSmallDateTimeValue(Object value) { + if (value == null) { return null; } @@ -384,85 +342,85 @@ public static Object roundSmallDateTimeValue(Object value) java.sql.Timestamp ts = null; int nanos = -1; - if(value instanceof Calendar) - { - cal = (Calendar)value; + if (value instanceof Calendar) { + cal = (Calendar) value; } - else - { - ts = (java.sql.Timestamp)value; + else { + ts = (java.sql.Timestamp) value; cal = Calendar.getInstance(); cal.setTimeInMillis(ts.getTime()); nanos = ts.getNanos(); } - //round to the nearest minute - double seconds = cal.get(Calendar.SECOND) + (nanos == -1 ? ((double)cal.get(Calendar.MILLISECOND) / 1000) : ((double)nanos / 1000000000)); - if(seconds > 29.998) - { + // round to the nearest minute + double seconds = cal.get(Calendar.SECOND) + (nanos == -1 ? ((double) cal.get(Calendar.MILLISECOND) / 1000) : ((double) nanos / 1000000000)); + if (seconds > 29.998) { cal.set(Calendar.MINUTE, cal.get(Calendar.MINUTE) + 1); } cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); nanos = 0; - //required to force computation + // required to force computation cal.getTimeInMillis(); - //return appropriate value - if(value instanceof Calendar) - { + // return appropriate value + if (value instanceof Calendar) { return cal; } - else - { + else { ts.setTime(cal.getTimeInMillis()); ts.setNanos(nanos); return ts; } } - - public static Object roundDatetimeValue(Object value) - { - if(value == null) + + private static Object roundDatetimeValue(Object value) { + if (value == null) return null; - Timestamp ts = value instanceof Timestamp ? (Timestamp)value : new Timestamp(((Calendar)value).getTimeInMillis()); + Timestamp ts = value instanceof Timestamp ? (Timestamp) value : new Timestamp(((Calendar) value).getTimeInMillis()); int millis = ts.getNanos() / 1000000; - int lastDigit = (int)(millis % 10); - switch(lastDigit) - { - //0, 1 -> 0 - case 1: ts.setNanos((millis - 1) * 1000000); - break; - - //2, 3, 4 -> 3 - case 2: ts.setNanos((millis + 1) * 1000000); - break; - case 4: ts.setNanos((millis - 1) * 1000000); - break; - - //5, 6, 7, 8 -> 7 - case 5: ts.setNanos((millis + 2) * 1000000); - break; - case 6: ts.setNanos((millis + 1) * 1000000); - break; - case 8: ts.setNanos((millis - 1) * 1000000); - break; - - //9 -> 0 with overflow - case 9: ts.setNanos(0); - ts.setTime(ts.getTime() + millis + 1); - break; - - //default, i.e. 0, 3, 7 -> 0, 3, 7 - //don't change the millis but make sure that any - //sub-millisecond digits are zeroed out - default: ts.setNanos((millis) * 1000000); + int lastDigit = (int) (millis % 10); + switch (lastDigit) { + // 0, 1 -> 0 + case 1: + ts.setNanos((millis - 1) * 1000000); + break; + + // 2, 3, 4 -> 3 + case 2: + ts.setNanos((millis + 1) * 1000000); + break; + case 4: + ts.setNanos((millis - 1) * 1000000); + break; + + // 5, 6, 7, 8 -> 7 + case 5: + ts.setNanos((millis + 2) * 1000000); + break; + case 6: + ts.setNanos((millis + 1) * 1000000); + break; + case 8: + ts.setNanos((millis - 1) * 1000000); + break; + + // 9 -> 0 with overflow + case 9: + ts.setNanos(0); + ts.setTime(ts.getTime() + millis + 1); + break; + + // default, i.e. 0, 3, 7 -> 0, 3, 7 + // don't change the millis but make sure that any + // sub-millisecond digits are zeroed out + default: + ts.setNanos((millis) * 1000000); } - if(value instanceof Calendar) - { - ((Calendar)value).setTimeInMillis(ts.getTime()); - ((Calendar)value).getTimeInMillis(); + if (value instanceof Calendar) { + ((Calendar) value).setTimeInMillis(ts.getTime()); + ((Calendar) value).getTimeInMillis(); return value; } return ts; diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetMetaData.java b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetMetaData.java index 7ed1e2baa..e5b29fbb0 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetMetaData.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetMetaData.java @@ -32,7 +32,7 @@ import com.microsoft.sqlserver.jdbc.SQLServerResultSetMetaData; /** - * @author v-afrafi + * * */ public class DBResultSetMetaData extends AbstractParentWrapper { @@ -67,7 +67,6 @@ public void verify() throws SQLException { this.isCurrency(i); this.isNullable(i); this.isSigned(i); - } } diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java b/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java index d21a82711..39734b03e 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java @@ -254,19 +254,14 @@ String populateTableSql() { // TODO: add betterway to enclose data if (JDBCType.CHAR == getColumn(colNum).getSqlType().getJdbctype() || JDBCType.VARCHAR == getColumn(colNum).getSqlType().getJdbctype() -// || JDBCType.NCHAR == getColumn(colNum).getSqlType().getJdbctype() -// || JDBCType.NVARCHAR == getColumn(colNum).getSqlType().getJdbctype() + || JDBCType.NCHAR == getColumn(colNum).getSqlType().getJdbctype() + || JDBCType.NVARCHAR == getColumn(colNum).getSqlType().getJdbctype() || JDBCType.TIMESTAMP == getColumn(colNum).getSqlType().getJdbctype() || JDBCType.DATE == getColumn(colNum).getSqlType().getJdbctype() || JDBCType.TIME == getColumn(colNum).getSqlType().getJdbctype()) { sb.add("'" + String.valueOf(getColumn(colNum).getRowValue(i)) + "'"); currentrow.add(getColumn(colNum).getRowValue(i)); } - else if (JDBCType.NCHAR == getColumn(colNum).getSqlType().getJdbctype() - || JDBCType.NVARCHAR == getColumn(colNum).getSqlType().getJdbctype()) { - sb.add("N'" + String.valueOf(getColumn(colNum).getRowValue(i)) + "'"); - currentrow.add(getColumn(colNum).getRowValue(i)); - } else { sb.add(String.valueOf(getColumn(colNum).getRowValue(i))); currentrow.add(getColumn(colNum).getRowValue(i)); diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlChar.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlChar.java index 536eb3694..a75b61a4a 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlChar.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlChar.java @@ -38,6 +38,7 @@ */ public class SqlChar extends SqlType { + private static String normalCharSet = "1234567890-=!@#$%^&*()_+qwertyuiop[]\\asdfghjkl;'zxcvbnm,./QWERTYUIOP{}|ASDFGHJKL:\"ZXCVBNM<>?"; public SqlChar() { this("char", JDBCType.CHAR, 4000); } @@ -50,13 +51,13 @@ public SqlChar() { public Object createdata() { int dataLength = ThreadLocalRandom.current().nextInt(precision); - String str = RandomStringUtils.randomAscii(dataLength); + String str = generateCharTypes(dataLength); String newStr = str.replace("'", ""); -// System.out.println("str " +str); -// System.out.println("new " +newStr); return newStr; -// return (RandomStringUtils.randomAscii(dataLength).replace("'", "\\'")); -// return StringEscapeUtils.escapeSql(RandomStringUtils.randomAscii(dataLength)); + } + private static String generateCharTypes(int columnLength) { + String charSet = normalCharSet; + return buildCharOrNChar(columnLength, charSet); } } \ No newline at end of file diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNChar.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNChar.java index d3710ea91..623034f7e 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNChar.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNChar.java @@ -31,6 +31,7 @@ import org.apache.commons.lang.StringEscapeUtils; public class SqlNChar extends SqlChar { + private static String normalCharSet = "1234567890-=!@#$%^&*()_+qwertyuiop[]\\asdfghjkl;'zxcvbnm,./QWERTYUIOP{}|ASDFGHJKL:\"ZXCVBNM<>?"; SqlNChar(String name, JDBCType jdbctype, int precision) { super(name, jdbctype, precision); @@ -42,23 +43,13 @@ public SqlNChar() { public Object createdata() { int dataLength = ThreadLocalRandom.current().nextInt(precision); - /* - * Just supporting Latin character sets for now, as the entire valid - * code point Character.MIN_CODE_POINT to Character.MAX_CODE_POINT has - * many unassigned code points. - * - * CodePoints Used: Basic Latin, Latin-1 Supplement, Latin Extended-A, - * Latin Extended-B - */ - int minCodePoint = 0x000; - int maxCodePoint = 0x24F; - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < dataLength; i++) { - // TODO: need to remove uassigned - int rand = ThreadLocalRandom.current().nextInt(minCodePoint, maxCodePoint); - char c = (char) rand; - sb.append(c); - } - return StringEscapeUtils.escapeSql(sb.toString()); + String str = generateCharTypes(dataLength); + String newStr = str.replace("'", ""); + return newStr; + } + + private static String generateCharTypes(int columnLength) { + String charSet = normalCharSet; + return buildCharOrNChar(columnLength, charSet); } } \ No newline at end of file diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlType.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlType.java index 153bea24f..c3f2bbbcd 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlType.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlType.java @@ -26,6 +26,7 @@ package com.microsoft.sqlserver.testframework.sqlType; import java.sql.JDBCType; +import java.util.Random; import java.util.concurrent.ThreadLocalRandom; public abstract class SqlType { @@ -39,7 +40,7 @@ public abstract class SqlType { protected Object maxvalue = null; protected Object nullvalue = null; // Primitives have non-null defaults protected VariableLengthType variableLengthType; - + static Random r = new Random(); /** * * @param name @@ -180,4 +181,35 @@ void generatePrecision() { int maxPrecision = this.precision; this.precision = ThreadLocalRandom.current().nextInt(minPrecision, maxPrecision + 1); } + + /** + * generate char or nchar values + * @param columnLength + * @param charSet + * @return + */ + protected static String buildCharOrNChar(int columnLength, String charSet) { + + int length; + + int columnLengthInt = columnLength; + length = columnLengthInt; + return buildRandomString(length, charSet); + + } + + private static String buildRandomString(int length, String charSet) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < length; i++) { + char c = pickRandomChar(charSet); + sb.append(c); + } + return sb.toString(); + } + + private static char pickRandomChar(String charSet) { + int charSetLength = charSet.length(); + int randomIndex = r.nextInt(charSetLength); + return charSet.charAt(randomIndex); + } } From ef04a4be6b3a31c3c625b3a00cca150c6f9be149 Mon Sep 17 00:00:00 2001 From: v-afrafi Date: Tue, 17 Jan 2017 13:43:02 -0800 Subject: [PATCH 06/28] removed comment --- .../java/com/microsoft/sqlserver/testframework/DBResultSet.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java index 9a2b1b93e..fccb738c7 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java @@ -88,7 +88,6 @@ public void close() throws SQLException { * @throws SQLException */ public boolean next() throws SQLException { - // if(_currentrow < DBTa) _currentrow++; return resultSet.next(); } From f3a9b51b461487ae4221ed08d0495369232486ee Mon Sep 17 00:00:00 2001 From: v-afrafi Date: Tue, 17 Jan 2017 13:55:26 -0800 Subject: [PATCH 07/28] removed unused variables --- .../testframework/DBPreparedStatement.java | 4 +--- .../sqlserver/testframework/DBResultSet.java | 1 - .../sqlserver/testframework/DBStatement.java | 3 --- .../sqlserver/testframework/DBTable.java | 2 +- .../testframework/sqlType/SqlType.java | 19 ++++++++----------- 5 files changed, 10 insertions(+), 19 deletions(-) diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBPreparedStatement.java b/src/test/java/com/microsoft/sqlserver/testframework/DBPreparedStatement.java index 8d6a5fc7c..4c18ecc45 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBPreparedStatement.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBPreparedStatement.java @@ -32,7 +32,7 @@ /** * - * Wrapper class PreparedStatement + * Wrapper class PreparedStatement */ public class DBPreparedStatement extends AbstractParentWrapper { @@ -71,7 +71,6 @@ void setInternal(Object internal) { public void setObject(int parameterIndex, Object targetObject) throws SQLException { ((PreparedStatement) product()).setObject(parameterIndex, targetObject); - } /** @@ -84,7 +83,6 @@ public DBResultSet executeQuery() throws SQLException { rs = pstmt.executeQuery(); dbresultSet = new DBResultSet(this, rs); return dbresultSet; - } } diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java index fccb738c7..07002a2ed 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java @@ -55,7 +55,6 @@ public class DBResultSet extends AbstractParentWrapper { // TODO: add resultSet level holdability // TODO: add concurrency control public DBTable currentTable; - public static final int VERIFY_MOVERS_NEXT = 0x100; public int _currentrow = -1; // The row this rowset is currently pointing to ResultSet resultSet = null; diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBStatement.java b/src/test/java/com/microsoft/sqlserver/testframework/DBStatement.java index 24f1126af..b8950d148 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBStatement.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBStatement.java @@ -46,9 +46,6 @@ public class DBStatement extends AbstractParentWrapper { Statement statement = null; DBResultSet dbresultSet = null; - public int _cursortype = ResultSet.TYPE_FORWARD_ONLY; - public int _concurrency = ResultSet.CONCUR_READ_ONLY; - public int _holdability = ResultSet.CLOSE_CURSORS_AT_COMMIT; DBStatement(DBConnection dbConnection) { super(dbConnection, null, "statement"); diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java b/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java index 39734b03e..11a52d974 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java @@ -49,7 +49,7 @@ public class DBTable extends AbstractSQLGenerator { String escapedTableName; List columns; int totalColumns; - static int totalRows = 3; // default row count set to 2 + static int totalRows = 3; // default row count set to 3 DBSchema schema; ArrayList> rows; ArrayList currentrow; diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlType.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlType.java index c3f2bbbcd..81783baa7 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlType.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlType.java @@ -41,6 +41,7 @@ public abstract class SqlType { protected Object nullvalue = null; // Primitives have non-null defaults protected VariableLengthType variableLengthType; static Random r = new Random(); + /** * * @param name @@ -56,8 +57,8 @@ public abstract class SqlType { * @param variableLengthType * {@link VariableLengthType} */ - SqlType(String name, JDBCType jdbctype, int precision, int scale, Object min, Object max, - Object nullvalue, VariableLengthType variableLengthType) { + SqlType(String name, JDBCType jdbctype, int precision, int scale, Object min, Object max, Object nullvalue, + VariableLengthType variableLengthType) { this.name = name; this.jdbctype = jdbctype; this.precision = precision; @@ -181,23 +182,19 @@ void generatePrecision() { int maxPrecision = this.precision; this.precision = ThreadLocalRandom.current().nextInt(minPrecision, maxPrecision + 1); } - + /** * generate char or nchar values + * * @param columnLength * @param charSet * @return */ protected static String buildCharOrNChar(int columnLength, String charSet) { - - int length; - - int columnLengthInt = columnLength; - length = columnLengthInt; - return buildRandomString(length, charSet); - + int columnLengthInt = columnLength; + return buildRandomString(columnLengthInt, charSet); } - + private static String buildRandomString(int length, String charSet) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < length; i++) { From 315e8ae7716b3ae1854783844f8fad333a62114a Mon Sep 17 00:00:00 2001 From: v-afrafi Date: Tue, 17 Jan 2017 15:00:36 -0800 Subject: [PATCH 08/28] update to DBResultSet --- .../com/microsoft/sqlserver/testframework/DBResultSet.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java index 07002a2ed..f27319f25 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java @@ -230,7 +230,8 @@ else if (metaData.getColumnTypeName(ordinal + 1).equalsIgnoreCase("smalldatetime assertTrue( (("" + Timestamp.valueOf(((OffsetDateTime) backendData).toLocalDateTime())) + " " + ((OffsetDateTime) backendData).getOffset()).equalsIgnoreCase("" + (DateTimeOffset) retrieved), - " unexpected DATETIMEOFFSET value"); + " unexpected DATETIMEOFFSET value, expected: " + ("" + Timestamp.valueOf(((OffsetDateTime) backendData).toLocalDateTime())) + " " + + ((OffsetDateTime) backendData).getOffset() + " .Retrieved: " + (DateTimeOffset) retrieved ); break; default: From 22e9eafc132f38460a08368c566be8d6176ddb7e Mon Sep 17 00:00:00 2001 From: v-xiangs Date: Tue, 17 Jan 2017 16:58:27 -0800 Subject: [PATCH 09/28] when socket timeout occured, do not try the second round --- .../java/com/microsoft/sqlserver/jdbc/IOBuffer.java | 10 ++++++++-- .../microsoft/sqlserver/jdbc/SQLServerConnection.java | 1 + .../microsoft/sqlserver/jdbc/SQLServerException.java | 1 + 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java b/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java index 9da033093..4370e50a1 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java @@ -2009,8 +2009,14 @@ final int read(byte[] data, int offset, int length) throws SQLServerException { if (logger.isLoggable(Level.FINE)) logger.fine(toString() + " read failed:" + e.getMessage()); - - con.terminate(SQLServerException.DRIVER_ERROR_IO_FAILED, e.getMessage()); + + if (e instanceof SocketTimeoutException) { + con.terminate(SQLServerException.ERROR_SOCKET_TIMEOUT, e.getMessage()); + } + else { + con.terminate(SQLServerException.DRIVER_ERROR_IO_FAILED, e.getMessage()); + } + return 0; // Keep the compiler happy. } } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java index 217746a99..c1a03f7dd 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java @@ -1806,6 +1806,7 @@ else if(null == currentPrimaryPlaceHolder) || (SQLServerException.DRIVER_ERROR_SSL_FAILED == sqlex.getDriverErrorCode()) // failure negotiating SSL || (SQLServerException.DRIVER_ERROR_INTERMITTENT_TLS_FAILED == sqlex.getDriverErrorCode()) // failure TLS1.2 || (SQLServerException.DRIVER_ERROR_UNSUPPORTED_CONFIG == sqlex.getDriverErrorCode()) // unsupported configuration (e.g. Sphinx, invalid packet size, etc.) + || (SQLServerException.ERROR_SOCKET_TIMEOUT == sqlex.getDriverErrorCode()) //socket timeout ocurred || timerHasExpired(timerExpire)// no more time to try again || (state.equals(State.Connected)&& !isDBMirroring) //for non-dbmirroring cases, do not retry after tcp socket connection succeeds diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerException.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerException.java index e6e2aa0e2..99b8bfd5e 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerException.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerException.java @@ -79,6 +79,7 @@ public final class SQLServerException extends java.sql.SQLException static final int DRIVER_ERROR_SSL_FAILED = 5; static final int DRIVER_ERROR_UNSUPPORTED_CONFIG = 6; static final int DRIVER_ERROR_INTERMITTENT_TLS_FAILED = 7; + static final int ERROR_SOCKET_TIMEOUT = 8; private int driverErrorCode = DRIVER_ERROR_NONE; final int getDriverErrorCode() { return driverErrorCode; } final void setDriverErrorCode(int value) { driverErrorCode = value; } From c8b488077fe4455b7211b1e900dee35ff60eaa76 Mon Sep 17 00:00:00 2001 From: v-afrafi Date: Wed, 18 Jan 2017 13:10:45 -0800 Subject: [PATCH 10/28] updates to sqlType and datetimeoffset creation --- .../sqlserver/testframework/DBResultSet.java | 51 +++--- .../sqlserver/testframework/DBStatement.java | 18 +- .../testframework/sqlType/SqlChar.java | 34 +++- .../sqlType/SqlDateTimeOffset.java | 165 ++++++++++++------ .../testframework/sqlType/SqlNChar.java | 10 +- .../testframework/sqlType/SqlType.java | 26 --- .../testframework/sqlType/SqlTypeValue.java | 2 +- 7 files changed, 186 insertions(+), 120 deletions(-) diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java index f27319f25..c0352509a 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java @@ -159,16 +159,19 @@ public void verifydata(int ordinal, Class coercion, Object backendData, Object r metaData = this.getMetaData(); switch (metaData.getColumnType(ordinal + 1)) { case java.sql.Types.BIGINT: - assertTrue((((Long) backendData).longValue() == ((Long) retrieved).longValue()), "Unexpected bigint value"); + assertTrue((((Long) backendData).longValue() == ((Long) retrieved).longValue()), + "Unexpected bigint value, expected: " + ((Long) backendData).longValue() + " .Retrieved: " + ((Long) retrieved).longValue()); break; case java.sql.Types.INTEGER: - assertTrue((((Integer) backendData).intValue() == ((Integer) retrieved).intValue()), "Unexpected int value"); + assertTrue((((Integer) backendData).intValue() == ((Integer) retrieved).intValue()), + "Unexpected int value, expected : " + ((Integer) backendData).intValue() + " ,received: " + ((Integer) retrieved).intValue()); break; case java.sql.Types.SMALLINT: case java.sql.Types.TINYINT: - assertTrue((((Short) backendData).shortValue() == ((Short) retrieved).shortValue()), "Unexpected smallint/tinyint value"); + assertTrue((((Short) backendData).shortValue() == ((Short) retrieved).shortValue()), "Unexpected smallint/tinyint value, expected: " + + " " + ((Short) backendData).shortValue() + " received: " + ((Short) retrieved).shortValue()); break; case java.sql.Types.BIT: @@ -176,69 +179,75 @@ public void verifydata(int ordinal, Class coercion, Object backendData, Object r backendData = true; else backendData = false; - assertTrue(((((Boolean) backendData)).booleanValue() == ((Boolean) retrieved).booleanValue()), "Unexpected bit value"); + assertTrue((((Boolean) backendData).booleanValue() == ((Boolean) retrieved).booleanValue()), "Unexpected bit value, expected: " + + ((Boolean) backendData).booleanValue() + " ,received: " + ((Boolean) retrieved).booleanValue()); break; case java.sql.Types.DECIMAL: case java.sql.Types.NUMERIC: - assertTrue(0 == (((BigDecimal) backendData).compareTo((BigDecimal) retrieved)), "Unexpected decimal/numeric/money/smallmoney value"); + assertTrue(0 == (((BigDecimal) backendData).compareTo((BigDecimal) retrieved)), "Unexpected decimal/numeric/money/smallmoney value " + + ",expected: " + (BigDecimal) backendData + " received: " + (BigDecimal) retrieved); break; case java.sql.Types.DOUBLE: - assertTrue((((Double) backendData).doubleValue() == ((Double) retrieved).doubleValue()), "Unexpected float value"); + assertTrue((((Double) backendData).doubleValue() == ((Double) retrieved).doubleValue()), "Unexpected float value, expected: " + + ((Double) backendData).doubleValue() + " received: " + ((Double) retrieved).doubleValue()); break; case java.sql.Types.REAL: - assertTrue((((Float) backendData).floatValue() == ((Float) retrieved).floatValue()), "Unexpected real value"); + assertTrue((((Float) backendData).floatValue() == ((Float) retrieved).floatValue()), + "Unexpected real value, expected: " + ((Float) backendData).floatValue() + " received: " + ((Float) retrieved).floatValue()); break; case java.sql.Types.VARCHAR: case java.sql.Types.NVARCHAR: - assertTrue((((String) backendData).trim().equalsIgnoreCase(((String) retrieved).trim())), "Unexpected varchar/nvarchar value "); + assertTrue((((String) backendData).trim().equalsIgnoreCase(((String) retrieved).trim())), "Unexpected varchar/nvarchar value, " + + "expected: " + ((String) backendData).trim() + " ,received: " + ((String) retrieved).trim()); break; - case java.sql.Types.CHAR: case java.sql.Types.NCHAR: - assertTrue((((String) backendData).trim().equalsIgnoreCase(((String) retrieved).trim())), "Unexpected char/nchar value "); + assertTrue((((String) backendData).trim().equalsIgnoreCase(((String) retrieved).trim())), "Unexpected char/nchar value, " + + "expected: " + ((String) backendData).trim() + " ,received: " + ((String) retrieved).trim()); break; case java.sql.Types.TIMESTAMP: if (metaData.getColumnTypeName(ordinal + 1).equalsIgnoreCase("datetime")) { assertTrue((((Timestamp) roundDatetimeValue(backendData)).getTime() == (((Timestamp) retrieved).getTime())), - "Unexpected datetime value"); + "Unexpected datetime value, expected: " + ((Timestamp) roundDatetimeValue(backendData)).getTime() + " , received: " + + (((Timestamp) retrieved).getTime())); break; } else if (metaData.getColumnTypeName(ordinal + 1).equalsIgnoreCase("smalldatetime")) { assertTrue((((Timestamp) roundSmallDateTimeValue(backendData)).getTime() == (((Timestamp) retrieved).getTime())), - "Unexpected smalldatetime value"); + "Unexpected smalldatetime value, expected: " + ((Timestamp) roundSmallDateTimeValue(backendData)).getTime() + + " ,received: " + (((Timestamp) retrieved).getTime())); break; } else - assertTrue(("" + Timestamp.valueOf((LocalDateTime) backendData)).equalsIgnoreCase("" + retrieved), "Unexpected datetime2 value"); + assertTrue(("" + Timestamp.valueOf((LocalDateTime) backendData)).equalsIgnoreCase("" + retrieved), "Unexpected datetime2 value, " + + "expected: " + Timestamp.valueOf((LocalDateTime) backendData) + " ,received: " + retrieved); break; case java.sql.Types.DATE: - assertTrue((("" + backendData).equalsIgnoreCase("" + retrieved)), "Unexpected date value"); + assertTrue((("" + backendData).equalsIgnoreCase("" + retrieved)), + "Unexpected date value, expected: " + backendData + " ,received: " + retrieved); break; case java.sql.Types.TIME: - assertTrue(("" + Time.valueOf((LocalTime) backendData)).equalsIgnoreCase("" + retrieved), "Unexpected time value "); + assertTrue(("" + Time.valueOf((LocalTime) backendData)).equalsIgnoreCase("" + retrieved), + "Unexpected time value, exptected: " + Time.valueOf((LocalTime) backendData) + " ,received: " + retrieved); break; case microsoft.sql.Types.DATETIMEOFFSET: - assertTrue( - (("" + Timestamp.valueOf(((OffsetDateTime) backendData).toLocalDateTime())) + " " - + ((OffsetDateTime) backendData).getOffset()).equalsIgnoreCase("" + (DateTimeOffset) retrieved), - " unexpected DATETIMEOFFSET value, expected: " + ("" + Timestamp.valueOf(((OffsetDateTime) backendData).toLocalDateTime())) + " " - + ((OffsetDateTime) backendData).getOffset() + " .Retrieved: " + (DateTimeOffset) retrieved ); + assertTrue(("" + backendData).equals("" + retrieved), + " unexpected DATETIMEOFFSET value, expected: " + backendData + " ,received: " + retrieved); break; default: fail("Unhandled JDBCType " + JDBCType.valueOf(metaData.getColumnType(ordinal + 1))); break; } - } /** diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBStatement.java b/src/test/java/com/microsoft/sqlserver/testframework/DBStatement.java index b8950d148..0c85066ef 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBStatement.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBStatement.java @@ -46,11 +46,11 @@ public class DBStatement extends AbstractParentWrapper { Statement statement = null; DBResultSet dbresultSet = null; - + DBStatement(DBConnection dbConnection) { super(dbConnection, null, "statement"); } - + DBStatement(DBConnection parent, Statement internal, int type, int concurrency, int holdability) { super(parent, null, "statement"); } @@ -65,7 +65,7 @@ DBStatement createStatement() throws SQLServerException { setInternal(statement); return this; } - + DBStatement createStatement(int type, int concurrency) throws SQLServerException { // TODO: add cursor and holdability statement = ((SQLServerConnection) parent().product()).createStatement(type, concurrency); @@ -99,8 +99,7 @@ public boolean execute(String sql) throws SQLException { } /** - * Close the Statement and ResultSet associated - * with it + * Close the Statement and ResultSet associated with it * * @throws SQLException */ @@ -145,15 +144,14 @@ public boolean dropTable(DBTable table) { void setInternal(Object internal) { this.internal = internal; } - + /** * * @return * @throws SQLException */ - public int getQueryTimeout() throws SQLException - { - int current = ((Statement) product()).getQueryTimeout(); - return current; + public int getQueryTimeout() throws SQLException { + int current = ((Statement) product()).getQueryTimeout(); + return current; } } diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlChar.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlChar.java index a75b61a4a..e54f5ad72 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlChar.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlChar.java @@ -38,7 +38,8 @@ */ public class SqlChar extends SqlType { - private static String normalCharSet = "1234567890-=!@#$%^&*()_+qwertyuiop[]\\asdfghjkl;'zxcvbnm,./QWERTYUIOP{}|ASDFGHJKL:\"ZXCVBNM<>?"; + private static String normalCharSet = "1234567890-=!@#$%^&*()_+qwertyuiop[]\\asdfghjkl;zxcvbnm,./QWERTYUIOP{}|ASDFGHJKL:\"ZXCVBNM<>?"; + public SqlChar() { this("char", JDBCType.CHAR, 4000); } @@ -51,13 +52,38 @@ public SqlChar() { public Object createdata() { int dataLength = ThreadLocalRandom.current().nextInt(precision); - String str = generateCharTypes(dataLength); - String newStr = str.replace("'", ""); - return newStr; + return generateCharTypes(dataLength); } private static String generateCharTypes(int columnLength) { String charSet = normalCharSet; return buildCharOrNChar(columnLength, charSet); } + + /** + * generate char or nchar values + * + * @param columnLength + * @param charSet + * @return + */ + protected static String buildCharOrNChar(int columnLength, String charSet) { + int columnLengthInt = columnLength; + return buildRandomString(columnLengthInt, charSet); + } + + private static String buildRandomString(int length, String charSet) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < length; i++) { + char c = pickRandomChar(charSet); + sb.append(c); + } + return sb.toString(); + } + + private static char pickRandomChar(String charSet) { + int charSetLength = charSet.length(); + int randomIndex = r.nextInt(charSetLength); + return charSet.charAt(randomIndex); + } } \ No newline at end of file diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlDateTimeOffset.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlDateTimeOffset.java index c5f3a85e6..f8cdadd74 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlDateTimeOffset.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlDateTimeOffset.java @@ -25,74 +25,137 @@ package com.microsoft.sqlserver.testframework.sqlType; -import static org.junit.jupiter.api.Assertions.fail; - import java.sql.JDBCType; import java.sql.Timestamp; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.time.OffsetDateTime; -import java.time.ZoneOffset; -import java.time.format.DateTimeFormatter; -import java.time.format.DateTimeFormatterBuilder; -import java.time.temporal.ChronoField; -import java.util.concurrent.ThreadLocalRandom; +import java.util.Calendar; -import org.apache.commons.lang3.RandomStringUtils; +import microsoft.sql.DateTimeOffset; public class SqlDateTimeOffset extends SqlDateTime { + public static boolean returnMinMax = (0 == r.nextInt(5)); // 20% chance of return Min/Max value + private static String numberCharSet2 = "123456789"; + // TODO: datetiemoffset can extend SqlDateTime2 // timezone is not supported in Timestamp so its useless to initialize // min/max with offset - static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss.SSSSSSSZ"); - static String basePattern = "yyyy-MM-dd HH:mm:ss"; - static ZoneOffset min = ZoneOffset.of("-1400"); - static ZoneOffset max = ZoneOffset.of("+1400"); - - static DateTimeFormatter formatter; - public SqlDateTimeOffset() { - super("datetimeoffset", - JDBCType.TIMESTAMP /* microsoft.sql.Types.DATETIMEOFFSET */, null, null); - try { - minvalue = new Timestamp( - dateFormat.parse((String) SqlTypeValue.DATETIMEOFFSET.minValue).getTime()); - maxvalue = new Timestamp( - dateFormat.parse((String) SqlTypeValue.DATETIMEOFFSET.maxValue).getTime()); - } - catch (ParseException ex) { - fail(ex.getMessage()); - } + super("datetimeoffset", JDBCType.TIMESTAMP /* microsoft.sql.Types.DATETIMEOFFSET */, null, null); + minvalue = Timestamp.valueOf((String) SqlTypeValue.DATETIMEOFFSET.minValue); + maxvalue = Timestamp.valueOf((String) SqlTypeValue.DATETIMEOFFSET.maxValue); this.precision = 7; this.variableLengthType = VariableLengthType.Precision; generatePrecision(); - formatter = new DateTimeFormatterBuilder().appendPattern(basePattern) - .appendFraction(ChronoField.NANO_OF_SECOND, 0, this.precision, true) - .appendOffset("+HH:mm", "Z").toFormatter(); + } public Object createdata() { - Timestamp temp = new Timestamp(ThreadLocalRandom.current() - .nextLong(((Timestamp) minvalue).getTime(), ((Timestamp) maxvalue).getTime())); - temp.setNanos(0); - String timeNano = temp.toString().substring(0, temp.toString().length() - 1) - + RandomStringUtils.randomNumeric(this.precision); - - // generate random offset values - int offsetSeconds = ThreadLocalRandom.current().nextInt(min.getTotalSeconds(), - max.getTotalSeconds() + 1); - - // trim the seconds from +HH:mm:ss - if (0 != offsetSeconds % 60) { - timeNano = timeNano - + ZoneOffset.ofTotalSeconds(offsetSeconds).toString().substring(0, 6); + return generateDatetimeoffset(this.precision); + } + + public Object generateDatetimeoffset(Integer precision) { + if (null == precision) { + precision = 7; + } + + DateTimeOffset maxDTS = calculateDateTimeOffsetMinMax("max", precision, "9999-12-31 23:59:59"); + DateTimeOffset minDTS = calculateDateTimeOffsetMinMax("min", precision, "0001-01-01 00:00:00"); + + long max = maxDTS.getTimestamp().getTime(); + long min = minDTS.getTimestamp().getTime(); + + Timestamp ts = generateTimestamp(max, min); + + if (null == ts) { + return null; + } + + if (returnMinMax) { + if (r.nextBoolean()) { + return maxDTS; + } + else { + // return minDTS; + return calculateDateTimeOffsetMinMax("min", precision, "0001-01-01 00:00:00.0000000"); + } + } + + int precisionDigits = buildPrecision(precision, numberCharSet2); + ts.setNanos(precisionDigits); + + int randomTimeZoneInMinutes = r.nextInt(1681) - 840; + + return microsoft.sql.DateTimeOffset.valueOf(ts, randomTimeZoneInMinutes); + } + + private static DateTimeOffset calculateDateTimeOffsetMinMax(String maxOrMin, Integer precision, String tsMinMax) { + int providedTimeZoneInMinutes; + if (maxOrMin.toLowerCase().equals("max")) { + providedTimeZoneInMinutes = 840; } else { - timeNano = timeNano + ZoneOffset.ofTotalSeconds(offsetSeconds).toString(); + providedTimeZoneInMinutes = -840; } - // can pass string rather than converting to LocalDateTime, but leaving - // it unchanged for now to handle prepared statements - OffsetDateTime of = OffsetDateTime.parse(timeNano, formatter); - return of; + + Timestamp tsMax = Timestamp.valueOf(tsMinMax); + + Calendar cal = Calendar.getInstance(); + long offset = cal.get(Calendar.ZONE_OFFSET); // in milliseconds + + // max Timestamp + difference of current time zone and GMT - provided time zone in milliseconds + tsMax = new Timestamp(tsMax.getTime() + offset - (providedTimeZoneInMinutes * 60 * 1000)); + + if (maxOrMin.toLowerCase().equals("max")) { + int precisionDigits = buildPrecision(precision, "9"); + tsMax.setNanos(precisionDigits); + } + + return microsoft.sql.DateTimeOffset.valueOf(tsMax, providedTimeZoneInMinutes); + } + + private static int buildPrecision(int precision, String charSet) { + String stringValue = calculatePrecisionDigits(precision, charSet); + return Integer.parseInt(stringValue); + } + + // setNanos(999999900) gives 00:00:00.9999999 + // so, this value has to be 9 digits + private static String calculatePrecisionDigits(int precision, String charSet) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < precision; i++) { + char c = pickRandomChar(charSet); + sb.append(c); + } + + for (int i = sb.length(); i < 9; i++) { + sb.append("0"); + } + + return sb.toString(); + } + + private static Timestamp generateTimestamp(long max, long min) { + + if (returnMinMax) { + if (r.nextBoolean()) { + return new Timestamp(max); + } + else { + return new Timestamp(min); + } + } + + while (true) { + long longValue = r.nextLong(); + + if (longValue >= min && longValue <= max) { + return new Timestamp(longValue); + } + } + } + + private static char pickRandomChar(String charSet) { + int charSetLength = charSet.length(); + int randomIndex = r.nextInt(charSetLength); + return charSet.charAt(randomIndex); } } \ No newline at end of file diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNChar.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNChar.java index 623034f7e..51067e9e2 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNChar.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNChar.java @@ -28,10 +28,8 @@ import java.sql.JDBCType; import java.util.concurrent.ThreadLocalRandom; -import org.apache.commons.lang.StringEscapeUtils; - public class SqlNChar extends SqlChar { - private static String normalCharSet = "1234567890-=!@#$%^&*()_+qwertyuiop[]\\asdfghjkl;'zxcvbnm,./QWERTYUIOP{}|ASDFGHJKL:\"ZXCVBNM<>?"; + private static String normalCharSet = "1234567890-=!@#$%^&*()_+qwertyuiop[]\\asdfghjkl;zxcvbnm,./QWERTYUIOP{}|ASDFGHJKL:\"ZXCVBNM<>?"; SqlNChar(String name, JDBCType jdbctype, int precision) { super(name, jdbctype, precision); @@ -43,11 +41,9 @@ public SqlNChar() { public Object createdata() { int dataLength = ThreadLocalRandom.current().nextInt(precision); - String str = generateCharTypes(dataLength); - String newStr = str.replace("'", ""); - return newStr; + return generateCharTypes(dataLength); } - + private static String generateCharTypes(int columnLength) { String charSet = normalCharSet; return buildCharOrNChar(columnLength, charSet); diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlType.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlType.java index 81783baa7..c759c6fe9 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlType.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlType.java @@ -183,30 +183,4 @@ void generatePrecision() { this.precision = ThreadLocalRandom.current().nextInt(minPrecision, maxPrecision + 1); } - /** - * generate char or nchar values - * - * @param columnLength - * @param charSet - * @return - */ - protected static String buildCharOrNChar(int columnLength, String charSet) { - int columnLengthInt = columnLength; - return buildRandomString(columnLengthInt, charSet); - } - - private static String buildRandomString(int length, String charSet) { - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < length; i++) { - char c = pickRandomChar(charSet); - sb.append(c); - } - return sb.toString(); - } - - private static char pickRandomChar(String charSet) { - int charSetLength = charSet.length(); - int randomIndex = r.nextInt(charSetLength); - return charSet.charAt(randomIndex); - } } diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlTypeValue.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlTypeValue.java index 46decb943..d556ebeee 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlTypeValue.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlTypeValue.java @@ -50,7 +50,7 @@ enum SqlTypeValue { TIME ("00:00:00.0000000", "23:59:59.9999999", null), SMALLDATETIME ("19000101T00:00:00", "20790606T23:59:59", null), DATETIME2 ("00010101T00:00:00.0000000", "99991231T23:59:59.9999999", null), - DATETIMEOFFSET ("00010101T00:00:00.0000000-1400", "99991231T23:59:59.9999999+1400", null), + DATETIMEOFFSET ("9999-12-31 23:59:59", "0001-01-01 00:00:00", null), ; Object minValue; From 85dd53d41a6d634a76d0a4872b4eaf0a2d2ccf4f Mon Sep 17 00:00:00 2001 From: Suraiya Hameed Date: Wed, 18 Jan 2017 15:21:50 -0800 Subject: [PATCH 11/28] Binary and Varbinary types for framework (#119) * Binary and Varbinary types for framework * updates to precision to fit row in SQL Server 8K page * modularizing the if block * added documentation --- .../sqlserver/testframework/DBColumn.java | 9 +++ .../sqlserver/testframework/DBSchema.java | 7 +- .../sqlserver/testframework/DBTable.java | 44 ++++++++++--- .../testframework/sqlType/SqlBinary.java | 64 +++++++++++++++++++ .../testframework/sqlType/SqlChar.java | 7 +- .../testframework/sqlType/SqlNChar.java | 2 +- .../testframework/sqlType/SqlTypeValue.java | 3 +- .../testframework/sqlType/SqlVarBinary.java | 41 ++++++++++++ 8 files changed, 161 insertions(+), 16 deletions(-) create mode 100644 src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlBinary.java create mode 100644 src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlVarBinary.java diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBColumn.java b/src/test/java/com/microsoft/sqlserver/testframework/DBColumn.java index 4228564ac..0e4efb814 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBColumn.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBColumn.java @@ -25,6 +25,7 @@ package com.microsoft.sqlserver.testframework; +import java.sql.JDBCType; import java.util.ArrayList; import java.util.List; @@ -71,6 +72,14 @@ SqlType getSqlType() { return sqlType; } + /** + * + * @return JDBCType for the column + */ + JDBCType getJdbctype() { + return sqlType.getJdbctype(); + } + /** * * @param sqlType diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBSchema.java b/src/test/java/com/microsoft/sqlserver/testframework/DBSchema.java index 3c15b3369..10702ed5c 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBSchema.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBSchema.java @@ -29,6 +29,7 @@ import java.util.List; import com.microsoft.sqlserver.testframework.sqlType.SqlBigInt; +import com.microsoft.sqlserver.testframework.sqlType.SqlBinary; import com.microsoft.sqlserver.testframework.sqlType.SqlBit; import com.microsoft.sqlserver.testframework.sqlType.SqlChar; import com.microsoft.sqlserver.testframework.sqlType.SqlDate; @@ -49,6 +50,7 @@ import com.microsoft.sqlserver.testframework.sqlType.SqlTime; import com.microsoft.sqlserver.testframework.sqlType.SqlTinyInt; import com.microsoft.sqlserver.testframework.sqlType.SqlType; +import com.microsoft.sqlserver.testframework.sqlType.SqlVarBinary; import com.microsoft.sqlserver.testframework.sqlType.SqlVarChar; /** @@ -94,8 +96,11 @@ public class DBSchema { sqlTypes.add(new SqlSmallDateTime()); sqlTypes.add(new SqlDateTime2()); sqlTypes.add(new SqlDateTimeOffset()); - // TODO: // Binary + sqlTypes.add(new SqlBinary()); + sqlTypes.add(new SqlVarBinary()); + + // TODO: // Other types } } diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java b/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java index e93a83af4..9a293280c 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java @@ -35,6 +35,8 @@ import java.util.logging.Level; import java.util.logging.Logger; +import org.apache.commons.codec.binary.Hex; + import com.microsoft.sqlserver.testframework.sqlType.SqlType; import com.microsoft.sqlserver.testframework.sqlType.VariableLengthType; import com.microsoft.sqlserver.testframework.util.RandomUtil; @@ -250,17 +252,16 @@ String populateTableSql() { sb.add(OPEN_BRACKET); for (int colNum = 0; colNum < totalColumns; colNum++) { - // TODO: add betterway to enclose data - if (JDBCType.CHAR == getColumn(colNum).getSqlType().getJdbctype() - || JDBCType.VARCHAR == getColumn(colNum).getSqlType().getJdbctype() - || JDBCType.NCHAR == getColumn(colNum).getSqlType().getJdbctype() - || JDBCType.NVARCHAR == getColumn(colNum).getSqlType().getJdbctype() - || JDBCType.TIMESTAMP == getColumn(colNum).getSqlType().getJdbctype() - || JDBCType.DATE == getColumn(colNum).getSqlType().getJdbctype() - || JDBCType.TIME == getColumn(colNum).getSqlType().getJdbctype()) + // TODO: consider how to enclose data in case of preparedStatemets + if (passDataAsString(colNum)) { sb.add("'" + String.valueOf(getColumn(colNum).getRowValue(i)) + "'"); - else + } + else if (passDataAsHex(colNum)) { + sb.add("0X" + Hex.encodeHexString((byte[]) (getColumn(colNum).getRowValue(i)))); + } + else { sb.add(String.valueOf(getColumn(colNum).getRowValue(i))); + } if (colNum < totalColumns - 1) { sb.add(COMMA); @@ -333,4 +334,29 @@ public void addColumn(SqlType sqlType) { DBColumn getColumn(int index) { return columns.get(index); } + + /** + * + * @param colNum + * @return true if value can be passed as String for the column + */ + boolean passDataAsString(int colNum){ + return (JDBCType.CHAR == getColumn(colNum).getJdbctype() + || JDBCType.VARCHAR == getColumn(colNum).getJdbctype() + || JDBCType.NCHAR == getColumn(colNum).getJdbctype() + || JDBCType.NVARCHAR == getColumn(colNum).getJdbctype() + || JDBCType.TIMESTAMP == getColumn(colNum).getJdbctype() + || JDBCType.DATE == getColumn(colNum).getJdbctype() + || JDBCType.TIME == getColumn(colNum).getJdbctype()); + } + + /** + * + * @param colNum + * @return true if value can be passed as Hex for the column + */ + boolean passDataAsHex(int colNum){ + return (JDBCType.BINARY == getColumn(colNum).getJdbctype() + || JDBCType.VARBINARY == getColumn(colNum).getJdbctype()); + } } diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlBinary.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlBinary.java new file mode 100644 index 000000000..12820c018 --- /dev/null +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlBinary.java @@ -0,0 +1,64 @@ +// --------------------------------------------------------------------------------------------------------------------------------- +// File: SqlBinary.java +// +// +// Microsoft JDBC Driver for SQL Server +// Copyright(c) Microsoft Corporation +// All rights reserved. +// MIT License +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), +// to deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, +// and / or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions : +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +// --------------------------------------------------------------------------------------------------------------------------------- + +package com.microsoft.sqlserver.testframework.sqlType; + +import java.sql.JDBCType; +import java.util.concurrent.ThreadLocalRandom; + +/** + * Contains name, jdbctype, precision, scale for binary data type + */ +public class SqlBinary extends SqlType { + + /** + * set JDBCType and precision for SqlBinary + */ + public SqlBinary() { + this("binary", JDBCType.BINARY, 2000); + } + + /** + * + * @param name binary or varbinary + * @param jdbctype + * @param precision + */ + SqlBinary(String name, JDBCType jdbctype, int precision) { + super(name, jdbctype, precision, 0, SqlTypeValue.BINARY.minValue, SqlTypeValue.BINARY.maxValue, SqlTypeValue.BINARY.nullValue, + VariableLengthType.Precision); + generatePrecision(); + } + + /** + * create random data for binary and varbinary column + */ + public Object createdata() { + int dataLength = ThreadLocalRandom.current().nextInt(precision); + byte[] bytes = new byte[dataLength]; + ThreadLocalRandom.current().nextBytes(bytes); + return bytes; + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlChar.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlChar.java index f0e57193a..19181556e 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlChar.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlChar.java @@ -32,14 +32,13 @@ import org.apache.commons.lang3.RandomStringUtils; /* - * Restricting the size of char/varchar to 4000 and nchar/nvarchar to 2000 to - * accommodate SQL Sever limitation of having of having maximum allowable table - * row size to 8060 + * Restricting the size of char/binary to 2000 and nchar to 1000 to accommodate SQL Sever limitation of having of having maximum allowable + * table row size to 8060 */ public class SqlChar extends SqlType { public SqlChar() { - this("char", JDBCType.CHAR, 4000); + this("char", JDBCType.CHAR, 2000); } SqlChar(String name, JDBCType jdbctype, int precision) { diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNChar.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNChar.java index d3710ea91..45fed3f75 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNChar.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNChar.java @@ -37,7 +37,7 @@ public class SqlNChar extends SqlChar { } public SqlNChar() { - this("nchar", JDBCType.NCHAR, 2000); + this("nchar", JDBCType.NCHAR, 1000); } public Object createdata() { diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlTypeValue.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlTypeValue.java index 46decb943..57fcf2a98 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlTypeValue.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlTypeValue.java @@ -45,8 +45,9 @@ enum SqlTypeValue { FLOAT (new Double(-1.79E308), new Double(+1.79E308), new Double(0)), REAL (new Float(-3.4E38), new Float(+3.4E38), new Float(0)), CHAR (null, null, null),// CHAR used by char, nchar, varchar, nvarchar + BINARY (null, null, null), DATETIME ("17530101T00:00:00.000", "99991231T23:59:59.997", null), - DATE ("00010101", "99991231", null), + DATE ("00010101", "99991231", null), TIME ("00:00:00.0000000", "23:59:59.9999999", null), SMALLDATETIME ("19000101T00:00:00", "20790606T23:59:59", null), DATETIME2 ("00010101T00:00:00.0000000", "99991231T23:59:59.9999999", null), diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlVarBinary.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlVarBinary.java new file mode 100644 index 000000000..0a3de1832 --- /dev/null +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlVarBinary.java @@ -0,0 +1,41 @@ +// --------------------------------------------------------------------------------------------------------------------------------- +// File: SqlVarBinary.java +// +// +// Microsoft JDBC Driver for SQL Server +// Copyright(c) Microsoft Corporation +// All rights reserved. +// MIT License +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), +// to deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, +// and / or sell copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following conditions : +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +// --------------------------------------------------------------------------------------------------------------------------------- + +package com.microsoft.sqlserver.testframework.sqlType; + +import java.sql.JDBCType; + +/** + * Contains name, jdbctype, precision, scale for varbinary data type + */ +public class SqlVarBinary extends SqlBinary { + + /** + * set JDBCType and precision for SqlVarBinary + */ + public SqlVarBinary() { + super("varbinary", JDBCType.VARBINARY, 4000); + } +} From 1aa343847256431656a84565669632b3884539a7 Mon Sep 17 00:00:00 2001 From: Suraiya Hameed Date: Wed, 18 Jan 2017 16:28:20 -0800 Subject: [PATCH 12/28] test bulkcopy with csv --- build.gradle | 9 +- pom.xml | 10 + .../jdbc/bulkCopy/BulkCopyCSVTest.java | 198 ++++++++++++++++++ .../jdbc/bulkCopy/BulkCopyTestUtil.java | 160 ++++++++------ .../jdbc/bulkCopy/SqlTypeMapping.java | 79 +++++++ .../sqlserver/testframework/DBResultSet.java | 11 + src/test/resources/BulkCopyCSVTestInput.csv | 6 + 7 files changed, 403 insertions(+), 70 deletions(-) create mode 100644 src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyCSVTest.java create mode 100644 src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/SqlTypeMapping.java create mode 100644 src/test/resources/BulkCopyCSVTestInput.csv diff --git a/build.gradle b/build.gradle index 61f956d59..dbe7c644b 100644 --- a/build.gradle +++ b/build.gradle @@ -51,6 +51,13 @@ sourceSets { include 'META-INF/services/java.sql.Driver' } } + test { + resources { + srcDirs 'src/test/resources' + include '**/*.csv' + output.resourcesDir = output.classesDir + } + } } //Get dependencies from Maven central repository @@ -71,5 +78,3 @@ dependencies { 'org.junit.jupiter:junit-jupiter-api:5.0.0-M3', 'org.junit.jupiter:junit-jupiter-engine:5.0.0-M3' } - - diff --git a/pom.xml b/pom.xml index 51edab545..10f517c4a 100644 --- a/pom.xml +++ b/pom.xml @@ -146,6 +146,7 @@ + @@ -198,6 +199,15 @@ + + + src/test/resources + + **/*.csv + + + + diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyCSVTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyCSVTest.java new file mode 100644 index 000000000..247b3ec58 --- /dev/null +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyCSVTest.java @@ -0,0 +1,198 @@ +/* + * Microsoft JDBC Driver for SQL Server + * + * Copyright(c) 2016 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.bulkCopy; + +import static org.junit.Assert.fail; + +import java.io.BufferedReader; +import java.io.FileInputStream; +import java.io.InputStreamReader; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.util.Arrays; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.platform.runner.JUnitPlatform; +import org.junit.runner.RunWith; + +import com.microsoft.sqlserver.jdbc.ISQLServerBulkRecord; +import com.microsoft.sqlserver.jdbc.SQLServerBulkCSVFileRecord; +import com.microsoft.sqlserver.jdbc.SQLServerBulkCopy; +import com.microsoft.sqlserver.testframework.AbstractTest; +import com.microsoft.sqlserver.testframework.DBConnection; +import com.microsoft.sqlserver.testframework.DBResultSet; +import com.microsoft.sqlserver.testframework.DBStatement; +import com.microsoft.sqlserver.testframework.DBTable; +import com.microsoft.sqlserver.testframework.sqlType.SqlType; + +/** + * Test bulkcopy with CSV file input + * + * In the input csv, first row is comma separated datatype name of values to follow Precision and scale are separated by hyphen in csv to distinguish + * between column and scale/precision ie decimal(18-6) in csv is decimal type with precision 18 and scale 6 + * + * Destination table contains one column for each datatype name in the csv header(first line of csv) + */ +@RunWith(JUnitPlatform.class) +@DisplayName("Test bulkCopy with CSV") +public class BulkCopyCSVTest extends AbstractTest { + + static String inputFile = "BulkCopyCSVTestInput.csv"; + static String encoding = "UTF-8"; + static String delimiter = ","; + + static DBConnection con = null; + static DBStatement stmt = null; + static String filePath = null; + + /** + * Create connection, statement and generate path of resource file + */ + @BeforeAll + static void setUpConnection() { + con = new DBConnection(connectionString); + stmt = con.createStatement(); + filePath = getCurrentClassPath(); + } + + /** + * test simple csv file for bulkcopy + */ + @Test + @DisplayName("Test SQLServerBulkCSVFileRecord") + void testCSV() { + DBTable destTable = null; + try { + BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath + inputFile), encoding)); + // read the first line from csv and parse it to get datatypes to create destination column + String[] columnTypes = br.readLine().substring(1)/* Skip the Byte order mark */.split(delimiter, -1); + br.close(); + + int numberOfColumns = columnTypes.length; + destTable = new DBTable(false); + SQLServerBulkCSVFileRecord fileRecord = new SQLServerBulkCSVFileRecord(filePath + inputFile, encoding, delimiter, true); + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy((Connection) con.product()); + bulkCopy.setDestinationTableName(destTable.getEscapedTableName()); + + // add a column in destTable for each datatype in csv + for (int i = 0; i < numberOfColumns; i++) { + SqlType sqlType = null; + int precision = -1; + int scale = -1; + + String columnType = columnTypes[i].trim().toLowerCase(); + int indexOpenParenthesis = columnType.lastIndexOf("("); + // skip the parenthesis in case of precision and scale type + if (-1 != indexOpenParenthesis) { + String precision_scale = columnType.substring(indexOpenParenthesis + 1, columnType.length() - 1); + columnType = columnType.substring(0, indexOpenParenthesis); + sqlType = SqlTypeMapping.valueOf(columnType.toUpperCase()).sqlType; + + // add scale if exist + int indexPrecisionScaleSeparator = precision_scale.indexOf("-"); + if (-1 != indexPrecisionScaleSeparator) { + scale = Integer.parseInt(precision_scale.substring(indexPrecisionScaleSeparator + 1)); + sqlType.setScale(scale); + precision_scale = precision_scale.substring(0, indexPrecisionScaleSeparator); + } + // add precision + precision = Integer.parseInt(precision_scale); + sqlType.setPrecision(precision); + } + else { + sqlType = SqlTypeMapping.valueOf(columnType.toUpperCase()).sqlType; + } + + destTable.addColumn(sqlType); + fileRecord.addColumnMetadata(i + 1, "", sqlType.getJdbctype().getVendorTypeNumber(), (-1 == precision) ? 0 : precision, + (-1 == scale) ? 0 : scale); + } + stmt.createTable(destTable); + bulkCopy.writeToServer((ISQLServerBulkRecord) fileRecord); + bulkCopy.close(); + validateValuesFromCSV(destTable); + } + catch (Exception e) { + fail(e.getMessage()); + } + finally { + if (null != destTable) { + stmt.dropTable(destTable); + } + } + } + + /** + * + * @return location of resource file + */ + static String getCurrentClassPath() { + + try { + String className = new Object() { + }.getClass().getEnclosingClass().getName(); + String location = Class.forName(className).getProtectionDomain().getCodeSource().getLocation().getPath(); + return location + "/"; + } + catch (ClassNotFoundException e) { + fail("Failed to get CSV file path. " + e.getMessage()); + } + return null; + } + + /** + * validate value in csv and in destination table as string + * @param destinationTable + */ + static void validateValuesFromCSV(DBTable destinationTable) { + BufferedReader br; + try { + br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath + inputFile), encoding)); + br.readLine(); // skip first line as it is header + + DBResultSet dstResultSet = stmt.executeQuery("SELECT * FROM " + destinationTable.getEscapedTableName() + ";"); + ResultSetMetaData destMeta = ((ResultSet) dstResultSet.product()).getMetaData(); + int totalColumns = destMeta.getColumnCount(); + while (dstResultSet.next()) { + String[] srcValues = br.readLine().split(delimiter); + if ((0 == srcValues.length) && (srcValues.length != totalColumns)) { + srcValues = new String[totalColumns]; + Arrays.fill(srcValues, null); + } + for (int i = 1; i <= totalColumns; i++) { + String srcValue = srcValues[i - 1]; + String dstValue = dstResultSet.getString(i); + srcValue = (null != srcValue) ? srcValue.trim() : srcValue; + dstValue = (null != dstValue) ? dstValue.trim() : dstValue; + + // get the value from csv as string and compare them + BulkCopyTestUtil.comapreSourceDest(java.sql.Types.VARCHAR, srcValue, dstValue); + } + } + } + catch (Exception e) { + fail("CSV validation failed with " + e.getMessage()); + } + } + + /** + * drop source table after testing bulk copy + * + * @throws SQLException + */ + @AfterAll + static void tearConnection() throws SQLException { + stmt.close(); + con.close(); + } +} diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTestUtil.java b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTestUtil.java index 9e00697de..f49437421 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTestUtil.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTestUtil.java @@ -7,6 +7,7 @@ */ package com.microsoft.sqlserver.jdbc.bulkCopy; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -19,6 +20,7 @@ import java.sql.SQLException; import java.sql.Time; import java.sql.Timestamp; +import java.util.Arrays; import com.microsoft.sqlserver.jdbc.SQLServerBulkCopy; import com.microsoft.sqlserver.testframework.DBConnection; @@ -38,7 +40,7 @@ class BulkCopyTestUtil { * @param sourceTable */ static void performBulkCopy(BulkCopyTestWrapper wrapper, DBTable sourceTable) { - performBulkCopy(wrapper, sourceTable, false); + performBulkCopy(wrapper, sourceTable, true); } /** @@ -109,73 +111,95 @@ static void validateValues(DBConnection con, DBTable sourceTable, DBTable destin Object srcValue, dstValue; srcValue = srcResultSet.getObject(i); dstValue = dstResultSet.getObject(i); - // Bulkcopy doesn't guarantee order of insertion - - // if we need to test several rows either use primary key or - // validate result based on sql JOIN - switch (destMeta.getColumnType(i)) { - case java.sql.Types.BIGINT: - assertTrue((((Long) srcValue).longValue() == ((Long) dstValue).longValue()), "Unexpected bigint value"); - break; - - case java.sql.Types.INTEGER: - assertTrue((((Integer) srcValue).intValue() == ((Integer) dstValue).intValue()), "Unexpected int value"); - break; - - case java.sql.Types.SMALLINT: - case java.sql.Types.TINYINT: - assertTrue((((Short) srcValue).shortValue() == ((Short) dstValue).shortValue()), "Unexpected smallint/tinyint value"); - break; - - case java.sql.Types.BIT: - assertTrue((((Boolean) srcValue).booleanValue() == ((Boolean) dstValue).booleanValue()), "Unexpected bit value"); - break; - - case java.sql.Types.DECIMAL: - case java.sql.Types.NUMERIC: - assertTrue(0 == (((BigDecimal) srcValue).compareTo((BigDecimal) dstValue)), - "Unexpected decimal/numeric/money/smallmoney value"); - break; - - case java.sql.Types.DOUBLE: - assertTrue((((Double) srcValue).doubleValue() == ((Double) dstValue).doubleValue()), "Unexpected float value"); - break; - - case java.sql.Types.REAL: - assertTrue((((Float) srcValue).floatValue() == ((Float) dstValue).floatValue()), "Unexpected real value"); - break; - - case java.sql.Types.VARCHAR: - case java.sql.Types.NVARCHAR: - assertTrue((((String) srcValue).equals((String) dstValue)), "Unexpected varchar/nvarchar value "); - break; - - case java.sql.Types.CHAR: - case java.sql.Types.NCHAR: - assertTrue((((String) srcValue).equals((String) dstValue)), "Unexpected char/nchar value "); - break; - - case java.sql.Types.TIMESTAMP: - assertTrue((((Timestamp) srcValue).getTime() == (((Timestamp) dstValue).getTime())), - "Unexpected datetime/smalldatetime/datetime2 value"); - break; - - case java.sql.Types.DATE: - assertTrue((((Date) srcValue).getTime() == (((Date) dstValue).getTime())), "Unexpected datetime value"); - break; - - case java.sql.Types.TIME: - assertTrue(((Time) srcValue).getTime() == ((Time) dstValue).getTime(), "Unexpected time value "); - break; - - case microsoft.sql.Types.DATETIMEOFFSET: - assertTrue(0 == ((microsoft.sql.DateTimeOffset) srcValue).compareTo((microsoft.sql.DateTimeOffset) dstValue), - "Unexpected time value "); - break; - - default: - fail("Unhandled JDBCType " + JDBCType.valueOf(destMeta.getColumnType(i))); - break; - } + + comapreSourceDest(destMeta.getColumnType(i),srcValue,dstValue); } } + + /** + * validate if both expected and actual value are same + * @param dataType + * @param expectedValue + * @param actualValue + */ + static void comapreSourceDest(int dataType, Object expectedValue, Object actualValue){ + // Bulkcopy doesn't guarantee order of insertion - if we need to test several rows either use primary key or + // validate result based on sql JOIN + + if((null == expectedValue) || (null == actualValue)) + { + // if one value is null other should be null too + assertEquals(expectedValue,actualValue,"Expected null in source and destination"); + } + else + switch (dataType) { + case java.sql.Types.BIGINT: + assertTrue((((Long) expectedValue).longValue() == ((Long) actualValue).longValue()), "Unexpected bigint value"); + break; + + case java.sql.Types.INTEGER: + assertTrue((((Integer) expectedValue).intValue() == ((Integer) actualValue).intValue()), "Unexpected int value"); + break; + + case java.sql.Types.SMALLINT: + case java.sql.Types.TINYINT: + assertTrue((((Short) expectedValue).shortValue() == ((Short) actualValue).shortValue()), "Unexpected smallint/tinyint value"); + break; + + case java.sql.Types.BIT: + assertTrue((((Boolean) expectedValue).booleanValue() == ((Boolean) actualValue).booleanValue()), "Unexpected bit value"); + break; + + case java.sql.Types.DECIMAL: + case java.sql.Types.NUMERIC: + assertTrue(0 == (((BigDecimal) expectedValue).compareTo((BigDecimal) actualValue)), + "Unexpected decimal/numeric/money/smallmoney value"); + break; + + case java.sql.Types.DOUBLE: + assertTrue((((Double) expectedValue).doubleValue() == ((Double) actualValue).doubleValue()), "Unexpected float value"); + break; + + case java.sql.Types.REAL: + assertTrue((((Float) expectedValue).floatValue() == ((Float) actualValue).floatValue()), "Unexpected real value"); + break; + + case java.sql.Types.VARCHAR: + case java.sql.Types.NVARCHAR: + assertTrue((((String) expectedValue).equals((String) actualValue)), "Unexpected varchar/nvarchar value "); + break; + + case java.sql.Types.CHAR: + case java.sql.Types.NCHAR: + assertTrue((((String) expectedValue).equals((String) actualValue)), "Unexpected char/nchar value "); + break; + + case java.sql.Types.BINARY: + case java.sql.Types.VARBINARY: + assertTrue(Arrays.equals(((byte[]) expectedValue), ((byte[]) actualValue)), "Unexpected bianry/varbinary value "); + break; + + case java.sql.Types.TIMESTAMP: + assertTrue((((Timestamp) expectedValue).getTime() == (((Timestamp) actualValue).getTime())), + "Unexpected datetime/smalldatetime/datetime2 value"); + break; + + case java.sql.Types.DATE: + assertTrue((((Date) expectedValue).getTime() == (((Date) actualValue).getTime())), "Unexpected datetime value"); + break; + + case java.sql.Types.TIME: + assertTrue(((Time) expectedValue).getTime() == ((Time) actualValue).getTime(), "Unexpected time value "); + break; + + case microsoft.sql.Types.DATETIMEOFFSET: + assertTrue(0 == ((microsoft.sql.DateTimeOffset) expectedValue).compareTo((microsoft.sql.DateTimeOffset) actualValue), + "Unexpected time value "); + break; + + default: + fail("Unhandled JDBCType " + JDBCType.valueOf(dataType)); + break; + } + } } \ No newline at end of file diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/SqlTypeMapping.java b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/SqlTypeMapping.java new file mode 100644 index 000000000..35ed43ba6 --- /dev/null +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/SqlTypeMapping.java @@ -0,0 +1,79 @@ +/* + * Microsoft JDBC Driver for SQL Server + * + * Copyright(c) 2016 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.bulkCopy; + +import com.microsoft.sqlserver.testframework.sqlType.SqlBigInt; +import com.microsoft.sqlserver.testframework.sqlType.SqlBinary; +import com.microsoft.sqlserver.testframework.sqlType.SqlBit; +import com.microsoft.sqlserver.testframework.sqlType.SqlChar; +import com.microsoft.sqlserver.testframework.sqlType.SqlDate; +import com.microsoft.sqlserver.testframework.sqlType.SqlDateTime; +import com.microsoft.sqlserver.testframework.sqlType.SqlDateTime2; +import com.microsoft.sqlserver.testframework.sqlType.SqlDateTimeOffset; +import com.microsoft.sqlserver.testframework.sqlType.SqlDecimal; +import com.microsoft.sqlserver.testframework.sqlType.SqlFloat; +import com.microsoft.sqlserver.testframework.sqlType.SqlInt; +import com.microsoft.sqlserver.testframework.sqlType.SqlMoney; +import com.microsoft.sqlserver.testframework.sqlType.SqlNChar; +import com.microsoft.sqlserver.testframework.sqlType.SqlNVarChar; +import com.microsoft.sqlserver.testframework.sqlType.SqlNumeric; +import com.microsoft.sqlserver.testframework.sqlType.SqlReal; +import com.microsoft.sqlserver.testframework.sqlType.SqlSmallDateTime; +import com.microsoft.sqlserver.testframework.sqlType.SqlSmallInt; +import com.microsoft.sqlserver.testframework.sqlType.SqlSmallMoney; +import com.microsoft.sqlserver.testframework.sqlType.SqlTime; +import com.microsoft.sqlserver.testframework.sqlType.SqlTinyInt; +import com.microsoft.sqlserver.testframework.sqlType.SqlType; +import com.microsoft.sqlserver.testframework.sqlType.SqlVarBinary; +import com.microsoft.sqlserver.testframework.sqlType.SqlVarChar; + +/** + * enum that returns object of desired datatype based for JDBCType type + */ +public enum SqlTypeMapping { + + BIGINT (new SqlBigInt()), + INT (new SqlInt()), + SMALLINT (new SqlSmallInt()), + TINYINT (new SqlTinyInt()), + BIT (new SqlBit()), + DECIMAL (new SqlDecimal()), + NUMERIC (new SqlNumeric()), + MONEY (new SqlMoney()), + SMALLMONEY (new SqlSmallMoney()), + // Appx Numeric + FLOAT (new SqlFloat()), + REAL (new SqlReal()), + // Character + CHAR (new SqlChar()), + VARCHAR (new SqlVarChar()), + // Unicode + NCHAR (new SqlNChar()), + NVARCHAR (new SqlNVarChar()), + // Temporal + DATETIME (new SqlDateTime()), + DATE (new SqlDate()), + TIME (new SqlTime()), + SMALLDATETIME (new SqlSmallDateTime()), + DATETIME2 (new SqlDateTime2()), + DATETIMEOFFSET (new SqlDateTimeOffset()), + //Binary + BINARY (new SqlBinary()), + VARBINARY (new SqlVarBinary()), + ; + + public SqlType sqlType; + + /** + * + * @param type + */ + SqlTypeMapping(SqlType type){ + this.sqlType = type; + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java index 04b069b04..8ed4527c2 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java @@ -77,6 +77,17 @@ public Object getObject(int index) throws SQLException { return resultSet.getObject(index); } + /** + * + * @param index + * @return + * @throws SQLException + */ + public String getString(int index) throws SQLException { + // call individual getters based on type + return resultSet.getString(index); + } + /** * * @param index diff --git a/src/test/resources/BulkCopyCSVTestInput.csv b/src/test/resources/BulkCopyCSVTestInput.csv new file mode 100644 index 000000000..f43d20d14 --- /dev/null +++ b/src/test/resources/BulkCopyCSVTestInput.csv @@ -0,0 +1,6 @@ +bit,tinyint,smallint,int,bigint,float(53),real,decimal(18-6),numeric(18-4),money(20-4),smallmoney(20-4),char(11),nchar(10),varchar(50),nvarchar(10),binary(5),varbinary(25) +1,2,-32768,0,0,-1.78E307,-3.4E38,22.335600,22.3356,-922337203685477.5808,-214748.3648,a5()b,௵ஷஇமண,test to test csv files,ࢨहश,6163686974,6163686974 +,,,,,,,,,,,,,,,, +0,5,32767,1,12,-2.23E-308,-1.18E-38,33.552695,33.5526,922337203685477.5807,0.0000,what!,ৡਐਲ,123 norma black street,Ӧ NӦ,5445535455,54455354 +0,255,0,-2147483648,-9223372036854775808,2.23E-308,0.0,33.503288,33.5032,0.0000,1.0011,no way,Ӧ NӦ,baker street Mr.Homls,àĂ,303C2D3988,303C2D39 +1,5,0,2147483647,9223372036854775807,12.0,3.4E38,33.000501,33.0005,1.0001,214748.3647,l l l l l |,Ȣʗʘ,test to test csv files,௵ஷஇமண,7E7D7A7B20,7E7D7A7B \ No newline at end of file From 149846841107f36e100ef8fc742bfe8c1752048a Mon Sep 17 00:00:00 2001 From: v-afrafi Date: Thu, 19 Jan 2017 11:09:26 -0800 Subject: [PATCH 13/28] adding dbresultsetTypes enum and --- .../microsoft/sqlserver/jdbc/bvt/bvtTest.java | 229 +++++++++--------- .../sqlserver/testframework/DBColumn.java | 16 +- .../sqlserver/testframework/DBConnection.java | 29 ++- .../sqlserver/testframework/DBResultSet.java | 109 ++++----- .../testframework/DBResultSetTypes.java | 33 +++ .../sqlserver/testframework/DBTable.java | 50 ++-- .../testframework/sqlType/SqlChar.java | 2 +- 7 files changed, 266 insertions(+), 202 deletions(-) create mode 100644 src/test/java/com/microsoft/sqlserver/testframework/DBResultSetTypes.java diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTest.java index 14fc4ebf2..c5471df70 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTest.java @@ -9,10 +9,10 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import java.math.BigDecimal; import java.sql.DatabaseMetaData; -import java.sql.ResultSet; import java.sql.SQLException; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -26,6 +26,7 @@ import com.microsoft.sqlserver.testframework.DBConnection; import com.microsoft.sqlserver.testframework.DBPreparedStatement; import com.microsoft.sqlserver.testframework.DBResultSet; +import com.microsoft.sqlserver.testframework.DBResultSetTypes; import com.microsoft.sqlserver.testframework.DBStatement; @RunWith(JUnitPlatform.class) @@ -37,9 +38,11 @@ public class bvtTest extends bvtTestSetup { private static DBConnection conn = null; private static DBStatement stmt = null; - /////////////////////////////////////////////////////////////////// - //// Connect to specified server and close the connection - ///////////////////////////////////////////////////////////////////// + /** + * Connect to specified server and close the connection + * + * @throws SQLException + */ @Test @DisplayName("test connection") public void testConnection() throws SQLException { @@ -52,9 +55,11 @@ public void testConnection() throws SQLException { } } - ///////////////////////////////////////////////////////////////////// - //// Verify isClosed() - ///////////////////////////////////////////////////////////////////// + /** + * Verify isClosed() + * + * @throws SQLException + */ @Test public void testConnectionIsClosed() throws SQLException { try { @@ -68,9 +73,11 @@ public void testConnectionIsClosed() throws SQLException { } } - ///////////////////////////////////////////////////////////////////// - //// Verify Driver Name and Version from MetaData - ///////////////////////////////////////////////////////////////////// + /** + * Verify Driver Name and Version from MetaData + * + * @throws SQLException + */ @Test public void testDriverNameAndDriverVersion() throws SQLException { try { @@ -88,9 +95,11 @@ public void testDriverNameAndDriverVersion() throws SQLException { } } - /////////////////////////////////////////////////////////////////// - // Create a statement, call close - /////////////////////////////////////////////////////////////////// + /** + * Create a statement, call close + * + * @throws SQLException + */ @Test public void testCreateStatement() throws SQLException { @@ -107,12 +116,11 @@ public void testCreateStatement() throws SQLException { } } - /////////////////////////////////////////////////////////////////// - // Create a statement with a query timeout - // ResultSet.Type_forward_only, - // ResultSet.CONCUR_READ_ONLY, executeQuery - // verify cursor by using next and previous and verify data - /////////////////////////////////////////////////////////////////// + /** + * Create a statement with a query timeout + * + * @throws SQLException + */ @Test public void testCreateStatementWithQueryTimeout() throws SQLException { @@ -126,19 +134,19 @@ public void testCreateStatementWithQueryTimeout() throws SQLException { } } - /////////////////////////////////////////////////////////////////// - // Create a statement - // ResultSet.Type_forward_only, - // ResultSet.CONCUR_READ_ONLY, executeQuery - // verify cursor by using next and previous and verify data - /////////////////////////////////////////////////////////////////// + /** + * Create a statement ResultSet.Type_forward_only, ResultSet.CONCUR_READ_ONLY, executeQuery verify cursor by using next and previous and verify + * data + * + * @throws SQLException + * @throws ClassNotFoundException + */ @Test public void testStmtForwardOnlyReadOnly() throws SQLException, ClassNotFoundException { try { conn = new DBConnection(connectionString); - stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); - + stmt = conn.createStatement(DBResultSetTypes.TYPE_FORWARD_ONLY_CONCUR_READ_ONLY); String query = "SELECT * FROM " + table1.getEscapedTableName(); rs = stmt.executeQuery(query); @@ -161,17 +169,18 @@ public void testStmtForwardOnlyReadOnly() throws SQLException, ClassNotFoundExce } } - /////////////////////////////////////////////////////////////////// - // Create a statement - // ResultSet.SCROLL_INSENSITIVE, - // ResultSet.CONCUR_READ_ONLY, executeQuery - // verify cursor by using next, afterlast and previous and verify data - /////////////////////////////////////////////////////////////////// + /** + * Create a statement, ResultSet.SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY, executeQuery verify cursor by using next, afterlast and previous + * and verify data + * + * @throws SQLException + * @throws ClassNotFoundException + */ @Test public void testStmtScrollInsensitiveReadOnly() throws SQLException, ClassNotFoundException { try { conn = new DBConnection(connectionString); - stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); + stmt = conn.createStatement(DBResultSetTypes.TYPE_SCROLL_INSENSITIVE_CONCUR_READ_ONLY); String query = "SELECT * FROM" + table1.getEscapedTableName(); rs = stmt.executeQuery(query); @@ -187,18 +196,18 @@ public void testStmtScrollInsensitiveReadOnly() throws SQLException, ClassNotFou } } - // ///////////////////////////////////////////////////////////////// - // // Create a statement - // // ResultSet.SCROLL_SENSITIVE, - // // ResultSet.CONCUR_READ_ONLY, executeQuery - // // verify cursor by using next and absolute and verify data - // /////////////////////////////////////////////////////////////////// + /** + * Create a statement ResultSet.SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY, executeQuery verify cursor by using next and absolute and verify + * data + * + * @throws SQLException + */ @Test public void testStmtScrollSensitiveReadOnly() throws SQLException { try { conn = new DBConnection(connectionString); - stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); + stmt = conn.createStatement(DBResultSetTypes.TYPE_SCROLL_SENSITIVE_CONCUR_READ_ONLY); String query = "SELECT * FROM " + table1.getEscapedTableName(); rs = stmt.executeQuery(query); @@ -216,18 +225,18 @@ public void testStmtScrollSensitiveReadOnly() throws SQLException { } } - /////////////////////////////////////////////////////////////////// - // Create a statement - // ResultSet.Type_forward_only, - // ResultSet.CONCUR_UPDATABLE, executeQuery - // verify cursor by using next and previous and verify data - /////////////////////////////////////////////////////////////////// + /** + * Create a statement ResultSet.Type_forward_only, ResultSet.CONCUR_UPDATABLE, executeQuery verify cursor by using next and previous and verify + * data + * + * @throws SQLException + */ @Test public void testStmtForwardOnlyUpdateable() throws SQLException { try { conn = new DBConnection(connectionString); - stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); + stmt = conn.createStatement(DBResultSetTypes.TYPE_FORWARD_ONLY_CONCUR_UPDATABLE); String query = "SELECT * FROM " + table1.getEscapedTableName(); rs = stmt.executeQuery(query); @@ -252,20 +261,19 @@ public void testStmtForwardOnlyUpdateable() throws SQLException { } } - /////////////////////////////////////////////////////////////////// - // Create a statement - // ResultSet.SCROLL_SENSITIVE, - // ResultSet.CONCUR_UPDATABLE, executeQuery - // verify cursor by using next and previous and verify data - /////////////////////////////////////////////////////////////////// + /** + * Create a statement ResultSet.SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE, executeQuery verify cursor by using next and previous and verify + * data + * + * @throws SQLException + */ @Test public void testStmtScrollSensitiveUpdatable() throws SQLException { try { conn = new DBConnection(connectionString); - stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); + stmt = conn.createStatement(DBResultSetTypes.TYPE_SCROLL_SENSITIVE_CONCUR_UPDATABLE); - // DBResultSet.currentTable = table1; String query = "SELECT * FROM " + table1.getEscapedTableName(); rs = stmt.executeQuery(query); @@ -283,20 +291,17 @@ public void testStmtScrollSensitiveUpdatable() throws SQLException { } } - /////////////////////////////////////////////////////////////////// - // Create a statement - // TYPE_SS_SCROLL_DYNAMIC, - // CONCUR_SS_OPTIMISTIC_CC, executeQuery - // verify cursor by using next and previous and verify data - /////////////////////////////////////////////////////////////////// + /** + * Create a statement TYPE_SS_SCROLL_DYNAMIC, CONCUR_SS_OPTIMISTIC_CC, executeQuery verify cursor by using next and previous and verify data + * + * @throws SQLException + */ @Test public void testStmtSS_ScrollDynamicOptimistic_CC() throws SQLException { try { - int TYPE_SS_SCROLL_DYNAMIC = 1006; - int CONCUR_SS_OPTIMISTIC_CC = 1008; conn = new DBConnection(connectionString); - stmt = conn.createStatement(TYPE_SS_SCROLL_DYNAMIC, CONCUR_SS_OPTIMISTIC_CC); + stmt = conn.createStatement(DBResultSetTypes.TYPE_DYNAMIC_CONCUR_OPTIMISTIC); String query = "SELECT * FROM " + table1.getEscapedTableName(); rs = stmt.executeQuery(query); @@ -312,20 +317,18 @@ public void testStmtSS_ScrollDynamicOptimistic_CC() throws SQLException { } } - /////////////////////////////////////////////////////////////////// - // Create a statement - // TYPE_SS_SEVER_CURSOR_FORWARD_ONLY, - // CONCUR_READ_ONLY, executeQuery - // verify cursor by using next and verify data - /////////////////////////////////////////////////////////////////// + /** + * Create a statement TYPE_SS_SEVER_CURSOR_FORWARD_ONLY, CONCUR_READ_ONLY, executeQuery verify cursor by using next and verify data + * + * @throws SQLException + */ @Test public void testStmtSS_SEVER_CURSOR_FORWARD_ONLY() throws SQLException { try { - int TYPE_SS_SEVER_CURSOR_FORWARD_ONLY = 2004; - int CONCUR_READ_ONLY = 1008; conn = new DBConnection(connectionString); - stmt = conn.createStatement(TYPE_SS_SEVER_CURSOR_FORWARD_ONLY, CONCUR_READ_ONLY); + DBResultSetTypes rsType = DBResultSetTypes.TYPE_FORWARD_ONLY_CONCUR_READ_ONLY; + stmt = conn.createStatement(rsType.resultsetCursor, rsType.resultSetConcurrency); String query = "SELECT * FROM " + table1.getEscapedTableName(); @@ -341,22 +344,24 @@ public void testStmtSS_SEVER_CURSOR_FORWARD_ONLY() throws SQLException { } - /////////////////////////////////////////////////////////////////// - // Create a preparedstatement, call close - /////////////////////////////////////////////////////////////////// + /** + * Create a preparedStatement, call close + * + * @throws SQLException + */ @Test public void testCreatepreparedStatement() throws SQLException { try { conn = new DBConnection(connectionString); String colName = table1.getColumnName(7); - String value = DBResultSet.getRow(table1, 0).get(7).toString(); + String value = table1.getRowData(7, 0).toString(); String query = "SELECT * from " + table1.getEscapedTableName() + " where [" + colName + "] = ? "; pstmt = conn.prepareStatement(query); pstmt.setObject(1, new BigDecimal(value)); - + rs = pstmt.executeQuery(); rs.verify(table1); } @@ -365,9 +370,11 @@ public void testCreatepreparedStatement() throws SQLException { } } - /////////////////////////////////////////////////////////////////// - // Verify resultset using ResultSetMetaData - /////////////////////////////////////////////////////////////////// + /** + * Verify resultset using ResultSetMetaData + * + * @throws SQLException + */ @Test public void testResultSet() throws SQLException { @@ -386,9 +393,11 @@ public void testResultSet() throws SQLException { } } - /////////////////////////////////////////////////////////////////// - // Verify resultset and close resultSet - /////////////////////////////////////////////////////////////////// + /** + * Verify resultset and close resultSet + * + * @throws SQLException + */ @Test public void testResultSetAndClose() throws SQLException { @@ -398,20 +407,25 @@ public void testResultSetAndClose() throws SQLException { String query = "SELECT * FROM " + table1.getEscapedTableName(); rs = stmt.executeQuery(query); - rs.currentTable = table1; - rs.verify(table1); - stmt.close(); + try { + if (null != rs) + rs.close(); + } + catch (SQLException e) { + fail(e.toString()); + } } finally { terminateVariation(); } } - /////////////////////////////////////////////////////////////////// - // Verify two concurrent resultsets from same connection, - // separate statements - /////////////////////////////////////////////////////////////////// + /** + * Verify two concurrent resultsets from same connection, separate statements + * + * @throws SQLException + */ @Test public void testTwoResultsetsDifferentStmt() throws SQLException { @@ -426,11 +440,9 @@ public void testTwoResultsetsDifferentStmt() throws SQLException { String query = "SELECT * FROM " + table1.getEscapedTableName(); rs1 = stmt1.executeQuery(query); - rs1.currentTable = table1; String query2 = "SELECT * FROM " + table2.getEscapedTableName(); rs2 = stmt2.executeQuery(query2); - rs2.currentTable = table2; // Interleave resultset calls rs1.next(); @@ -461,10 +473,11 @@ public void testTwoResultsetsDifferentStmt() throws SQLException { } } - /////////////////////////////////////////////////////////////////// - // Verify two concurrent resultsets from same connection, - // same statement - /////////////////////////////////////////////////////////////////// + /** + * Verify two concurrent resultsets from same connection, same statement + * + * @throws SQLException + */ @Test public void testTwoResultsetsSameStmt() throws SQLException { @@ -510,20 +523,20 @@ public void testTwoResultsetsSameStmt() throws SQLException { } } - /////////////////////////////////////////////////////////////////// - // Verify resultset closed after statement is closed - /////////////////////////////////////////////////////////////////// + /** + * Verify resultset closed after statement is closed + * + * @throws SQLException + */ @Test public void testResultSetAndCloseStmt() throws SQLException { try { conn = new DBConnection(connectionString); stmt = conn.createStatement(); - // SELECT * FROM ORDER BY String query = "SELECT * FROM " + table1.getEscapedTableName(); rs = stmt.executeQuery(query); - // close statement and verify resultSet stmt.close(); // this should close the resultSet try { rs.next(); @@ -537,9 +550,11 @@ public void testResultSetAndCloseStmt() throws SQLException { } } - /////////////////////////////////////////////////////////////////// - // Verify resultset using SelectMethod - /////////////////////////////////////////////////////////////////// + /** + * Verify resultset using SelectMethod + * + * @throws SQLException + */ @Test public void testResultSetSelectMethod() throws SQLException { @@ -547,11 +562,9 @@ public void testResultSetSelectMethod() throws SQLException { conn = new DBConnection(connectionString + ";selectMethod=cursor;"); stmt = conn.createStatement(); - // SELECT * FROM ORDER BY String query = "SELECT * FROM " + table1.getEscapedTableName(); rs = stmt.executeQuery(query); - // verify resultSet rs.verify(table1); } finally { diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBColumn.java b/src/test/java/com/microsoft/sqlserver/testframework/DBColumn.java index a0becc965..70aad6320 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBColumn.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBColumn.java @@ -25,14 +25,14 @@ package com.microsoft.sqlserver.testframework; +import java.sql.JDBCType; import java.util.ArrayList; import java.util.List; import com.microsoft.sqlserver.testframework.sqlType.SqlType; /** - * This class holds data for Column. Think about encrypted columns. createCMK - * code should not add here. + * This class holds data for Column. Think about encrypted columns. createCMK code should not add here. */ class DBColumn { @@ -71,6 +71,14 @@ SqlType getSqlType() { return sqlType; } + /** + * + * @return JDBCType for the column + */ + JDBCType getJdbctype() { + return sqlType.getJdbctype(); + } + /** * * @param sqlType @@ -88,7 +96,7 @@ void setSqlType(SqlType sqlType) { void populateValues(int rows) { columnValues = new ArrayList(); for (int i = 0; i < rows; i++) - columnValues.add(sqlType.createdata()); + columnValues.add(sqlType.createdata()); } /** @@ -96,7 +104,7 @@ void populateValues(int rows) { * @param row * @return the value populated for the column */ - Object getRowValue(int row) { + public Object getRowValue(int row) { // handle exceptions return columnValues.get(row); } diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBConnection.java b/src/test/java/com/microsoft/sqlserver/testframework/DBConnection.java index 30476b35e..3673b62c4 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBConnection.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBConnection.java @@ -29,12 +29,11 @@ import java.sql.Connection; import java.sql.DatabaseMetaData; -import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.sql.Statement; import com.microsoft.sqlserver.jdbc.SQLServerConnection; +import com.microsoft.sqlserver.jdbc.SQLServerException; /* * Wrapper class for SQLServerConnection @@ -47,10 +46,6 @@ public class DBConnection extends AbstractParentWrapper { // TODO: add additional connection properties // TODO: add DataSource support private SQLServerConnection connection = null; - private boolean _closed = false; - private boolean _closeCalled = false; - public int _holdability = ResultSet.HOLD_CURSORS_OVER_COMMIT; - /** * establishes connection using the input @@ -112,21 +107,31 @@ public DBStatement createStatement(int type, int concurrency) throws SQLExceptio return dbstatement.createStatement(type, concurrency); } - + + /** + * + * @param rsType + * @return + * @throws SQLServerException + */ + public DBStatement createStatement(DBResultSetTypes rsType) throws SQLServerException { + DBStatement dbstatement = new DBStatement(this); + return dbstatement.createStatement(rsType.resultsetCursor, rsType.resultSetConcurrency); + } + /** * * @param query * @return * @throws SQLException */ - public DBPreparedStatement prepareStatement(String query) throws SQLException - { - DBPreparedStatement dbpstmt = new DBPreparedStatement(this, internal, "preparedStatement"); - return dbpstmt.prepareStatement(query); + public DBPreparedStatement prepareStatement(String query) throws SQLException { + DBPreparedStatement dbpstmt = new DBPreparedStatement(this, internal, "preparedStatement"); + return dbpstmt.prepareStatement(query); } /** - * clsoe connection + * close connection */ public void close() { try { diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java index c0352509a..a079b15fc 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java @@ -37,24 +37,31 @@ import java.sql.Timestamp; import java.time.LocalDateTime; import java.time.LocalTime; -import java.time.OffsetDateTime; -import java.util.ArrayList; import java.util.Calendar; -import microsoft.sql.DateTimeOffset; - /** * wrapper class for ResultSet * * @author Microsoft * */ + public class DBResultSet extends AbstractParentWrapper { // TODO: add cursors // TODO: add resultSet level holdability // TODO: add concurrency control - public DBTable currentTable; + + public static final int TYPE_DYNAMIC = ResultSet.TYPE_SCROLL_SENSITIVE + 1; + public static final int CONCUR_OPTIMISTIC = ResultSet.CONCUR_UPDATABLE + 2; + public static final int TYPE_CURSOR_FORWARDONLY = ResultSet.TYPE_FORWARD_ONLY + 1001; + public static final int TYPE_FORWARD_ONLY = ResultSet.TYPE_FORWARD_ONLY; + public static final int CONCUR_READ_ONLY = ResultSet.CONCUR_READ_ONLY; + public static final int TYPE_SCROLL_INSENSITIVE = ResultSet.TYPE_SCROLL_INSENSITIVE; + public static final int TYPE_SCROLL_SENSITIVE = ResultSet.TYPE_SCROLL_SENSITIVE; + public static final int CONCUR_UPDATABLE = ResultSet.CONCUR_UPDATABLE; + + protected DBTable currentTable; public int _currentrow = -1; // The row this rowset is currently pointing to ResultSet resultSet = null; @@ -146,102 +153,102 @@ public void verifyCurrentRow(DBTable table) throws SQLException { * @throws SQLException */ public void verifydata(int ordinal, Class coercion, Object arg) throws SQLException { - Object backendData = this.currentrow().get(ordinal); + Object expectedData = currentTable.columns.get(ordinal).getRowValue(_currentrow); // getXXX - default mapping Object retrieved = this.getXXX(ordinal + 1, coercion); // Verify - verifydata(ordinal, coercion, backendData, retrieved); + verifydata(ordinal, coercion, expectedData, retrieved); } - public void verifydata(int ordinal, Class coercion, Object backendData, Object retrieved) throws SQLException { + public void verifydata(int ordinal, Class coercion, Object expectedData, Object retrieved) throws SQLException { metaData = this.getMetaData(); switch (metaData.getColumnType(ordinal + 1)) { case java.sql.Types.BIGINT: - assertTrue((((Long) backendData).longValue() == ((Long) retrieved).longValue()), - "Unexpected bigint value, expected: " + ((Long) backendData).longValue() + " .Retrieved: " + ((Long) retrieved).longValue()); + assertTrue((((Long) expectedData).longValue() == ((Long) retrieved).longValue()), + "Unexpected bigint value, expected: " + ((Long) expectedData).longValue() + " .Retrieved: " + ((Long) retrieved).longValue()); break; case java.sql.Types.INTEGER: - assertTrue((((Integer) backendData).intValue() == ((Integer) retrieved).intValue()), - "Unexpected int value, expected : " + ((Integer) backendData).intValue() + " ,received: " + ((Integer) retrieved).intValue()); + assertTrue((((Integer) expectedData).intValue() == ((Integer) retrieved).intValue()), "Unexpected int value, expected : " + + ((Integer) expectedData).intValue() + " ,received: " + ((Integer) retrieved).intValue()); break; case java.sql.Types.SMALLINT: case java.sql.Types.TINYINT: - assertTrue((((Short) backendData).shortValue() == ((Short) retrieved).shortValue()), "Unexpected smallint/tinyint value, expected: " - + " " + ((Short) backendData).shortValue() + " received: " + ((Short) retrieved).shortValue()); + assertTrue((((Short) expectedData).shortValue() == ((Short) retrieved).shortValue()), "Unexpected smallint/tinyint value, expected: " + + " " + ((Short) expectedData).shortValue() + " received: " + ((Short) retrieved).shortValue()); break; case java.sql.Types.BIT: - if (backendData.equals(1)) - backendData = true; + if (expectedData.equals(1)) + expectedData = true; else - backendData = false; - assertTrue((((Boolean) backendData).booleanValue() == ((Boolean) retrieved).booleanValue()), "Unexpected bit value, expected: " - + ((Boolean) backendData).booleanValue() + " ,received: " + ((Boolean) retrieved).booleanValue()); + expectedData = false; + assertTrue((((Boolean) expectedData).booleanValue() == ((Boolean) retrieved).booleanValue()), "Unexpected bit value, expected: " + + ((Boolean) expectedData).booleanValue() + " ,received: " + ((Boolean) retrieved).booleanValue()); break; case java.sql.Types.DECIMAL: case java.sql.Types.NUMERIC: - assertTrue(0 == (((BigDecimal) backendData).compareTo((BigDecimal) retrieved)), "Unexpected decimal/numeric/money/smallmoney value " - + ",expected: " + (BigDecimal) backendData + " received: " + (BigDecimal) retrieved); + assertTrue(0 == (((BigDecimal) expectedData).compareTo((BigDecimal) retrieved)), "Unexpected decimal/numeric/money/smallmoney value " + + ",expected: " + (BigDecimal) expectedData + " received: " + (BigDecimal) retrieved); break; case java.sql.Types.DOUBLE: - assertTrue((((Double) backendData).doubleValue() == ((Double) retrieved).doubleValue()), "Unexpected float value, expected: " - + ((Double) backendData).doubleValue() + " received: " + ((Double) retrieved).doubleValue()); + assertTrue((((Double) expectedData).doubleValue() == ((Double) retrieved).doubleValue()), "Unexpected float value, expected: " + + ((Double) expectedData).doubleValue() + " received: " + ((Double) retrieved).doubleValue()); break; case java.sql.Types.REAL: - assertTrue((((Float) backendData).floatValue() == ((Float) retrieved).floatValue()), - "Unexpected real value, expected: " + ((Float) backendData).floatValue() + " received: " + ((Float) retrieved).floatValue()); + assertTrue((((Float) expectedData).floatValue() == ((Float) retrieved).floatValue()), + "Unexpected real value, expected: " + ((Float) expectedData).floatValue() + " received: " + ((Float) retrieved).floatValue()); break; case java.sql.Types.VARCHAR: case java.sql.Types.NVARCHAR: - assertTrue((((String) backendData).trim().equalsIgnoreCase(((String) retrieved).trim())), "Unexpected varchar/nvarchar value, " - + "expected: " + ((String) backendData).trim() + " ,received: " + ((String) retrieved).trim()); + assertTrue((((String) expectedData).trim().equalsIgnoreCase(((String) retrieved).trim())), "Unexpected varchar/nvarchar value, " + + "expected: " + ((String) expectedData).trim() + " ,received: " + ((String) retrieved).trim()); break; case java.sql.Types.CHAR: case java.sql.Types.NCHAR: - assertTrue((((String) backendData).trim().equalsIgnoreCase(((String) retrieved).trim())), "Unexpected char/nchar value, " - + "expected: " + ((String) backendData).trim() + " ,received: " + ((String) retrieved).trim()); + assertTrue((((String) expectedData).trim().equalsIgnoreCase(((String) retrieved).trim())), "Unexpected char/nchar value, " + + "expected: " + ((String) expectedData).trim() + " ,received: " + ((String) retrieved).trim()); break; case java.sql.Types.TIMESTAMP: if (metaData.getColumnTypeName(ordinal + 1).equalsIgnoreCase("datetime")) { - assertTrue((((Timestamp) roundDatetimeValue(backendData)).getTime() == (((Timestamp) retrieved).getTime())), - "Unexpected datetime value, expected: " + ((Timestamp) roundDatetimeValue(backendData)).getTime() + " , received: " + assertTrue((((Timestamp) roundDatetimeValue(expectedData)).getTime() == (((Timestamp) retrieved).getTime())), + "Unexpected datetime value, expected: " + ((Timestamp) roundDatetimeValue(expectedData)).getTime() + " , received: " + (((Timestamp) retrieved).getTime())); break; } else if (metaData.getColumnTypeName(ordinal + 1).equalsIgnoreCase("smalldatetime")) { - assertTrue((((Timestamp) roundSmallDateTimeValue(backendData)).getTime() == (((Timestamp) retrieved).getTime())), - "Unexpected smalldatetime value, expected: " + ((Timestamp) roundSmallDateTimeValue(backendData)).getTime() + assertTrue((((Timestamp) roundSmallDateTimeValue(expectedData)).getTime() == (((Timestamp) retrieved).getTime())), + "Unexpected smalldatetime value, expected: " + ((Timestamp) roundSmallDateTimeValue(expectedData)).getTime() + " ,received: " + (((Timestamp) retrieved).getTime())); break; } else - assertTrue(("" + Timestamp.valueOf((LocalDateTime) backendData)).equalsIgnoreCase("" + retrieved), "Unexpected datetime2 value, " - + "expected: " + Timestamp.valueOf((LocalDateTime) backendData) + " ,received: " + retrieved); + assertTrue(("" + Timestamp.valueOf((LocalDateTime) expectedData)).equalsIgnoreCase("" + retrieved), "Unexpected datetime2 value, " + + "expected: " + Timestamp.valueOf((LocalDateTime) expectedData) + " ,received: " + retrieved); break; case java.sql.Types.DATE: - assertTrue((("" + backendData).equalsIgnoreCase("" + retrieved)), - "Unexpected date value, expected: " + backendData + " ,received: " + retrieved); + assertTrue((("" + expectedData).equalsIgnoreCase("" + retrieved)), + "Unexpected date value, expected: " + expectedData + " ,received: " + retrieved); break; case java.sql.Types.TIME: - assertTrue(("" + Time.valueOf((LocalTime) backendData)).equalsIgnoreCase("" + retrieved), - "Unexpected time value, exptected: " + Time.valueOf((LocalTime) backendData) + " ,received: " + retrieved); + assertTrue(("" + Time.valueOf((LocalTime) expectedData)).equalsIgnoreCase("" + retrieved), + "Unexpected time value, exptected: " + Time.valueOf((LocalTime) expectedData) + " ,received: " + retrieved); break; case microsoft.sql.Types.DATETIMEOFFSET: - assertTrue(("" + backendData).equals("" + retrieved), - " unexpected DATETIMEOFFSET value, expected: " + backendData + " ,received: " + retrieved); + assertTrue(("" + expectedData).equals("" + retrieved), + " unexpected DATETIMEOFFSET value, expected: " + expectedData + " ,received: " + retrieved); break; default: @@ -250,26 +257,6 @@ else if (metaData.getColumnTypeName(ordinal + 1).equalsIgnoreCase("smalldatetime } } - /** - * Retrieves the current row of the table - * - * @return - */ - public ArrayList currentrow() { - return currentTable.getAllRows().get(_currentrow); - } - - /** - * Get the indexed row from the backend data for the specific table - * - * @param table - * @param index - * @return - */ - public static ArrayList getRow(DBTable table, int index) { - return table.getAllRows().get(index); - } - private Object getXXX(int idx, Class coercion) throws SQLException { if (coercion == Object.class) { return this.getObject(idx); diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetTypes.java b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetTypes.java new file mode 100644 index 000000000..63a47c6ed --- /dev/null +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetTypes.java @@ -0,0 +1,33 @@ +/* + * Microsoft JDBC Driver for SQL Server + * + * Copyright(c) 2016 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.testframework; + +/** + * @author Microsoft + * + */ + +public enum DBResultSetTypes { + + TYPE_FORWARD_ONLY_CONCUR_READ_ONLY(DBResultSet.TYPE_FORWARD_ONLY, DBResultSet.CONCUR_READ_ONLY), TYPE_SCROLL_INSENSITIVE_CONCUR_READ_ONLY( + DBResultSet.TYPE_SCROLL_INSENSITIVE, DBResultSet.CONCUR_READ_ONLY), TYPE_SCROLL_SENSITIVE_CONCUR_READ_ONLY( + DBResultSet.TYPE_SCROLL_SENSITIVE, DBResultSet.CONCUR_READ_ONLY), TYPE_FORWARD_ONLY_CONCUR_UPDATABLE( + DBResultSet.TYPE_FORWARD_ONLY, DBResultSet.CONCUR_UPDATABLE), TYPE_SCROLL_SENSITIVE_CONCUR_UPDATABLE( + DBResultSet.TYPE_SCROLL_SENSITIVE, DBResultSet.CONCUR_UPDATABLE), TYPE_DYNAMIC_CONCUR_OPTIMISTIC( + DBResultSet.TYPE_DYNAMIC, DBResultSet.CONCUR_OPTIMISTIC), TYPE_CURSOR_FORWARDONLY_CONCUR_UPDATABLE( + DBResultSet.TYPE_CURSOR_FORWARDONLY, DBResultSet.CONCUR_READ_ONLY),; + + public int resultsetCursor; + public int resultSetConcurrency; + + DBResultSetTypes(int resultSetCursor, int resultSetConcurrency) { + this.resultsetCursor = resultSetCursor; + this.resultSetConcurrency = resultSetConcurrency; + } + +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java b/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java index 11a52d974..fc483873f 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java @@ -35,6 +35,8 @@ import java.util.logging.Level; import java.util.logging.Logger; +import org.apache.commons.codec.binary.Hex; + import com.microsoft.sqlserver.testframework.sqlType.SqlType; import com.microsoft.sqlserver.testframework.sqlType.VariableLengthType; import com.microsoft.sqlserver.testframework.util.RandomUtil; @@ -72,8 +74,6 @@ public DBTable(boolean autoGenerateSchema) { this.columns = new ArrayList(); } this.totalColumns = columns.size(); - this.currentrow = new ArrayList(); - this.rows = new ArrayList>(); } /** @@ -132,7 +132,7 @@ public static int getTotalRows() { /** * * @param totalRows - * set the number of rows in table, default value is 2 + * set the number of rows in table, default value is 3 */ public void setTotalRows(int totalRows) { this.totalRows = totalRows; @@ -252,19 +252,15 @@ String populateTableSql() { sb.add(OPEN_BRACKET); for (int colNum = 0; colNum < totalColumns; colNum++) { - // TODO: add betterway to enclose data - if (JDBCType.CHAR == getColumn(colNum).getSqlType().getJdbctype() || JDBCType.VARCHAR == getColumn(colNum).getSqlType().getJdbctype() - || JDBCType.NCHAR == getColumn(colNum).getSqlType().getJdbctype() - || JDBCType.NVARCHAR == getColumn(colNum).getSqlType().getJdbctype() - || JDBCType.TIMESTAMP == getColumn(colNum).getSqlType().getJdbctype() - || JDBCType.DATE == getColumn(colNum).getSqlType().getJdbctype() - || JDBCType.TIME == getColumn(colNum).getSqlType().getJdbctype()) { + // TODO: consider how to enclose data in case of preparedStatemets + if (passDataAsString(colNum)) { sb.add("'" + String.valueOf(getColumn(colNum).getRowValue(i)) + "'"); - currentrow.add(getColumn(colNum).getRowValue(i)); + } + else if (passDataAsHex(colNum)) { + sb.add("0X" + Hex.encodeHexString((byte[]) (getColumn(colNum).getRowValue(i)))); } else { sb.add(String.valueOf(getColumn(colNum).getRowValue(i))); - currentrow.add(getColumn(colNum).getRowValue(i)); } if (colNum < totalColumns - 1) { @@ -272,8 +268,6 @@ String populateTableSql() { } } sb.add(CLOSE_BRACKET); - rows.add(currentrow); - currentrow = new ArrayList(); } return (sb.toString()); @@ -341,8 +335,32 @@ DBColumn getColumn(int index) { return columns.get(index); } - public ArrayList> getAllRows() { - return rows; + public List getColumns() { + return columns; + } + + public Object getRowData(int colIndex, int rowIndex) { + return columns.get(colIndex).getRowValue(rowIndex); } + /** + * + * @param colNum + * @return true if value can be passed as String for the column + */ + boolean passDataAsString(int colNum) { + return (JDBCType.CHAR == getColumn(colNum).getJdbctype() || JDBCType.VARCHAR == getColumn(colNum).getJdbctype() + || JDBCType.NCHAR == getColumn(colNum).getJdbctype() || JDBCType.NVARCHAR == getColumn(colNum).getJdbctype() + || JDBCType.TIMESTAMP == getColumn(colNum).getJdbctype() || JDBCType.DATE == getColumn(colNum).getJdbctype() + || JDBCType.TIME == getColumn(colNum).getJdbctype()); + } + + /** + * + * @param colNum + * @return true if value can be passed as Hex for the column + */ + boolean passDataAsHex(int colNum) { + return (JDBCType.BINARY == getColumn(colNum).getJdbctype() || JDBCType.VARBINARY == getColumn(colNum).getJdbctype()); + } } diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlChar.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlChar.java index e54f5ad72..c9012b4b3 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlChar.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlChar.java @@ -33,7 +33,7 @@ import org.apache.commons.lang3.RandomStringUtils; /* - * Restricting the size of char/varchar to 4000 and nchar/nvarchar to 2000 to accommodate SQL Sever limitation of having of having maximum allowable + * Restricting the size of char/binary to 2000 and nchar to 1000 to accommodate SQL Sever limitation of having of having maximum allowable * table row size to 8060 */ public class SqlChar extends SqlType { From 697d4ebeb696ec7f8e673f6d5541e7a28a3facb2 Mon Sep 17 00:00:00 2001 From: v-afrafi Date: Thu, 19 Jan 2017 11:35:27 -0800 Subject: [PATCH 14/28] added binary/varbinary verification --- .../sqlserver/testframework/DBResultSet.java | 18 ++++++ .../sqlserver/testframework/DBTable.java | 57 ++----------------- 2 files changed, 22 insertions(+), 53 deletions(-) diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java index a079b15fc..a97c330bb 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java @@ -251,11 +251,29 @@ else if (metaData.getColumnTypeName(ordinal + 1).equalsIgnoreCase("smalldatetime " unexpected DATETIMEOFFSET value, expected: " + expectedData + " ,received: " + retrieved); break; + case java.sql.Types.BINARY: + assertTrue(parseByte((byte[])expectedData, (byte[])retrieved), + " unexpected BINARY value, expected: " + expectedData + " ,received: " + retrieved); + break; + + case java.sql.Types.VARBINARY: + assertTrue(parseByte((byte[])expectedData, (byte[])retrieved), + " unexpected BINARY value, expected: " + expectedData + " ,received: " + retrieved); + break; default: fail("Unhandled JDBCType " + JDBCType.valueOf(metaData.getColumnType(ordinal + 1))); break; } } + + private boolean parseByte(byte[] expectedData, byte[] retrieved) { + for (int j = 0; j < expectedData.length; j++) { + assertTrue( + expectedData[j] == retrieved[j] && expectedData[j] == retrieved[j] && expectedData[j] == retrieved[j], + " unexpected BINARY value, expected"); + } + return true; + } private Object getXXX(int idx, Class coercion) throws SQLException { if (coercion == Object.class) { diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java b/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java index 26cb0e8b9..2442fc023 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java @@ -335,53 +335,21 @@ DBColumn getColumn(int index) { return columns.get(index); } - public List getColumns() { - return columns; - } - - public Object getRowData(int colIndex, int rowIndex) { - return columns.get(colIndex).getRowValue(rowIndex); - } - - /** - * - * @param colNum - * @return true if value can be passed as String for the column - */ - boolean passDataAsString(int colNum) { - return (JDBCType.CHAR == getColumn(colNum).getJdbctype() || JDBCType.VARCHAR == getColumn(colNum).getJdbctype() - || JDBCType.NCHAR == getColumn(colNum).getJdbctype() || JDBCType.NVARCHAR == getColumn(colNum).getJdbctype() - || JDBCType.TIMESTAMP == getColumn(colNum).getJdbctype() || JDBCType.DATE == getColumn(colNum).getJdbctype() - || JDBCType.TIME == getColumn(colNum).getJdbctype()); - } - /** * - * @param colNum - * @return true if value can be passed as Hex for the column + * @param colIndex + * @param rowIndex + * @return */ - boolean passDataAsHex(int colNum) { - return (JDBCType.BINARY == getColumn(colNum).getJdbctype() || JDBCType.VARBINARY == getColumn(colNum).getJdbctype()); - } -<<<<<<< HEAD - - public List getColumns() { - return columns; - } - public Object getRowData(int colIndex, int rowIndex) { return columns.get(colIndex).getRowValue(rowIndex); } -======= - ->>>>>>> 85dd53d41a6d634a76d0a4872b4eaf0a2d2ccf4f /** * * @param colNum * @return true if value can be passed as String for the column */ -<<<<<<< HEAD boolean passDataAsString(int colNum) { return (JDBCType.CHAR == getColumn(colNum).getJdbctype() || JDBCType.VARCHAR == getColumn(colNum).getJdbctype() || JDBCType.NCHAR == getColumn(colNum).getJdbctype() || JDBCType.NVARCHAR == getColumn(colNum).getJdbctype() @@ -389,30 +357,13 @@ boolean passDataAsString(int colNum) { || JDBCType.TIME == getColumn(colNum).getJdbctype()); } -======= - boolean passDataAsString(int colNum){ - return (JDBCType.CHAR == getColumn(colNum).getJdbctype() - || JDBCType.VARCHAR == getColumn(colNum).getJdbctype() - || JDBCType.NCHAR == getColumn(colNum).getJdbctype() - || JDBCType.NVARCHAR == getColumn(colNum).getJdbctype() - || JDBCType.TIMESTAMP == getColumn(colNum).getJdbctype() - || JDBCType.DATE == getColumn(colNum).getJdbctype() - || JDBCType.TIME == getColumn(colNum).getJdbctype()); - } - ->>>>>>> 85dd53d41a6d634a76d0a4872b4eaf0a2d2ccf4f /** * * @param colNum * @return true if value can be passed as Hex for the column */ -<<<<<<< HEAD + boolean passDataAsHex(int colNum) { return (JDBCType.BINARY == getColumn(colNum).getJdbctype() || JDBCType.VARBINARY == getColumn(colNum).getJdbctype()); -======= - boolean passDataAsHex(int colNum){ - return (JDBCType.BINARY == getColumn(colNum).getJdbctype() - || JDBCType.VARBINARY == getColumn(colNum).getJdbctype()); ->>>>>>> 85dd53d41a6d634a76d0a4872b4eaf0a2d2ccf4f } } From b7a85ce2913fde67424f92304eee1caa49331e04 Mon Sep 17 00:00:00 2001 From: v-afrafi Date: Fri, 20 Jan 2017 16:52:43 -0800 Subject: [PATCH 15/28] post review commits --- .../microsoft/sqlserver/jdbc/bvt/bvtTest.java | 38 +++++-- .../sqlserver/testframework/DBColumn.java | 2 +- .../sqlserver/testframework/DBConnection.java | 2 +- .../testframework/DBPreparedStatement.java | 46 +++----- .../sqlserver/testframework/DBResultSet.java | 91 +++++++--------- .../testframework/DBResultSetMetaData.java | 103 ++++++++---------- .../testframework/DBResultSetTypes.java | 16 +-- .../sqlserver/testframework/DBStatement.java | 4 - .../sqlserver/testframework/DBTable.java | 33 ++---- .../testframework/sqlType/SqlChar.java | 10 +- .../sqlType/SqlDateTimeOffset.java | 63 +++++------ .../testframework/sqlType/SqlType.java | 3 +- .../testframework/sqlType/SqlTypeValue.java | 4 +- 13 files changed, 183 insertions(+), 232 deletions(-) diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTest.java index c5471df70..42f99478e 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTest.java @@ -1,14 +1,14 @@ /* * Microsoft JDBC Driver for SQL Server * - * Copyright(c) 2016 Microsoft Corporation All rights reserved. + * 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.bvt; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import java.math.BigDecimal; @@ -17,7 +17,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.junit.AfterClass; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.platform.runner.JUnitPlatform; @@ -64,9 +64,9 @@ public void testConnection() throws SQLException { public void testConnectionIsClosed() throws SQLException { try { conn = new DBConnection(connectionString); - assertTrue("BVT connection should not be closed", !conn.isClosed()); + assertTrue(!conn.isClosed(), "BVT connection should not be closed"); conn.close(); - assertTrue("BVT connection should not be open", conn.isClosed()); + assertTrue(conn.isClosed(), "BVT connection should not be open"); } finally { terminateVariation(); @@ -85,10 +85,10 @@ public void testDriverNameAndDriverVersion() throws SQLException { DatabaseMetaData metaData = conn.getMetaData(); Pattern p = Pattern.compile(driverNamePattern); Matcher m = p.matcher(metaData.getDriverName()); - assertTrue("Driver name is not a correct format! ", m.find()); + assertTrue(m.find(), "Driver name is not a correct format! "); String[] parts = metaData.getDriverVersion().split("\\."); if (parts.length != 4) - assertTrue("Driver version number should be four parts! ", true); + assertTrue(true, "Driver version number should be four parts! "); } finally { terminateVariation(); @@ -109,9 +109,9 @@ public void testCreateStatement() throws SQLException { String query = "SELECT * FROM " + table1.getEscapedTableName() + ";"; rs = stmt.executeQuery(query); rs.verify(table1); + rs.close(); } finally { - terminateVariation(); } } @@ -157,7 +157,7 @@ public void testStmtForwardOnlyReadOnly() throws SQLException, ClassNotFoundExce try { rs.previous(); - assertTrue("Previous should have thrown an exception", false); + assertTrue(false, "Previous should have thrown an exception"); } catch (SQLException ex) { // expected exception @@ -249,7 +249,7 @@ public void testStmtForwardOnlyUpdateable() throws SQLException { rs.verifyCurrentRow(table1); try { rs.previous(); - assertTrue("Previous should have thrown an exception", false); + assertTrue(false, "Previous should have thrown an exception"); } catch (SQLException ex) { // expected exception @@ -544,6 +544,7 @@ public void testResultSetAndCloseStmt() throws SQLException { catch (SQLException e) { assertEquals(e.toString(), "com.microsoft.sqlserver.jdbc.SQLServerException: The result set is closed."); } + assertTrue(true, "Previouse one should have thrown exception!"); } finally { terminateVariation(); @@ -572,17 +573,30 @@ public void testResultSetSelectMethod() throws SQLException { } } - @AfterClass + /** + * drops tables + * + * @throws SQLException + */ + @AfterAll public static void terminate() throws SQLException { try { + conn = new DBConnection(connectionString); stmt = conn.createStatement(); + stmt.execute("if object_id('" + table1.getEscapedTableName() + "','U') is not null" + " drop table " + table1.getEscapedTableName()); + stmt.execute("if object_id('" + table2.getEscapedTableName() + "','U') is not null" + " drop table " + table2.getEscapedTableName()); } finally { terminateVariation(); } } + /** + * cleanup after tests + * + * @throws SQLException + */ public static void terminateVariation() throws SQLException { if (conn != null && !conn.isClosed()) { try { diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBColumn.java b/src/test/java/com/microsoft/sqlserver/testframework/DBColumn.java index 70aad6320..796a72208 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBColumn.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBColumn.java @@ -104,7 +104,7 @@ void populateValues(int rows) { * @param row * @return the value populated for the column */ - public Object getRowValue(int row) { + Object getRowValue(int row) { // handle exceptions return columnValues.get(row); } diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBConnection.java b/src/test/java/com/microsoft/sqlserver/testframework/DBConnection.java index 3673b62c4..25a116126 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBConnection.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBConnection.java @@ -126,7 +126,7 @@ public DBStatement createStatement(DBResultSetTypes rsType) throws SQLServerExce * @throws SQLException */ public DBPreparedStatement prepareStatement(String query) throws SQLException { - DBPreparedStatement dbpstmt = new DBPreparedStatement(this, internal, "preparedStatement"); + DBPreparedStatement dbpstmt = new DBPreparedStatement(this); return dbpstmt.prepareStatement(query); } diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBPreparedStatement.java b/src/test/java/com/microsoft/sqlserver/testframework/DBPreparedStatement.java index 4c18ecc45..ba8d230cb 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBPreparedStatement.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBPreparedStatement.java @@ -1,28 +1,10 @@ -// --------------------------------------------------------------------------------------------------------------------------------- -// File: DBPreparedStatement.java -// -// -// Microsoft JDBC Driver for SQL Server -// Copyright(c) Microsoft Corporation -// All rights reserved. -// MIT License -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files(the "Software"), -// to deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, -// and / or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions : -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// --------------------------------------------------------------------------------------------------------------------------------- - +/** + * 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.testframework; import java.sql.Connection; @@ -38,6 +20,13 @@ public class DBPreparedStatement extends AbstractParentWrapper { PreparedStatement pstmt = null; DBResultSet dbresultSet = null; + + /** + * + */ + public DBPreparedStatement(DBConnection dbconnection) { + super(dbconnection, null, "preparedStatement"); + } /** * @param parent @@ -53,7 +42,7 @@ public class DBPreparedStatement extends AbstractParentWrapper { * */ DBPreparedStatement prepareStatement(String query) throws SQLException { - pstmt = ((Connection) product()).prepareStatement(query); + pstmt = ((Connection) parent().product()).prepareStatement(query); setInternal(pstmt); return this; } @@ -64,8 +53,9 @@ void setInternal(Object internal) { } /** - * @param i - * @param bigDecimal + * + * @param parameterIndex + * @param targetObject * @throws SQLException */ public void setObject(int parameterIndex, Object targetObject) throws SQLException { diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java index a97c330bb..f7230822b 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java @@ -1,28 +1,10 @@ -// --------------------------------------------------------------------------------------------------------------------------------- -// File: DBResultSet.java -// -// -// Microsoft JDBC Driver for SQL Server -// Copyright(c) Microsoft Corporation -// All rights reserved. -// MIT License -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files(the "Software"), -// to deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, -// and / or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions : -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// --------------------------------------------------------------------------------------------------------------------------------- - +/** + * 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.testframework; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -31,13 +13,15 @@ import java.math.BigDecimal; import java.sql.JDBCType; import java.sql.ResultSet; -import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.sql.Time; import java.sql.Timestamp; import java.time.LocalDateTime; import java.time.LocalTime; +import java.util.Arrays; import java.util.Calendar; +import java.util.logging.Level; +import java.util.logging.Logger; /** * wrapper class for ResultSet @@ -51,6 +35,7 @@ public class DBResultSet extends AbstractParentWrapper { // TODO: add cursors // TODO: add resultSet level holdability // TODO: add concurrency control + public static final Logger log = Logger.getLogger("DBResultSet"); public static final int TYPE_DYNAMIC = ResultSet.TYPE_SCROLL_SENSITIVE + 1; public static final int CONCUR_OPTIMISTIC = ResultSet.CONCUR_UPDATABLE + 2; @@ -141,18 +126,16 @@ public void verifyCurrentRow(DBTable table) throws SQLException { Class _class = Object.class; for (int i = 0; i < totalColumns; i++) - verifydata(i, _class, null); - + verifydata(i, _class); } /** * * @param ordinal * @param coercion - * @param arg * @throws SQLException */ - public void verifydata(int ordinal, Class coercion, Object arg) throws SQLException { + public void verifydata(int ordinal, Class coercion) throws SQLException { Object expectedData = currentTable.columns.get(ordinal).getRowValue(_currentrow); // getXXX - default mapping @@ -162,6 +145,15 @@ public void verifydata(int ordinal, Class coercion, Object arg) throws SQLExcept verifydata(ordinal, coercion, expectedData, retrieved); } + /** + * verifies data + * + * @param ordinal + * @param coercion + * @param expectedData + * @param retrieved + * @throws SQLException + */ public void verifydata(int ordinal, Class coercion, Object expectedData, Object retrieved) throws SQLException { metaData = this.getMetaData(); switch (metaData.getColumnType(ordinal + 1)) { @@ -252,12 +244,12 @@ else if (metaData.getColumnTypeName(ordinal + 1).equalsIgnoreCase("smalldatetime break; case java.sql.Types.BINARY: - assertTrue(parseByte((byte[])expectedData, (byte[])retrieved), + assertTrue(parseByte((byte[]) expectedData, (byte[]) retrieved), " unexpected BINARY value, expected: " + expectedData + " ,received: " + retrieved); break; case java.sql.Types.VARBINARY: - assertTrue(parseByte((byte[])expectedData, (byte[])retrieved), + assertTrue(Arrays.equals((byte[]) expectedData, (byte[]) retrieved), " unexpected BINARY value, expected: " + expectedData + " ,received: " + retrieved); break; default: @@ -265,12 +257,11 @@ else if (metaData.getColumnTypeName(ordinal + 1).equalsIgnoreCase("smalldatetime break; } } - - private boolean parseByte(byte[] expectedData, byte[] retrieved) { - for (int j = 0; j < expectedData.length; j++) { - assertTrue( - expectedData[j] == retrieved[j] && expectedData[j] == retrieved[j] && expectedData[j] == retrieved[j], - " unexpected BINARY value, expected"); + + private boolean parseByte(byte[] expectedData, byte[] retrieved) { + assertTrue(Arrays.equals(expectedData, Arrays.copyOf(retrieved, expectedData.length)), " unexpected BINARY value, expected"); + for (int i = expectedData.length; i < retrieved.length; i++) { + assertTrue(0 == retrieved[i], "unexpected data BINARY"); } return true; } @@ -279,25 +270,25 @@ private Object getXXX(int idx, Class coercion) throws SQLException { if (coercion == Object.class) { return this.getObject(idx); } + else { + if (log.isLoggable(Level.FINE)) { + log.fine("coercion not supported! "); + } + else { + log.fine("coercion + " + coercion.toString() + " is not supported!"); + } + } return null; } /** * * @return + * @throws SQLException */ - public DBResultSetMetaData getMetaData() { - ResultSetMetaData product = null; - DBResultSetMetaData wrapper = null; - try { - product = resultSet.getMetaData(); - wrapper = new DBResultSetMetaData(parent, product, name); - } - catch (SQLException e) { - fail(e.getMessage()); - } - - return wrapper; + public DBResultSetMetaData getMetaData() throws SQLException { + DBResultSetMetaData metaData = new DBResultSetMetaData(this); + return metaData.getMetaData(); } /** diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetMetaData.java b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetMetaData.java index e5b29fbb0..11ddf8bc6 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetMetaData.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetMetaData.java @@ -1,42 +1,28 @@ -// --------------------------------------------------------------------------------------------------------------------------------- -// File: DBResultSetMetaData.java -// -// -// Microsoft JDBC Driver for SQL Server -// Copyright(c) Microsoft Corporation -// All rights reserved. -// MIT License -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files(the "Software"), -// to deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, -// and / or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions : -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// --------------------------------------------------------------------------------------------------------------------------------- +/* + * 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.testframework; -import static org.junit.Assert.fail; - +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; import java.sql.SQLException; import com.microsoft.sqlserver.jdbc.SQLServerResultSetMetaData; /** * - * + * Wrapper class for ResultSetMetaData */ public class DBResultSetMetaData extends AbstractParentWrapper { + DBResultSetMetaData dbresultSetMetaData = null; + ResultSetMetaData resultSetMetaData = null; + /** * @param parent * @param internal @@ -47,6 +33,28 @@ public class DBResultSetMetaData extends AbstractParentWrapper { // TODO Auto-generated constructor stub } + /** + * + */ + public DBResultSetMetaData(DBResultSet dbresultset) { + super(dbresultset, null, "dbresultset"); + } + + DBResultSetMetaData resultSetMetaData() { + return this; + } + + /** + * + * @return + * @throws SQLException + */ + public DBResultSetMetaData getMetaData() throws SQLException { + resultSetMetaData = ((ResultSet) parent().product()).getMetaData(); + setInternal(resultSetMetaData); + return this; + } + /** * * @throws SQLException @@ -76,14 +84,7 @@ public void verify() throws SQLException { * @throws SQLException */ public int getColumnCount() throws SQLException { - int current = 0; - try { - current = ((SQLServerResultSetMetaData) product()).getColumnCount(); - } - catch (SQLException e) { - fail(e.toString()); - } - return current; + return ((SQLServerResultSetMetaData) product()).getColumnCount(); } /** @@ -93,8 +94,7 @@ public int getColumnCount() throws SQLException { * @throws SQLException */ public String getColumnName(int index) throws SQLException { - String current = ((SQLServerResultSetMetaData) product()).getColumnName(index); - return current; + return ((SQLServerResultSetMetaData) product()).getColumnName(index); } /** @@ -104,8 +104,7 @@ public String getColumnName(int index) throws SQLException { * @throws SQLException */ public int getColumnType(int index) throws SQLException { - int current = ((SQLServerResultSetMetaData) product()).getColumnType(index); - return current; + return ((SQLServerResultSetMetaData) product()).getColumnType(index); } /** @@ -115,8 +114,7 @@ public int getColumnType(int index) throws SQLException { * @throws SQLException */ public String getColumnTypeName(int index) throws SQLException { - String current = ((SQLServerResultSetMetaData) product()).getColumnTypeName(index); - return current; + return ((SQLServerResultSetMetaData) product()).getColumnTypeName(index); } /** @@ -126,8 +124,7 @@ public String getColumnTypeName(int index) throws SQLException { * @throws SQLException */ public int getPrecision(int x) throws SQLException { - int current = ((SQLServerResultSetMetaData) product()).getPrecision(x); - return current; + return ((SQLServerResultSetMetaData) product()).getPrecision(x); } /** @@ -137,8 +134,7 @@ public int getPrecision(int x) throws SQLException { * @throws SQLException */ public int getScale(int x) throws SQLException { - int current = ((SQLServerResultSetMetaData) product()).getScale(x); - return current; + return ((SQLServerResultSetMetaData) product()).getScale(x); } /** @@ -148,8 +144,8 @@ public int getScale(int x) throws SQLException { * @throws SQLException */ public boolean isCaseSensitive(int x) throws SQLException { - boolean current = ((SQLServerResultSetMetaData) product()).isCaseSensitive(x); - return current; + return ((SQLServerResultSetMetaData) product()).isCaseSensitive(x); + } /** @@ -159,8 +155,7 @@ public boolean isCaseSensitive(int x) throws SQLException { * @throws SQLException */ public boolean isCurrency(int x) throws SQLException { - boolean current = ((SQLServerResultSetMetaData) product()).isCurrency(x); - return current; + return ((SQLServerResultSetMetaData) product()).isCurrency(x); } /** @@ -170,8 +165,7 @@ public boolean isCurrency(int x) throws SQLException { * @throws SQLException */ public boolean isAutoIncrement(int x) throws SQLException { - boolean current = ((SQLServerResultSetMetaData) product()).isAutoIncrement(x); - return current; + return ((SQLServerResultSetMetaData) product()).isAutoIncrement(x); } /** @@ -181,8 +175,7 @@ public boolean isAutoIncrement(int x) throws SQLException { * @throws SQLException */ public int isNullable(int x) throws SQLException { - int current = ((SQLServerResultSetMetaData) product()).isNullable(x); - return current; + return ((SQLServerResultSetMetaData) product()).isNullable(x); } /** @@ -192,7 +185,7 @@ public int isNullable(int x) throws SQLException { * @throws SQLException */ public boolean isSigned(int x) throws SQLException { - boolean current = ((SQLServerResultSetMetaData) product()).isSigned(x); - return current; + return ((SQLServerResultSetMetaData) product()).isSigned(x); } + } diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetTypes.java b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetTypes.java index 63a47c6ed..d1af9baf7 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetTypes.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetTypes.java @@ -1,7 +1,7 @@ /* * Microsoft JDBC Driver for SQL Server * - * Copyright(c) 2016 Microsoft Corporation All rights reserved. + * 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. */ @@ -14,13 +14,13 @@ public enum DBResultSetTypes { - TYPE_FORWARD_ONLY_CONCUR_READ_ONLY(DBResultSet.TYPE_FORWARD_ONLY, DBResultSet.CONCUR_READ_ONLY), TYPE_SCROLL_INSENSITIVE_CONCUR_READ_ONLY( - DBResultSet.TYPE_SCROLL_INSENSITIVE, DBResultSet.CONCUR_READ_ONLY), TYPE_SCROLL_SENSITIVE_CONCUR_READ_ONLY( - DBResultSet.TYPE_SCROLL_SENSITIVE, DBResultSet.CONCUR_READ_ONLY), TYPE_FORWARD_ONLY_CONCUR_UPDATABLE( - DBResultSet.TYPE_FORWARD_ONLY, DBResultSet.CONCUR_UPDATABLE), TYPE_SCROLL_SENSITIVE_CONCUR_UPDATABLE( - DBResultSet.TYPE_SCROLL_SENSITIVE, DBResultSet.CONCUR_UPDATABLE), TYPE_DYNAMIC_CONCUR_OPTIMISTIC( - DBResultSet.TYPE_DYNAMIC, DBResultSet.CONCUR_OPTIMISTIC), TYPE_CURSOR_FORWARDONLY_CONCUR_UPDATABLE( - DBResultSet.TYPE_CURSOR_FORWARDONLY, DBResultSet.CONCUR_READ_ONLY),; + TYPE_FORWARD_ONLY_CONCUR_READ_ONLY(DBResultSet.TYPE_FORWARD_ONLY, DBResultSet.CONCUR_READ_ONLY), + TYPE_SCROLL_INSENSITIVE_CONCUR_READ_ONLY(DBResultSet.TYPE_SCROLL_INSENSITIVE, DBResultSet.CONCUR_READ_ONLY), + TYPE_SCROLL_SENSITIVE_CONCUR_READ_ONLY(DBResultSet.TYPE_SCROLL_SENSITIVE, DBResultSet.CONCUR_READ_ONLY), + TYPE_FORWARD_ONLY_CONCUR_UPDATABLE(DBResultSet.TYPE_FORWARD_ONLY, DBResultSet.CONCUR_UPDATABLE), + TYPE_SCROLL_SENSITIVE_CONCUR_UPDATABLE(DBResultSet.TYPE_SCROLL_SENSITIVE, DBResultSet.CONCUR_UPDATABLE), + TYPE_DYNAMIC_CONCUR_OPTIMISTIC( DBResultSet.TYPE_DYNAMIC, DBResultSet.CONCUR_OPTIMISTIC), + TYPE_CURSOR_FORWARDONLY_CONCUR_UPDATABLE(DBResultSet.TYPE_CURSOR_FORWARDONLY, DBResultSet.CONCUR_READ_ONLY),; public int resultsetCursor; public int resultSetConcurrency; diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBStatement.java b/src/test/java/com/microsoft/sqlserver/testframework/DBStatement.java index 0c85066ef..82309fe99 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBStatement.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBStatement.java @@ -51,10 +51,6 @@ public class DBStatement extends AbstractParentWrapper { super(dbConnection, null, "statement"); } - DBStatement(DBConnection parent, Statement internal, int type, int concurrency, int holdability) { - super(parent, null, "statement"); - } - DBStatement statement() { return this; } diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java b/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java index 2442fc023..7e2802939 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java @@ -1,27 +1,10 @@ -// --------------------------------------------------------------------------------------------------------------------------------- -// File: DBTable.java -// -// -// Microsoft JDBC Driver for SQL Server -// Copyright(c) Microsoft Corporation -// All rights reserved. -// MIT License -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files(the "Software"), -// to deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, -// and / or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions : -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// --------------------------------------------------------------------------------------------------------------------------------- +/* + * 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.testframework; @@ -53,8 +36,6 @@ public class DBTable extends AbstractSQLGenerator { int totalColumns; static int totalRows = 3; // default row count set to 3 DBSchema schema; - ArrayList> rows; - ArrayList currentrow; /** * Initializes {@link DBTable} with tableName, schema, and {@link DBColumns} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlChar.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlChar.java index 0c45f9671..ef4c66ba4 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlChar.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlChar.java @@ -26,15 +26,11 @@ package com.microsoft.sqlserver.testframework.sqlType; import java.sql.JDBCType; -import java.util.Random; import java.util.concurrent.ThreadLocalRandom; -import org.apache.commons.lang.StringEscapeUtils; -import org.apache.commons.lang3.RandomStringUtils; - /* - * Restricting the size of char/binary to 2000 and nchar to 1000 to accommodate SQL Sever limitation of having of having maximum allowable - * table row size to 8060 + * Restricting the size of char/binary to 2000 and nchar to 1000 to accommodate SQL Sever limitation of having of having maximum allowable table row + * size to 8060 */ public class SqlChar extends SqlType { @@ -83,7 +79,7 @@ private static String buildRandomString(int length, String charSet) { private static char pickRandomChar(String charSet) { int charSetLength = charSet.length(); - int randomIndex = r.nextInt(charSetLength); + int randomIndex = ThreadLocalRandom.current().nextInt(charSetLength); return charSet.charAt(randomIndex); } } \ No newline at end of file diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlDateTimeOffset.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlDateTimeOffset.java index f8cdadd74..5b2c6ae7f 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlDateTimeOffset.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlDateTimeOffset.java @@ -1,39 +1,24 @@ -// --------------------------------------------------------------------------------------------------------------------------------- -// File: SqlDateTimeOffset.java -// -// -// Microsoft JDBC Driver for SQL Server -// Copyright(c) Microsoft Corporation -// All rights reserved. -// MIT License -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files(the "Software"), -// to deal in the Software without restriction, including without limitation the -// rights to use, copy, modify, merge, publish, distribute, sublicense, -// and / or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions : -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -// --------------------------------------------------------------------------------------------------------------------------------- - +/* + * 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.testframework.sqlType; import java.sql.JDBCType; import java.sql.Timestamp; import java.util.Calendar; +import java.util.concurrent.ThreadLocalRandom; import microsoft.sql.DateTimeOffset; public class SqlDateTimeOffset extends SqlDateTime { - public static boolean returnMinMax = (0 == r.nextInt(5)); // 20% chance of return Min/Max value + public static boolean returnMinMax = (0 == ThreadLocalRandom.current().nextInt(5)); // 20% chance of return Min/Max value private static String numberCharSet2 = "123456789"; + DateTimeOffset maxDTS; + DateTimeOffset minDTS; // TODO: datetiemoffset can extend SqlDateTime2 // timezone is not supported in Timestamp so its useless to initialize @@ -45,21 +30,28 @@ public SqlDateTimeOffset() { this.precision = 7; this.variableLengthType = VariableLengthType.Precision; generatePrecision(); + maxDTS = calculateDateTimeOffsetMinMax("max", precision, (String) SqlTypeValue.DATETIMEOFFSET.maxValue); + minDTS = calculateDateTimeOffsetMinMax("min", precision, (String) SqlTypeValue.DATETIMEOFFSET.minValue); } + /** + * create data + */ public Object createdata() { return generateDatetimeoffset(this.precision); } + /** + * + * @param precision + * @return + */ public Object generateDatetimeoffset(Integer precision) { if (null == precision) { precision = 7; } - DateTimeOffset maxDTS = calculateDateTimeOffsetMinMax("max", precision, "9999-12-31 23:59:59"); - DateTimeOffset minDTS = calculateDateTimeOffsetMinMax("min", precision, "0001-01-01 00:00:00"); - long max = maxDTS.getTimestamp().getTime(); long min = minDTS.getTimestamp().getTime(); @@ -70,19 +62,18 @@ public Object generateDatetimeoffset(Integer precision) { } if (returnMinMax) { - if (r.nextBoolean()) { + if (ThreadLocalRandom.current().nextBoolean()) { return maxDTS; } else { - // return minDTS; - return calculateDateTimeOffsetMinMax("min", precision, "0001-01-01 00:00:00.0000000"); + return minDTS; } } int precisionDigits = buildPrecision(precision, numberCharSet2); ts.setNanos(precisionDigits); - int randomTimeZoneInMinutes = r.nextInt(1681) - 840; + int randomTimeZoneInMinutes = ThreadLocalRandom.current().nextInt(1681) - 840; return microsoft.sql.DateTimeOffset.valueOf(ts, randomTimeZoneInMinutes); } @@ -136,7 +127,7 @@ private static String calculatePrecisionDigits(int precision, String charSet) { private static Timestamp generateTimestamp(long max, long min) { if (returnMinMax) { - if (r.nextBoolean()) { + if (ThreadLocalRandom.current().nextBoolean()) { return new Timestamp(max); } else { @@ -145,7 +136,7 @@ private static Timestamp generateTimestamp(long max, long min) { } while (true) { - long longValue = r.nextLong(); + long longValue = ThreadLocalRandom.current().nextLong(); if (longValue >= min && longValue <= max) { return new Timestamp(longValue); @@ -155,7 +146,7 @@ private static Timestamp generateTimestamp(long max, long min) { private static char pickRandomChar(String charSet) { int charSetLength = charSet.length(); - int randomIndex = r.nextInt(charSetLength); + int randomIndex = ThreadLocalRandom.current().nextInt(charSetLength); return charSet.charAt(randomIndex); } } \ No newline at end of file diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlType.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlType.java index c759c6fe9..6ac548e84 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlType.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlType.java @@ -26,7 +26,6 @@ package com.microsoft.sqlserver.testframework.sqlType; import java.sql.JDBCType; -import java.util.Random; import java.util.concurrent.ThreadLocalRandom; public abstract class SqlType { @@ -40,7 +39,7 @@ public abstract class SqlType { protected Object maxvalue = null; protected Object nullvalue = null; // Primitives have non-null defaults protected VariableLengthType variableLengthType; - static Random r = new Random(); +// protected ThreadLocalRandom r; /** * diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlTypeValue.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlTypeValue.java index c14459157..a4309aee6 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlTypeValue.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlTypeValue.java @@ -51,9 +51,9 @@ enum SqlTypeValue { TIME ("00:00:00.0000000", "23:59:59.9999999", null), SMALLDATETIME ("19000101T00:00:00", "20790606T23:59:59", null), DATETIME2 ("00010101T00:00:00.0000000", "99991231T23:59:59.9999999", null), - DATETIMEOFFSET ("9999-12-31 23:59:59", "0001-01-01 00:00:00", null), + DATETIMEOFFSET ("0001-01-01 00:00:00", "9999-12-31 23:59:59", null), ; - + Object minValue; Object maxValue; Object nullValue; From e21facee42e59648d8c4254db521564ca46eb394 Mon Sep 17 00:00:00 2001 From: Suraiya Hameed Date: Tue, 24 Jan 2017 13:22:00 -0800 Subject: [PATCH 16/28] formatted source code --- .../java/com/microsoft/sqlserver/jdbc/AE.java | 260 +- .../sqlserver/jdbc/ActivityCorrelator.java | 205 +- .../sqlserver/jdbc/AuthenticationJNI.java | 348 +- .../com/microsoft/sqlserver/jdbc/Column.java | 952 +- .../com/microsoft/sqlserver/jdbc/DDC.java | 2801 ++- .../sqlserver/jdbc/DLLException.java | 355 +- .../microsoft/sqlserver/jdbc/DataTypes.java | 827 +- .../sqlserver/jdbc/FailOverInfo.java | 182 +- .../sqlserver/jdbc/FailOverMapSingleton.java | 148 +- .../microsoft/sqlserver/jdbc/IOBuffer.java | 15417 ++++++++-------- .../sqlserver/jdbc/ISQLServerBulkRecord.java | 76 +- .../jdbc/ISQLServerCallableStatement.java | 82 +- .../jdbc/ISQLServerCallableStatement42.java | 158 +- .../sqlserver/jdbc/ISQLServerConnection.java | 58 +- .../sqlserver/jdbc/ISQLServerDataRecord.java | 64 +- .../sqlserver/jdbc/ISQLServerDataSource.java | 430 +- .../jdbc/ISQLServerPreparedStatement.java | 54 +- .../jdbc/ISQLServerPreparedStatement42.java | 115 +- .../sqlserver/jdbc/ISQLServerResultSet.java | 102 +- .../sqlserver/jdbc/ISQLServerResultSet42.java | 140 +- .../sqlserver/jdbc/ISQLServerStatement.java | 53 +- .../sqlserver/jdbc/KerbAuthentication.java | 422 +- .../jdbc/KeyStoreProviderCommon.java | 321 +- .../sqlserver/jdbc/KeyVaultCredential.java | 89 +- .../sqlserver/jdbc/PLPInputStream.java | 526 +- .../microsoft/sqlserver/jdbc/Parameter.java | 2483 ++- .../sqlserver/jdbc/ParameterUtils.java | 256 +- .../sqlserver/jdbc/ReaderInputStream.java | 135 +- .../sqlserver/jdbc/SQLCollation.java | 371 +- .../sqlserver/jdbc/SQLJdbcVersion.java | 40 +- ...QLServerAeadAes256CbcHmac256Algorithm.java | 608 +- ...rverAeadAes256CbcHmac256EncryptionKey.java | 112 +- .../SQLServerAeadAes256CbcHmac256Factory.java | 114 +- .../sqlserver/jdbc/SQLServerBlob.java | 407 +- .../jdbc/SQLServerBulkCSVFileRecord.java | 994 +- .../sqlserver/jdbc/SQLServerBulkCopy.java | 5711 +++--- .../jdbc/SQLServerBulkCopy42Helper.java | 159 +- .../jdbc/SQLServerBulkCopyOptions.java | 217 +- .../jdbc/SQLServerCallableStatement.java | 3593 ++-- .../jdbc/SQLServerCallableStatement42.java | 313 +- .../sqlserver/jdbc/SQLServerClob.java | 601 +- ...ColumnEncryptionAzureKeyVaultProvider.java | 1087 +- ...umnEncryptionCertificateStoreProvider.java | 416 +- ...rColumnEncryptionJavaKeyStoreProvider.java | 520 +- ...erverColumnEncryptionKeyStoreProvider.java | 111 +- .../sqlserver/jdbc/SQLServerConnection.java | 10706 +++++------ .../SQLServerConnectionPoolDataSource.java | 124 +- .../jdbc/SQLServerConnectionPoolProxy.java | 1292 +- .../sqlserver/jdbc/SQLServerDataColumn.java | 101 +- .../sqlserver/jdbc/SQLServerDataSource.java | 1132 +- .../SQLServerDataSourceObjectFactory.java | 163 +- .../sqlserver/jdbc/SQLServerDataTable.java | 508 +- .../jdbc/SQLServerDatabaseMetaData.java | 3203 ++-- .../sqlserver/jdbc/SQLServerDriver.java | 932 +- .../jdbc/SQLServerEncryptionAlgorithm.java | 61 +- .../SQLServerEncryptionAlgorithmFactory.java | 55 +- ...LServerEncryptionAlgorithmFactoryList.java | 146 +- .../jdbc/SQLServerEncryptionType.java | 69 +- .../sqlserver/jdbc/SQLServerException.java | 513 +- .../sqlserver/jdbc/SQLServerJdbc41.java | 58 +- .../sqlserver/jdbc/SQLServerJdbc42.java | 69 +- ...LServerKeyVaultAuthenticationCallback.java | 52 +- .../sqlserver/jdbc/SQLServerMetaData.java | 378 +- .../sqlserver/jdbc/SQLServerNClob.java | 46 +- .../jdbc/SQLServerParameterMetaData.java | 1722 +- .../jdbc/SQLServerPooledConnection.java | 457 +- .../jdbc/SQLServerPreparedStatement.java | 4425 +++-- .../jdbc/SQLServerPreparedStatement42.java | 95 +- .../SQLServerPreparedStatement42Helper.java | 149 +- .../sqlserver/jdbc/SQLServerResource.java | 53 +- .../sqlserver/jdbc/SQLServerResultSet.java | 7528 ++++---- .../sqlserver/jdbc/SQLServerResultSet42.java | 203 +- .../jdbc/SQLServerResultSetMetaData.java | 399 +- .../sqlserver/jdbc/SQLServerSQLXML.java | 471 +- .../sqlserver/jdbc/SQLServerSavepoint.java | 149 +- .../jdbc/SQLServerSecurityUtility.java | 246 +- .../sqlserver/jdbc/SQLServerSortOrder.java | 45 +- .../sqlserver/jdbc/SQLServerStatement.java | 4032 ++-- ...erverStatementColumnEncryptionSetting.java | 68 +- .../sqlserver/jdbc/SQLServerSymmetricKey.java | 84 +- .../jdbc/SQLServerSymmetricKeyCache.java | 340 +- .../sqlserver/jdbc/SQLServerXAConnection.java | 126 +- .../sqlserver/jdbc/SQLServerXADataSource.java | 211 +- .../sqlserver/jdbc/SQLServerXAResource.java | 1643 +- .../sqlserver/jdbc/SSPIAuthentication.java | 39 +- .../sqlserver/jdbc/ScrollWindow.java | 139 +- .../sqlserver/jdbc/SimpleInputStream.java | 419 +- .../sqlserver/jdbc/StreamColInfo.java | 44 +- .../sqlserver/jdbc/StreamColumns.java | 479 +- .../microsoft/sqlserver/jdbc/StreamDone.java | 694 +- .../microsoft/sqlserver/jdbc/StreamError.java | 121 +- .../microsoft/sqlserver/jdbc/StreamInfo.java | 47 +- .../sqlserver/jdbc/StreamLoginAck.java | 73 +- .../sqlserver/jdbc/StreamPacket.java | 58 +- .../sqlserver/jdbc/StreamRetStatus.java | 54 +- .../sqlserver/jdbc/StreamRetValue.java | 100 +- .../microsoft/sqlserver/jdbc/StreamSSPI.java | 61 +- .../sqlserver/jdbc/StreamTabName.java | 53 +- .../microsoft/sqlserver/jdbc/StringUtils.java | 49 +- .../com/microsoft/sqlserver/jdbc/TVP.java | 898 +- .../sqlserver/jdbc/UDTTDSHeader.java | 56 +- .../com/microsoft/sqlserver/jdbc/Util.java | 1977 +- .../sqlserver/jdbc/XMLTDSHeader.java | 56 +- .../com/microsoft/sqlserver/jdbc/dtv.java | 7638 ++++---- .../microsoft/sqlserver/jdbc/tdsparser.java | 518 +- .../java/microsoft/sql/DateTimeOffset.java | 204 +- src/main/java/microsoft/sql/Types.java | 91 +- .../src/main/java/executeStoredProcedure.java | 327 +- .../adaptive/src/main/java/readLargeData.java | 280 +- .../src/main/java/updateLargeData.java | 292 +- .../src/main/java/AlwaysEncrypted.java | 351 +- .../AzureActiveDirectoryAuthentication.java | 170 +- .../connections/src/main/java/connectDS.java | 153 +- .../connections/src/main/java/connectURL.java | 161 +- .../datatypes/src/main/java/basicDT.java | 363 +- .../src/main/java/sqlxmlExample.java | 577 +- .../resultsets/src/main/java/cacheRS.java | 317 +- .../resultsets/src/main/java/retrieveRS.java | 252 +- .../resultsets/src/main/java/updateRS.java | 258 +- .../sparse/src/main/java/SparseColumns.java | 324 +- 120 files changed, 48198 insertions(+), 53982 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/AE.java b/src/main/java/com/microsoft/sqlserver/jdbc/AE.java index d24f6fe8e..6a4ddba13 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/AE.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/AE.java @@ -1,51 +1,38 @@ -//--------------------------------------------------------------------------------------------------------------------------------- -// File: AE.java -// -// -// Microsoft JDBC Driver for SQL Server -// Copyright(c) Microsoft Corporation -// All rights reserved. -// MIT License -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), -// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : -// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//--------------------------------------------------------------------------------------------------------------------------------- - +/* + * 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; import java.util.Vector; /** - * Represents a single encrypted value for a CEK. It contains the encrypted CEK,the store type, name,the key path and encryption algorithm. + * Represents a single encrypted value for a CEK. It contains the encrypted CEK,the store type, name,the key path and encryption algorithm. */ class EncryptionKeyInfo { - EncryptionKeyInfo( - byte[] encryptedKeyVal, - int dbId, - int keyId, - int keyVersion, - byte[] mdVersion, - String keyPathVal, - String keyStoreNameVal, - String algorithmNameVal) - { - encryptedKey = encryptedKeyVal; - databaseId = dbId; - cekId = keyId; - cekVersion = keyVersion; - cekMdVersion = mdVersion; - keyPath = keyPathVal; - keyStoreName = keyStoreNameVal; - algorithmName = algorithmNameVal; - } + EncryptionKeyInfo(byte[] encryptedKeyVal, + int dbId, + int keyId, + int keyVersion, + byte[] mdVersion, + String keyPathVal, + String keyStoreNameVal, + String algorithmNameVal) { + encryptedKey = encryptedKeyVal; + databaseId = dbId; + cekId = keyId; + cekVersion = keyVersion; + cekMdVersion = mdVersion; + keyPath = keyPathVal; + keyStoreName = keyStoreNameVal; + algorithmName = algorithmNameVal; + } - byte[] encryptedKey; // the encrypted "column encryption key" + byte[] encryptedKey; // the encrypted "column encryption key" int databaseId; int cekId; int cekVersion; @@ -53,80 +40,77 @@ class EncryptionKeyInfo { String keyPath; String keyStoreName; String algorithmName; - byte normalizationRuleVersion; + byte normalizationRuleVersion; } /** - * Represents a unique CEK as an entry in the CekTable. A unique (plaintext is unique) CEK can have multiple - * encrypted CEKs when using multiple CMKs. These encrypted CEKs are represented by a member vector. + * Represents a unique CEK as an entry in the CekTable. A unique (plaintext is unique) CEK can have multiple encrypted CEKs when using multiple CMKs. + * These encrypted CEKs are represented by a member vector. */ -class CekTableEntry -{ - static final private java.util.logging.Logger aeLogger = - java.util.logging.Logger.getLogger("com.microsoft.sqlserver.jdbc.AE"); - - Vector columnEncryptionKeyValues; - int ordinal; - int databaseId; - int cekId; - int cekVersion; - byte[] cekMdVersion; - - Vector getColumnEncryptionKeyValues() { - return columnEncryptionKeyValues; - } +class CekTableEntry { + static final private java.util.logging.Logger aeLogger = java.util.logging.Logger.getLogger("com.microsoft.sqlserver.jdbc.AE"); - int getOrdinal() { - return ordinal; - } + Vector columnEncryptionKeyValues; + int ordinal; + int databaseId; + int cekId; + int cekVersion; + byte[] cekMdVersion; - int getDatabaseId() { - return databaseId; - } + Vector getColumnEncryptionKeyValues() { + return columnEncryptionKeyValues; + } - int getCekId() { - return cekId; - } - - int getCekVersion() { - return cekVersion; - } + int getOrdinal() { + return ordinal; + } - byte[] getCekMdVersion() { - return cekMdVersion; - } - - CekTableEntry(int ordinalVal) - { + int getDatabaseId() { + return databaseId; + } + + int getCekId() { + return cekId; + } + + int getCekVersion() { + return cekVersion; + } + + byte[] getCekMdVersion() { + return cekMdVersion; + } + + CekTableEntry(int ordinalVal) { ordinal = ordinalVal; databaseId = 0; cekId = 0; cekVersion = 0; cekMdVersion = null; columnEncryptionKeyValues = new Vector(); - } - - int getSize(){ - return columnEncryptionKeyValues.size(); } - - void add(byte[] encryptedKey, int dbId, int keyId, int keyVersion, byte[] mdVersion, String keyPath, String keyStoreName, String algorithmName) { + + int getSize() { + return columnEncryptionKeyValues.size(); + } + + void add(byte[] encryptedKey, + int dbId, + int keyId, + int keyVersion, + byte[] mdVersion, + String keyPath, + String keyStoreName, + String algorithmName) { assert null != columnEncryptionKeyValues : "columnEncryptionKeyValues should already be initialized."; - if (aeLogger.isLoggable(java.util.logging.Level.FINE)){ - aeLogger.fine("Retrieving CEK values"); - } - - EncryptionKeyInfo encryptionKey = new EncryptionKeyInfo( - encryptedKey, - dbId, - keyId, - keyVersion, - mdVersion, - keyPath, - keyStoreName, - algorithmName); + if (aeLogger.isLoggable(java.util.logging.Level.FINE)) { + aeLogger.fine("Retrieving CEK values"); + } + + EncryptionKeyInfo encryptionKey = new EncryptionKeyInfo(encryptedKey, dbId, keyId, keyVersion, mdVersion, keyPath, keyStoreName, + algorithmName); columnEncryptionKeyValues.add(encryptionKey); if (0 == databaseId) { @@ -136,40 +120,36 @@ void add(byte[] encryptedKey, int dbId, int keyId, int keyVersion, byte[] mdVers cekMdVersion = mdVersion; } else { - assert(databaseId == dbId); - assert(cekId == keyId); - assert(cekVersion == keyVersion); + assert (databaseId == dbId); + assert (cekId == keyId); + assert (cekVersion == keyVersion); assert ((null != cekMdVersion) && (null != mdVersion) && (cekMdVersion.length == mdVersion.length)); } - } + } } /** * Contains all CEKs, each row represents one unique CEK (represented by CekTableEntry). */ -class CekTable -{ - CekTableEntry[] keyList; - - CekTable(int tableSize) - { - keyList = new CekTableEntry[tableSize]; - } - - int getSize() - { - return keyList.length; - } - - CekTableEntry getCekTableEntry(int index) - { - return keyList[index]; - } - - void setCekTableEntry(int index, CekTableEntry entry) - { - keyList[index] = entry; - } +class CekTable { + CekTableEntry[] keyList; + + CekTable(int tableSize) { + keyList = new CekTableEntry[tableSize]; + } + + int getSize() { + return keyList.length; + } + + CekTableEntry getCekTableEntry(int index) { + return keyList[index]; + } + + void setCekTableEntry(int index, + CekTableEntry entry) { + keyList[index] = entry; + } } /** @@ -275,17 +255,16 @@ enum DescribeParameterEncryptionResultSet1 { KeyEncryptionAlgorithm; private int value; - + // Column indexing starts from 1; - static{ - for (int i = 0; i < values().length; ++i) - { - values()[i].value = i + 1; - } + static { + for (int i = 0; i < values().length; ++i) { + values()[i].value = i + 1; + } } - int value() - { - return value; + + int value() { + return value; } } @@ -301,17 +280,16 @@ enum DescribeParameterEncryptionResultSet2 { NormalizationRuleVersion; private int value; - + // Column indexing starts from 1; - static{ - for (int i = 0; i < values().length; ++i) - { - values()[i].value = i + 1; - } + static { + for (int i = 0; i < values().length; ++i) { + values()[i].value = i + 1; + } + } + + int value() { + return value; } - int value() - { - return value; - } } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ActivityCorrelator.java b/src/main/java/com/microsoft/sqlserver/jdbc/ActivityCorrelator.java index 184bb4153..422ff7ca3 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ActivityCorrelator.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ActivityCorrelator.java @@ -1,127 +1,100 @@ -//--------------------------------------------------------------------------------------------------------------------------------- -// File: ActivityCorrelator.java -// -// -// Microsoft JDBC Driver for SQL Server -// Copyright(c) Microsoft Corporation -// All rights reserved. -// MIT License -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), -// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : -// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//--------------------------------------------------------------------------------------------------------------------------------- - +/* + * 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; -import java.lang.ThreadLocal; import java.util.UUID; /** * ActivityCorrelator provides the APIs to access the ActivityId in TLS */ -final class ActivityCorrelator -{ - - private static ThreadLocal ActivityIdTls = new ThreadLocal() - { - protected ActivityId initialValue() - { - return new ActivityId(); - } - }; - - // Get the current ActivityId in TLS - static ActivityId getCurrent() - { - // get the value in TLS, not reference - return ActivityIdTls.get(); - } - - // Increment the Sequence number of the ActivityId in TLS - // and return the ActivityId with new Sequence number - static ActivityId getNext() - { - // We need to call get() method on ThreadLocal to get - // the current value of ActivityId stored in TLS, - // then increment the sequence number. - - // Get the current ActivityId in TLS - ActivityId activityId = getCurrent(); - - // Increment the Sequence number - activityId.Increment(); - - - return activityId; - } - - static void setCurrentActivityIdSentFlag() - { - ActivityId activityId = getCurrent(); - activityId.setSentFlag(); - } - +final class ActivityCorrelator { + + private static ThreadLocal ActivityIdTls = new ThreadLocal() { + protected ActivityId initialValue() { + return new ActivityId(); + } + }; + + // Get the current ActivityId in TLS + static ActivityId getCurrent() { + // get the value in TLS, not reference + return ActivityIdTls.get(); + } + + // Increment the Sequence number of the ActivityId in TLS + // and return the ActivityId with new Sequence number + static ActivityId getNext() { + // We need to call get() method on ThreadLocal to get + // the current value of ActivityId stored in TLS, + // then increment the sequence number. + + // Get the current ActivityId in TLS + ActivityId activityId = getCurrent(); + + // Increment the Sequence number + activityId.Increment(); + + return activityId; + } + + static void setCurrentActivityIdSentFlag() { + ActivityId activityId = getCurrent(); + activityId.setSentFlag(); + } + } - + class ActivityId { - private final UUID Id; - private long Sequence; - private boolean isSentToServer; - - ActivityId() - { - Id = UUID.randomUUID(); - Sequence = 0; - isSentToServer= false; - } - - UUID getId() - { - return Id; - } - - long getSequence() - { - return Sequence; - } - - void Increment() - { - if (Sequence < 0xffffffffl) //to get to 32-bit unsigned - { - ++Sequence; - } - else - { - Sequence = 0; - } - - isSentToServer = false; - } - - void setSentFlag() - { - isSentToServer = true; - } - - boolean IsSentToServer() - { - return isSentToServer; - } - - @Override public String toString () - { - StringBuilder sb = new StringBuilder(); - sb.append(Id.toString()); - sb.append("-"); - sb.append(Sequence); - return sb.toString(); - } -} + private final UUID Id; + private long Sequence; + private boolean isSentToServer; + + ActivityId() { + Id = UUID.randomUUID(); + Sequence = 0; + isSentToServer = false; + } + + UUID getId() { + return Id; + } + + long getSequence() { + return Sequence; + } + + void Increment() { + if (Sequence < 0xffffffffl) // to get to 32-bit unsigned + { + ++Sequence; + } + else { + Sequence = 0; + } + isSentToServer = false; + } + + void setSentFlag() { + isSentToServer = true; + } + + boolean IsSentToServer() { + return isSentToServer; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(Id.toString()); + sb.append("-"); + sb.append(Sequence); + return sb.toString(); + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/AuthenticationJNI.java b/src/main/java/com/microsoft/sqlserver/jdbc/AuthenticationJNI.java index f63f960c8..f212d7674 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/AuthenticationJNI.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/AuthenticationJNI.java @@ -1,169 +1,199 @@ -//--------------------------------------------------------------------------------------------------------------------------------- -// File: AuthenticationJNI.java -// -// -// Microsoft JDBC Driver for SQL Server -// Copyright(c) Microsoft Corporation -// All rights reserved. -// MIT License -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), -// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : -// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//--------------------------------------------------------------------------------------------------------------------------------- - +/* + * 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; -class FedAuthDllInfo{ - byte[] accessTokenBytes = null; - long expiresIn = 0; +class FedAuthDllInfo { + byte[] accessTokenBytes = null; + long expiresIn = 0; - FedAuthDllInfo(byte[] accessTokenBytes, long expiresIn){ - this.accessTokenBytes = accessTokenBytes; - this.expiresIn = expiresIn; - } + FedAuthDllInfo(byte[] accessTokenBytes, + long expiresIn) { + this.accessTokenBytes = accessTokenBytes; + this.expiresIn = expiresIn; + } } /** * Encapsulation of the JNI native calls for trusted authentication. */ -final class AuthenticationJNI extends SSPIAuthentication -{ - private final static int maximumpointersize = 128; // we keep the SNI_Sec pointer - private static boolean enabled = false; - private static java.util.logging.Logger authLogger = java.util.logging.Logger.getLogger("com.microsoft.sqlserver.jdbc.internals.AuthenticationJNI"); - private static int sspiBlobMaxlen = 0; - private byte[] sniSec = new byte[maximumpointersize]; - private int sniSecLen[] = {0}; - private final String DNSName; - private final int port; - private SQLServerConnection con; - - private static final UnsatisfiedLinkError linkError; - static int GetMaxSSPIBlobSize(){return sspiBlobMaxlen;} - - static - { - UnsatisfiedLinkError temp=null; - // Load the DLL - try - { - String libName = "sqljdbc_auth"; - System.loadLibrary(libName); - int []pkg= new int[1]; - pkg[0]=0; - if(0==SNISecInitPackage(pkg, authLogger)) - { - sspiBlobMaxlen = pkg[0]; - } - else - throw new UnsatisfiedLinkError(); - enabled=true; - } - catch (UnsatisfiedLinkError e) - { - temp =e; - authLogger.warning("Failed to load the sqljdbc_auth.dll cause : " + e.getMessage()); - // This is not re-thrown on purpose - the constructor will terminate the properly with the appropriate error string - } - finally - { - linkError = temp; - } - - } - - AuthenticationJNI(SQLServerConnection con, String address, int serverport) throws SQLServerException - { - if(!enabled) - con.terminate(SQLServerException.DRIVER_ERROR_NONE, SQLServerException.getErrString("R_notConfiguredForIntegrated"), linkError); - - this.con = con; - DNSName = GetDNSName(address); - port = serverport; - } - - static FedAuthDllInfo getAccessTokenForWindowsIntegrated(String stsURL, String servicePrincipalName, String clientConnectionId, String clientId, long expirationFileTime) throws DLLException{ - FedAuthDllInfo dllInfo = ADALGetAccessTokenForWindowsIntegrated(stsURL, servicePrincipalName, clientConnectionId, clientId, expirationFileTime, authLogger); - return dllInfo; - } - - static FedAuthDllInfo getAccessToken(String userName, String password, String stsURL, String servicePrincipalName, String clientConnectionId, String clientId, long expirationFileTime) throws DLLException{ - FedAuthDllInfo dllInfo = ADALGetAccessToken(userName, password, stsURL, servicePrincipalName, clientConnectionId, clientId, expirationFileTime, authLogger); - return dllInfo; - } - - - // InitDNSName should be called to initialize the DNSName before calling this function - byte[] GenerateClientContext(byte[] pin, boolean[] done ) throws SQLServerException - { - byte[]pOut; - int[] outsize; // This is where the size of the filled data returned - outsize = new int[1]; - outsize[0] = GetMaxSSPIBlobSize(); - pOut = new byte[outsize[0]]; - - // assert DNSName cant be null - assert DNSName != null; - - int failure = SNISecGenClientContext( sniSec, sniSecLen, pin, pin.length, pOut, outsize, done, DNSName, port, null, null, authLogger); - - if(failure != 0) - { - authLogger.warning(toString() + " Authentication failed code : " + failure); - con.terminate(SQLServerException.DRIVER_ERROR_NONE, SQLServerException.getErrString("R_integratedAuthenticationFailed"), linkError); - } - // allocate space based on the size returned - byte output[] = new byte[outsize[0]]; - System.arraycopy( pOut, 0, output, 0, outsize[0] ); - return output; - } - - - /*L0*/ int ReleaseClientContext() - { - int success = 0; - if(sniSecLen[0] > 0) - { - success = SNISecReleaseClientContext(sniSec, sniSecLen[0], authLogger); - sniSecLen[0] = 0; - } - return success; - } - - // note we handle the failures of the GetDNSName in this function, this function will return an empty string if the underlying call fails. - private static String GetDNSName(String address) - { - String DNS[] = new String[1]; - if(GetDNSName(address, DNS, authLogger) !=0) - { - //Simply initialize the DNS to address - DNS[0] = address; - } - return DNS[0]; - } - - // we use arrays of size one in many places to retrieve output values - // Java Integer objects are immutable so we cant use them to get the output sizes. - // Same for String - /*L0*/private native static int SNISecGenClientContext( byte[] psec, int[] secptrsize, - byte[] pin, int insize, byte[] pOut, int[] outsize, - boolean[] done, String servername, int port, - String username, String password, java.util.logging.Logger log); - - /*L0*/ private native static int SNISecReleaseClientContext( byte[] psec, int secptrsize, java.util.logging.Logger log); - private native static int SNISecInitPackage(int[] pcbMaxToken, java.util.logging.Logger log); - private native static int SNISecTerminatePackage(java.util.logging.Logger log); - private native static int SNIGetSID(byte[] SID, java.util.logging.Logger log); - private native static boolean SNIIsEqualToCurrentSID(byte[] SID, java.util.logging.Logger log); - private native static int GetDNSName(String address, String[] DNSName, java.util.logging.Logger log); - private native static FedAuthDllInfo ADALGetAccessTokenForWindowsIntegrated(String stsURL, String servicePrincipalName, String clientConnectionId, String clientId, long expirationFileTime, java.util.logging.Logger log); - private native static FedAuthDllInfo ADALGetAccessToken(String userName, String password, String stsURL, String servicePrincipalName, String clientConnectionId, String clientId, long expirationFileTime, java.util.logging.Logger log); - native static byte[] DecryptColumnEncryptionKey(String masterKeyPath, String encryptionAlgorithm, byte[] encryptedColumnEncryptionKey) throws DLLException; +final class AuthenticationJNI extends SSPIAuthentication { + private final static int maximumpointersize = 128; // we keep the SNI_Sec pointer + private static boolean enabled = false; + private static java.util.logging.Logger authLogger = java.util.logging.Logger + .getLogger("com.microsoft.sqlserver.jdbc.internals.AuthenticationJNI"); + private static int sspiBlobMaxlen = 0; + private byte[] sniSec = new byte[maximumpointersize]; + private int sniSecLen[] = {0}; + private final String DNSName; + private final int port; + private SQLServerConnection con; + + private static final UnsatisfiedLinkError linkError; + + static int GetMaxSSPIBlobSize() { + return sspiBlobMaxlen; + } + + static { + UnsatisfiedLinkError temp = null; + // Load the DLL + try { + String libName = "sqljdbc_auth"; + System.loadLibrary(libName); + int[] pkg = new int[1]; + pkg[0] = 0; + if (0 == SNISecInitPackage(pkg, authLogger)) { + sspiBlobMaxlen = pkg[0]; + } + else + throw new UnsatisfiedLinkError(); + enabled = true; + } + catch (UnsatisfiedLinkError e) { + temp = e; + authLogger.warning("Failed to load the sqljdbc_auth.dll cause : " + e.getMessage()); + // This is not re-thrown on purpose - the constructor will terminate the properly with the appropriate error string + } + finally { + linkError = temp; + } + + } + + AuthenticationJNI(SQLServerConnection con, + String address, + int serverport) throws SQLServerException { + if (!enabled) + con.terminate(SQLServerException.DRIVER_ERROR_NONE, SQLServerException.getErrString("R_notConfiguredForIntegrated"), linkError); + + this.con = con; + DNSName = GetDNSName(address); + port = serverport; + } + + static FedAuthDllInfo getAccessTokenForWindowsIntegrated(String stsURL, + String servicePrincipalName, + String clientConnectionId, + String clientId, + long expirationFileTime) throws DLLException { + FedAuthDllInfo dllInfo = ADALGetAccessTokenForWindowsIntegrated(stsURL, servicePrincipalName, clientConnectionId, clientId, + expirationFileTime, authLogger); + return dllInfo; + } + + static FedAuthDllInfo getAccessToken(String userName, + String password, + String stsURL, + String servicePrincipalName, + String clientConnectionId, + String clientId, + long expirationFileTime) throws DLLException { + FedAuthDllInfo dllInfo = ADALGetAccessToken(userName, password, stsURL, servicePrincipalName, clientConnectionId, clientId, + expirationFileTime, authLogger); + return dllInfo; + } + + // InitDNSName should be called to initialize the DNSName before calling this function + byte[] GenerateClientContext(byte[] pin, + boolean[] done) throws SQLServerException { + byte[] pOut; + int[] outsize; // This is where the size of the filled data returned + outsize = new int[1]; + outsize[0] = GetMaxSSPIBlobSize(); + pOut = new byte[outsize[0]]; + + // assert DNSName cant be null + assert DNSName != null; + + int failure = SNISecGenClientContext(sniSec, sniSecLen, pin, pin.length, pOut, outsize, done, DNSName, port, null, null, authLogger); + + if (failure != 0) { + authLogger.warning(toString() + " Authentication failed code : " + failure); + con.terminate(SQLServerException.DRIVER_ERROR_NONE, SQLServerException.getErrString("R_integratedAuthenticationFailed"), linkError); + } + // allocate space based on the size returned + byte output[] = new byte[outsize[0]]; + System.arraycopy(pOut, 0, output, 0, outsize[0]); + return output; + } + + /* L0 */ int ReleaseClientContext() { + int success = 0; + if (sniSecLen[0] > 0) { + success = SNISecReleaseClientContext(sniSec, sniSecLen[0], authLogger); + sniSecLen[0] = 0; + } + return success; + } + + // note we handle the failures of the GetDNSName in this function, this function will return an empty string if the underlying call fails. + private static String GetDNSName(String address) { + String DNS[] = new String[1]; + if (GetDNSName(address, DNS, authLogger) != 0) { + // Simply initialize the DNS to address + DNS[0] = address; + } + return DNS[0]; + } + + // we use arrays of size one in many places to retrieve output values + // Java Integer objects are immutable so we cant use them to get the output sizes. + // Same for String + /* L0 */private native static int SNISecGenClientContext(byte[] psec, + int[] secptrsize, + byte[] pin, + int insize, + byte[] pOut, + int[] outsize, + boolean[] done, + String servername, + int port, + String username, + String password, + java.util.logging.Logger log); + + /* L0 */ private native static int SNISecReleaseClientContext(byte[] psec, + int secptrsize, + java.util.logging.Logger log); + + private native static int SNISecInitPackage(int[] pcbMaxToken, + java.util.logging.Logger log); + + private native static int SNISecTerminatePackage(java.util.logging.Logger log); + + private native static int SNIGetSID(byte[] SID, + java.util.logging.Logger log); + + private native static boolean SNIIsEqualToCurrentSID(byte[] SID, + java.util.logging.Logger log); + + private native static int GetDNSName(String address, + String[] DNSName, + java.util.logging.Logger log); + + private native static FedAuthDllInfo ADALGetAccessTokenForWindowsIntegrated(String stsURL, + String servicePrincipalName, + String clientConnectionId, + String clientId, + long expirationFileTime, + java.util.logging.Logger log); + + private native static FedAuthDllInfo ADALGetAccessToken(String userName, + String password, + String stsURL, + String servicePrincipalName, + String clientConnectionId, + String clientId, + long expirationFileTime, + java.util.logging.Logger log); + + native static byte[] DecryptColumnEncryptionKey(String masterKeyPath, + String encryptionAlgorithm, + byte[] encryptedColumnEncryptionKey) throws DLLException; } - diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/Column.java b/src/main/java/com/microsoft/sqlserver/jdbc/Column.java index 75c1b6c72..06eaf1fb3 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/Column.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/Column.java @@ -1,508 +1,472 @@ -//--------------------------------------------------------------------------------------------------------------------------------- -// File: Column.java -// -// -// Microsoft JDBC Driver for SQL Server -// Copyright(c) Microsoft Corporation -// All rights reserved. -// MIT License -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), -// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : -// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//--------------------------------------------------------------------------------------------------------------------------------- - +/* + * 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; import java.text.MessageFormat; import java.util.Calendar; - /** * Column represents a database column definition (meta data) within a result set. */ final class Column { - private TypeInfo typeInfo; - private CryptoMetadata cryptoMetadata; - final TypeInfo getTypeInfo() { return typeInfo; } - private DTV updaterDTV; - private final DTV getterDTV=new DTV(); - - //updated if sendStringParametersAsUnicode=true for setNString, setNCharacterStream, and setNClob methods - private JDBCType jdbcTypeSetByUser = null; - - //set length of value for variable length type (String) - private int valueLength = 0; - - // The column name, which may be an alias, that is used with value setters and getters. - private String columnName; - final void setColumnName(String name) { columnName = name; } - final String getColumnName() { return columnName; } - - // The base column name which is the actual column name in an underlying table. - // This name must be used, rather than the column name above, when inserting or - // updating rows in the table. - private String baseColumnName; - final void setBaseColumnName(String name) { baseColumnName = name; } - final String getBaseColumnName() { return baseColumnName; } - - private int tableNum; - final void setTableNum(int num) { tableNum = num; } - final int getTableNum() { return tableNum; } - - private int infoStatus; - final void setInfoStatus(int status) { infoStatus = status; } - final boolean hasDifferentName() { return 0 != (infoStatus & TDS.COLINFO_STATUS_DIFFERENT_NAME); } - final boolean isHidden() { return 0 != (infoStatus & TDS.COLINFO_STATUS_HIDDEN); } - final boolean isKey() { return 0 != (infoStatus & TDS.COLINFO_STATUS_KEY); } - final boolean isExpression() { return 0 != (infoStatus & TDS.COLINFO_STATUS_EXPRESSION); } - final boolean isUpdatable() - { - return - !isExpression() && - !isHidden() && - tableName.getObjectName().length() > 0; - } - - private SQLIdentifier tableName; - final void setTableName(SQLIdentifier name) { tableName = name; } - final SQLIdentifier getTableName() { return tableName; } - - ColumnFilter filter; - - /** - * Create a new column - * @param typeInfo the column TYPE_INFO - * @param columnName the column name - * @param tableName the column's table name - * @param cryptoMeta the column's crypto metadata - */ - Column(TypeInfo typeInfo, String columnName, SQLIdentifier tableName, CryptoMetadata cryptoMeta) - { - this.typeInfo = typeInfo; - this.columnName = columnName; - this.baseColumnName = columnName; - this.tableName = tableName; - this.cryptoMetadata = cryptoMeta; - } - - CryptoMetadata getCryptoMetadata(){ - return cryptoMetadata; - } - - /** - * Clears the values associated with this column. - */ - final void clear() - { - getterDTV.clear(); - } - - /** - * Skip this column. - * - * The column's value may or may not already be marked. If this - * column's value has not yet been marked, this function assumes - * that the value is located at the current position in the response. - */ - final void skipValue(TDSReader tdsReader, boolean isDiscard) throws SQLServerException - { - getterDTV.skipValue(typeInfo, tdsReader, isDiscard); - } - - /** - * Sets Null value on the getterDTV of a column - */ - final void initFromCompressedNull() - { - getterDTV.initFromCompressedNull(); - } - - void setFilter(ColumnFilter filter) - { - this.filter = filter; - } - - /** - * Returns whether the value of this column is SQL NULL. - * - * If the column has not yet been read from the response then - * this method returns false. - */ - final boolean isNull() - { - return getterDTV.isNull(); - } - - /** - * Returns true if the column value is initialized to - * some value by reading the stream from server - * i.e. it returns true, if impl of getterDTV is not set to null - */ - final boolean isInitialized() - { - return getterDTV.isInitialized(); - } - - /** - * Retrieves this colum's value. - * - * If the column has not yet been read from the response then - * this method reads it. - */ - Object getValue(JDBCType jdbcType, InputStreamGetterArgs getterArgs, Calendar cal, TDSReader tdsReader) throws SQLServerException - { - Object value = getterDTV.getValue(jdbcType, typeInfo.getScale(), getterArgs, cal, typeInfo, cryptoMetadata, tdsReader); - return (null != filter) ? filter.apply(value, jdbcType) : value; - } - - int getInt(TDSReader tdsReader) throws SQLServerException - { - return ((Integer) getValue(JDBCType.INTEGER, null, null, tdsReader)).intValue(); - } - - void updateValue( - JDBCType jdbcType, - Object value, - JavaType javaType, - StreamSetterArgs streamSetterArgs, - Calendar cal, - Integer scale, - SQLServerConnection con, - SQLServerStatementColumnEncryptionSetting stmtColumnEncriptionSetting, - Integer precision, - boolean forceEncrypt, - int parameterIndex) throws SQLServerException - { - SSType ssType = typeInfo.getSSType(); - - if (null != cryptoMetadata ) - { - if(SSType.VARBINARYMAX == cryptoMetadata.baseTypeInfo.getSSType() && JDBCType.BINARY == jdbcType){ - jdbcType = cryptoMetadata.baseTypeInfo.getSSType().getJDBCType(); - } - - if(null != value){ - //for encrypted tinyint, we need to convert short value to byte value, otherwise it would be sent as smallint - if(JDBCType.TINYINT == cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType() && javaType == JavaType.SHORT){ - if(value instanceof Boolean){ - if(true == ((boolean)value)){ - value = 1; - } - else{ - value = 0; - } - } - String stringValue = "" + value; - Short shortValue = Short.valueOf(stringValue); - - if(shortValue >= 0 && shortValue <= 255){ - value = shortValue.byteValue(); - javaType = JavaType.BYTE; - jdbcType = JDBCType.TINYINT; - } - } - } - //if the column is encrypted and value is null, get the real column type instead of binary types - else if (jdbcType.isBinary()){ - jdbcType = cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType(); - } - } - - if(null == scale && null != cryptoMetadata){ - scale = cryptoMetadata.getBaseTypeInfo().getScale(); - } - - //if jdbcType is char or varchar, check if the column is actually char/varchar or nchar/nvarchar - //in order to make updateString() work with encrypted Nchar typpes - if(null != cryptoMetadata && (JDBCType.CHAR == jdbcType || JDBCType.VARCHAR == jdbcType)){ - if(JDBCType.NVARCHAR == cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType() - || JDBCType.NCHAR == cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType() - || JDBCType.LONGNVARCHAR == cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType()){ - jdbcType = cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType(); - } - } - - if(Util.shouldHonorAEForParameters(stmtColumnEncriptionSetting, con)) - { - if((null == cryptoMetadata) && true == forceEncrypt){ - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_ForceEncryptionTrue_HonorAETrue_UnencryptedColumnRS")); - Object[] msgArgs = {parameterIndex}; - - throw new SQLServerException( - null, - form.format(msgArgs), - null, - 0, - false); - } - else{ - setJdbcTypeSetByUser(jdbcType); - - this.valueLength = Util.getValueLengthBaseOnJavaType(value, javaType, precision, scale, jdbcType); - - //for update encrypted nchar or nvarchar value on result set, must double the value length, - //otherwise, the data is truncated. - if(null != cryptoMetadata){ - if(JDBCType.NCHAR == cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType() - || JDBCType.NVARCHAR == cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType() - || JDBCType.LONGNVARCHAR == cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType()){ - this.valueLength = valueLength * 2; - } - } - } - } - else{ - if(true == forceEncrypt){ - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_ForceEncryptionTrue_HonorAEFalseRS")); - Object[] msgArgs = {parameterIndex}; - - throw new SQLServerException( - null, - form.format(msgArgs), - null, - 0, - false); - } - } - - if (null != streamSetterArgs) - { - if (!streamSetterArgs.streamType.convertsTo(typeInfo)) - DataTypes.throwConversionError(streamSetterArgs.streamType.toString(), ssType.toString()); - } - else - { - if(null != cryptoMetadata) - { - // For GUID, set the JDBCType before checking for conversion - if ((JDBCType.UNKNOWN == jdbcType) - && (value instanceof java.util.UUID)) - { - javaType = JavaType.STRING; - jdbcType = JDBCType.GUID; - setJdbcTypeSetByUser(jdbcType); - } - - SSType basicSSType = cryptoMetadata.baseTypeInfo.getSSType(); - if (!jdbcType.convertsTo(basicSSType)) - DataTypes.throwConversionError(jdbcType.toString(), ssType.toString()); - - JDBCType jdbcTypeFromSSType = getJDBCTypeFromBaseSSType(basicSSType, jdbcType); - - if( jdbcTypeFromSSType != jdbcType) - { - setJdbcTypeSetByUser(jdbcTypeFromSSType); - jdbcType = jdbcTypeFromSSType; - this.valueLength = Util.getValueLengthBaseOnJavaType(value, javaType, precision, scale, jdbcType); - } - } - else - { - if (!jdbcType.convertsTo(ssType)) - DataTypes.throwConversionError(jdbcType.toString(), ssType.toString()); - } - } - - // DateTimeOffset is not supported with SQL Server versions earlier than Katmai - if ((JDBCType.DATETIMEOFFSET == jdbcType || JavaType.DATETIMEOFFSET == javaType) && - !con.isKatmaiOrLater()) - { - throw new SQLServerException( - SQLServerException.getErrString("R_notSupported"), - SQLState.DATA_EXCEPTION_NOT_SPECIFIC, - DriverError.NOT_SET, - null); - } - - // sendStringParametersAsUnicode - // If set to true, this connection property tells the driver to send textual parameters - // to the server as Unicode rather than MBCS. This is accomplished here by re-tagging - // the value with the appropriate corresponding Unicode type. - if ((null != cryptoMetadata) && (con.sendStringParametersAsUnicode()) && - (JavaType.STRING == javaType || - JavaType.READER == javaType || - JavaType.CLOB == javaType)) - { - jdbcType = getSSPAUJDBCType(jdbcType); - } - - // Cheesy checks determine whether updating is allowed, but do not determine HOW to do - // the update (i.e. what JDBC type to use for the update). The JDBC type to use depends - // on the SQL Server type of the column and the JDBC type requested. - // - // In most cases the JDBCType to use is just the requested JDBCType. But in some cases - // a client side type conversion is necessary because SQL Server does not directly support - // conversion from the requested JDBCType to the column SSType, or the driver needs to - // provide special data conversion. - - // Update of Unicode SSType from textual JDBCType: Use Unicode. - if ( - (SSType.NCHAR == ssType || - SSType.NVARCHAR == ssType || - SSType.NVARCHARMAX == ssType || - SSType.NTEXT == ssType || - SSType.XML == ssType) && - - (JDBCType.CHAR == jdbcType || - JDBCType.VARCHAR == jdbcType || - JDBCType.LONGVARCHAR == jdbcType || - JDBCType.CLOB == jdbcType) - ) - { - jdbcType = (JDBCType.CLOB == jdbcType) ? JDBCType.NCLOB : JDBCType.NVARCHAR; - } - - // Update of binary SSType from textual JDBCType: Convert hex to binary. - else if ( - (SSType.BINARY == ssType || - SSType.VARBINARY == ssType || - SSType.VARBINARYMAX == ssType || - SSType.IMAGE == ssType || - SSType.UDT == ssType) && - - (JDBCType.CHAR == jdbcType || - JDBCType.VARCHAR == jdbcType || - JDBCType.LONGVARCHAR == jdbcType) - ) - { - jdbcType = JDBCType.VARBINARY; - } - - // Update of textual SSType from temporal JDBCType requires - // client-side conversion from temporal to textual. - else if ( - (JDBCType.TIMESTAMP == jdbcType || - JDBCType.DATE == jdbcType || - JDBCType.TIME == jdbcType || - JDBCType.DATETIMEOFFSET == jdbcType) && - - (SSType.CHAR == ssType || - SSType.VARCHAR == ssType || - SSType.VARCHARMAX == ssType || - SSType.TEXT == ssType || - SSType.NCHAR == ssType || - SSType.NVARCHAR == ssType || - SSType.NVARCHARMAX == ssType || - SSType.NTEXT == ssType) - ) - { - jdbcType = JDBCType.NCHAR; - } - - // Lazily create the updater DTV on first update of the column - if (null == updaterDTV) - updaterDTV = new DTV(); - - // Set the column's value - - updaterDTV.setValue(typeInfo.getSQLCollation(), jdbcType, value, javaType, streamSetterArgs, cal, scale, con, false); - } - - /** - * Used when sendStringParametersAsUnicode=true to derive the appropriate National Character Set - * JDBC type corresponding to the specified JDBC type. - */ - private static JDBCType getSSPAUJDBCType(JDBCType jdbcType) - { - switch (jdbcType) - { - case CHAR: return JDBCType.NCHAR; - case VARCHAR: return JDBCType.NVARCHAR; - case LONGVARCHAR: return JDBCType.LONGNVARCHAR; - case CLOB: return JDBCType.NCLOB; - default: return jdbcType; - } - } - - private static JDBCType getJDBCTypeFromBaseSSType(SSType basicSSType,JDBCType jdbcType) - { - switch (jdbcType) - { - case TIMESTAMP: - if(SSType.DATETIME == basicSSType) - return JDBCType.DATETIME; - else if (SSType.SMALLDATETIME == basicSSType) - return JDBCType.SMALLDATETIME; - return jdbcType; - - case NUMERIC: - case DECIMAL: - if(SSType.MONEY == basicSSType) - return JDBCType.MONEY; - if (SSType.SMALLMONEY == basicSSType) - return JDBCType.SMALLMONEY; - return jdbcType; - - case CHAR: - if(SSType.GUID == basicSSType) - return JDBCType.GUID; - if(SSType.VARCHARMAX == basicSSType) - return JDBCType.LONGVARCHAR; - - default: - return jdbcType; - } - } - - boolean hasUpdates() - { - return null != updaterDTV; - } - - void cancelUpdates() - { - updaterDTV = null; - } - - void sendByRPC( - TDSWriter tdsWriter, - SQLServerConnection conn) throws SQLServerException - { - // If the column has had no updates then there is nothing to send - if (null == updaterDTV) - return; - try{ - //this is for updateRow() stuff - updaterDTV.sendCryptoMetaData(cryptoMetadata, tdsWriter); - updaterDTV.jdbcTypeSetByUser(getJdbcTypeSetByUser(), getValueLength()); - - // Otherwise, send the updated value via RPC - updaterDTV.sendByRPC( - baseColumnName, - typeInfo, - null != cryptoMetadata ? cryptoMetadata.getBaseTypeInfo().getSQLCollation():typeInfo.getSQLCollation(), - null != cryptoMetadata ? cryptoMetadata.getBaseTypeInfo().getPrecision():typeInfo.getPrecision(), - null != cryptoMetadata ? cryptoMetadata.getBaseTypeInfo().getScale():typeInfo.getScale(), - false, // isOutParameter (always false for column updates) - tdsWriter, - conn); - } - finally{ - //this is for updateRow() stuff - updaterDTV.sendCryptoMetaData(null, tdsWriter); - } - } - - JDBCType getJdbcTypeSetByUser() { - return jdbcTypeSetByUser; - } - void setJdbcTypeSetByUser(JDBCType jdbcTypeSetByUser) { - this.jdbcTypeSetByUser = jdbcTypeSetByUser; - } - - int getValueLength() { - return valueLength; - } + private TypeInfo typeInfo; + private CryptoMetadata cryptoMetadata; + + final TypeInfo getTypeInfo() { + return typeInfo; + } + + private DTV updaterDTV; + private final DTV getterDTV = new DTV(); + + // updated if sendStringParametersAsUnicode=true for setNString, setNCharacterStream, and setNClob methods + private JDBCType jdbcTypeSetByUser = null; + + // set length of value for variable length type (String) + private int valueLength = 0; + + // The column name, which may be an alias, that is used with value setters and getters. + private String columnName; + + final void setColumnName(String name) { + columnName = name; + } + + final String getColumnName() { + return columnName; + } + + // The base column name which is the actual column name in an underlying table. + // This name must be used, rather than the column name above, when inserting or + // updating rows in the table. + private String baseColumnName; + + final void setBaseColumnName(String name) { + baseColumnName = name; + } + + final String getBaseColumnName() { + return baseColumnName; + } + + private int tableNum; + + final void setTableNum(int num) { + tableNum = num; + } + + final int getTableNum() { + return tableNum; + } + + private int infoStatus; + + final void setInfoStatus(int status) { + infoStatus = status; + } + + final boolean hasDifferentName() { + return 0 != (infoStatus & TDS.COLINFO_STATUS_DIFFERENT_NAME); + } + + final boolean isHidden() { + return 0 != (infoStatus & TDS.COLINFO_STATUS_HIDDEN); + } + + final boolean isKey() { + return 0 != (infoStatus & TDS.COLINFO_STATUS_KEY); + } + + final boolean isExpression() { + return 0 != (infoStatus & TDS.COLINFO_STATUS_EXPRESSION); + } + + final boolean isUpdatable() { + return !isExpression() && !isHidden() && tableName.getObjectName().length() > 0; + } + + private SQLIdentifier tableName; + + final void setTableName(SQLIdentifier name) { + tableName = name; + } + + final SQLIdentifier getTableName() { + return tableName; + } + + ColumnFilter filter; + + /** + * Create a new column + * + * @param typeInfo + * the column TYPE_INFO + * @param columnName + * the column name + * @param tableName + * the column's table name + * @param cryptoMeta + * the column's crypto metadata + */ + Column(TypeInfo typeInfo, + String columnName, + SQLIdentifier tableName, + CryptoMetadata cryptoMeta) { + this.typeInfo = typeInfo; + this.columnName = columnName; + this.baseColumnName = columnName; + this.tableName = tableName; + this.cryptoMetadata = cryptoMeta; + } + + CryptoMetadata getCryptoMetadata() { + return cryptoMetadata; + } + + /** + * Clears the values associated with this column. + */ + final void clear() { + getterDTV.clear(); + } + + /** + * Skip this column. + * + * The column's value may or may not already be marked. If this column's value has not yet been marked, this function assumes that the value is + * located at the current position in the response. + */ + final void skipValue(TDSReader tdsReader, + boolean isDiscard) throws SQLServerException { + getterDTV.skipValue(typeInfo, tdsReader, isDiscard); + } + + /** + * Sets Null value on the getterDTV of a column + */ + final void initFromCompressedNull() { + getterDTV.initFromCompressedNull(); + } + + void setFilter(ColumnFilter filter) { + this.filter = filter; + } + + /** + * Returns whether the value of this column is SQL NULL. + * + * If the column has not yet been read from the response then this method returns false. + */ + final boolean isNull() { + return getterDTV.isNull(); + } + + /** + * Returns true if the column value is initialized to some value by reading the stream from server i.e. it returns true, if impl of getterDTV is + * not set to null + */ + final boolean isInitialized() { + return getterDTV.isInitialized(); + } + + /** + * Retrieves this colum's value. + * + * If the column has not yet been read from the response then this method reads it. + */ + Object getValue(JDBCType jdbcType, + InputStreamGetterArgs getterArgs, + Calendar cal, + TDSReader tdsReader) throws SQLServerException { + Object value = getterDTV.getValue(jdbcType, typeInfo.getScale(), getterArgs, cal, typeInfo, cryptoMetadata, tdsReader); + return (null != filter) ? filter.apply(value, jdbcType) : value; + } + + int getInt(TDSReader tdsReader) throws SQLServerException { + return ((Integer) getValue(JDBCType.INTEGER, null, null, tdsReader)).intValue(); + } + + void updateValue(JDBCType jdbcType, + Object value, + JavaType javaType, + StreamSetterArgs streamSetterArgs, + Calendar cal, + Integer scale, + SQLServerConnection con, + SQLServerStatementColumnEncryptionSetting stmtColumnEncriptionSetting, + Integer precision, + boolean forceEncrypt, + int parameterIndex) throws SQLServerException { + SSType ssType = typeInfo.getSSType(); + + if (null != cryptoMetadata) { + if (SSType.VARBINARYMAX == cryptoMetadata.baseTypeInfo.getSSType() && JDBCType.BINARY == jdbcType) { + jdbcType = cryptoMetadata.baseTypeInfo.getSSType().getJDBCType(); + } + + if (null != value) { + // for encrypted tinyint, we need to convert short value to byte value, otherwise it would be sent as smallint + if (JDBCType.TINYINT == cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType() && javaType == JavaType.SHORT) { + if (value instanceof Boolean) { + if (true == ((boolean) value)) { + value = 1; + } + else { + value = 0; + } + } + String stringValue = "" + value; + Short shortValue = Short.valueOf(stringValue); + + if (shortValue >= 0 && shortValue <= 255) { + value = shortValue.byteValue(); + javaType = JavaType.BYTE; + jdbcType = JDBCType.TINYINT; + } + } + } + // if the column is encrypted and value is null, get the real column type instead of binary types + else if (jdbcType.isBinary()) { + jdbcType = cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType(); + } + } + + if (null == scale && null != cryptoMetadata) { + scale = cryptoMetadata.getBaseTypeInfo().getScale(); + } + + // if jdbcType is char or varchar, check if the column is actually char/varchar or nchar/nvarchar + // in order to make updateString() work with encrypted Nchar typpes + if (null != cryptoMetadata && (JDBCType.CHAR == jdbcType || JDBCType.VARCHAR == jdbcType)) { + if (JDBCType.NVARCHAR == cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType() + || JDBCType.NCHAR == cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType() + || JDBCType.LONGNVARCHAR == cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType()) { + jdbcType = cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType(); + } + } + + if (Util.shouldHonorAEForParameters(stmtColumnEncriptionSetting, con)) { + if ((null == cryptoMetadata) && true == forceEncrypt) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_ForceEncryptionTrue_HonorAETrue_UnencryptedColumnRS")); + Object[] msgArgs = {parameterIndex}; + + throw new SQLServerException(null, form.format(msgArgs), null, 0, false); + } + else { + setJdbcTypeSetByUser(jdbcType); + + this.valueLength = Util.getValueLengthBaseOnJavaType(value, javaType, precision, scale, jdbcType); + + // for update encrypted nchar or nvarchar value on result set, must double the value length, + // otherwise, the data is truncated. + if (null != cryptoMetadata) { + if (JDBCType.NCHAR == cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType() + || JDBCType.NVARCHAR == cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType() + || JDBCType.LONGNVARCHAR == cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType()) { + this.valueLength = valueLength * 2; + } + } + } + } + else { + if (true == forceEncrypt) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_ForceEncryptionTrue_HonorAEFalseRS")); + Object[] msgArgs = {parameterIndex}; + + throw new SQLServerException(null, form.format(msgArgs), null, 0, false); + } + } + + if (null != streamSetterArgs) { + if (!streamSetterArgs.streamType.convertsTo(typeInfo)) + DataTypes.throwConversionError(streamSetterArgs.streamType.toString(), ssType.toString()); + } + else { + if (null != cryptoMetadata) { + // For GUID, set the JDBCType before checking for conversion + if ((JDBCType.UNKNOWN == jdbcType) && (value instanceof java.util.UUID)) { + javaType = JavaType.STRING; + jdbcType = JDBCType.GUID; + setJdbcTypeSetByUser(jdbcType); + } + + SSType basicSSType = cryptoMetadata.baseTypeInfo.getSSType(); + if (!jdbcType.convertsTo(basicSSType)) + DataTypes.throwConversionError(jdbcType.toString(), ssType.toString()); + + JDBCType jdbcTypeFromSSType = getJDBCTypeFromBaseSSType(basicSSType, jdbcType); + + if (jdbcTypeFromSSType != jdbcType) { + setJdbcTypeSetByUser(jdbcTypeFromSSType); + jdbcType = jdbcTypeFromSSType; + this.valueLength = Util.getValueLengthBaseOnJavaType(value, javaType, precision, scale, jdbcType); + } + } + else { + if (!jdbcType.convertsTo(ssType)) + DataTypes.throwConversionError(jdbcType.toString(), ssType.toString()); + } + } + + // DateTimeOffset is not supported with SQL Server versions earlier than Katmai + if ((JDBCType.DATETIMEOFFSET == jdbcType || JavaType.DATETIMEOFFSET == javaType) && !con.isKatmaiOrLater()) { + throw new SQLServerException(SQLServerException.getErrString("R_notSupported"), SQLState.DATA_EXCEPTION_NOT_SPECIFIC, DriverError.NOT_SET, + null); + } + + // sendStringParametersAsUnicode + // If set to true, this connection property tells the driver to send textual parameters + // to the server as Unicode rather than MBCS. This is accomplished here by re-tagging + // the value with the appropriate corresponding Unicode type. + if ((null != cryptoMetadata) && (con.sendStringParametersAsUnicode()) + && (JavaType.STRING == javaType || JavaType.READER == javaType || JavaType.CLOB == javaType)) { + jdbcType = getSSPAUJDBCType(jdbcType); + } + + // Cheesy checks determine whether updating is allowed, but do not determine HOW to do + // the update (i.e. what JDBC type to use for the update). The JDBC type to use depends + // on the SQL Server type of the column and the JDBC type requested. + // + // In most cases the JDBCType to use is just the requested JDBCType. But in some cases + // a client side type conversion is necessary because SQL Server does not directly support + // conversion from the requested JDBCType to the column SSType, or the driver needs to + // provide special data conversion. + + // Update of Unicode SSType from textual JDBCType: Use Unicode. + if ((SSType.NCHAR == ssType || SSType.NVARCHAR == ssType || SSType.NVARCHARMAX == ssType || SSType.NTEXT == ssType || SSType.XML == ssType) && + + (JDBCType.CHAR == jdbcType || JDBCType.VARCHAR == jdbcType || JDBCType.LONGVARCHAR == jdbcType || JDBCType.CLOB == jdbcType)) { + jdbcType = (JDBCType.CLOB == jdbcType) ? JDBCType.NCLOB : JDBCType.NVARCHAR; + } + + // Update of binary SSType from textual JDBCType: Convert hex to binary. + else if ((SSType.BINARY == ssType || SSType.VARBINARY == ssType || SSType.VARBINARYMAX == ssType || SSType.IMAGE == ssType + || SSType.UDT == ssType) && + + (JDBCType.CHAR == jdbcType || JDBCType.VARCHAR == jdbcType || JDBCType.LONGVARCHAR == jdbcType)) { + jdbcType = JDBCType.VARBINARY; + } + + // Update of textual SSType from temporal JDBCType requires + // client-side conversion from temporal to textual. + else if ((JDBCType.TIMESTAMP == jdbcType || JDBCType.DATE == jdbcType || JDBCType.TIME == jdbcType || JDBCType.DATETIMEOFFSET == jdbcType) && + + (SSType.CHAR == ssType || SSType.VARCHAR == ssType || SSType.VARCHARMAX == ssType || SSType.TEXT == ssType || SSType.NCHAR == ssType + || SSType.NVARCHAR == ssType || SSType.NVARCHARMAX == ssType || SSType.NTEXT == ssType)) { + jdbcType = JDBCType.NCHAR; + } + + // Lazily create the updater DTV on first update of the column + if (null == updaterDTV) + updaterDTV = new DTV(); + + // Set the column's value + + updaterDTV.setValue(typeInfo.getSQLCollation(), jdbcType, value, javaType, streamSetterArgs, cal, scale, con, false); + } + + /** + * Used when sendStringParametersAsUnicode=true to derive the appropriate National Character Set JDBC type corresponding to the specified JDBC + * type. + */ + private static JDBCType getSSPAUJDBCType(JDBCType jdbcType) { + switch (jdbcType) { + case CHAR: + return JDBCType.NCHAR; + case VARCHAR: + return JDBCType.NVARCHAR; + case LONGVARCHAR: + return JDBCType.LONGNVARCHAR; + case CLOB: + return JDBCType.NCLOB; + default: + return jdbcType; + } + } + + private static JDBCType getJDBCTypeFromBaseSSType(SSType basicSSType, + JDBCType jdbcType) { + switch (jdbcType) { + case TIMESTAMP: + if (SSType.DATETIME == basicSSType) + return JDBCType.DATETIME; + else if (SSType.SMALLDATETIME == basicSSType) + return JDBCType.SMALLDATETIME; + return jdbcType; + + case NUMERIC: + case DECIMAL: + if (SSType.MONEY == basicSSType) + return JDBCType.MONEY; + if (SSType.SMALLMONEY == basicSSType) + return JDBCType.SMALLMONEY; + return jdbcType; + + case CHAR: + if (SSType.GUID == basicSSType) + return JDBCType.GUID; + if (SSType.VARCHARMAX == basicSSType) + return JDBCType.LONGVARCHAR; + + default: + return jdbcType; + } + } + + boolean hasUpdates() { + return null != updaterDTV; + } + + void cancelUpdates() { + updaterDTV = null; + } + + void sendByRPC(TDSWriter tdsWriter, + SQLServerConnection conn) throws SQLServerException { + // If the column has had no updates then there is nothing to send + if (null == updaterDTV) + return; + try { + // this is for updateRow() stuff + updaterDTV.sendCryptoMetaData(cryptoMetadata, tdsWriter); + updaterDTV.jdbcTypeSetByUser(getJdbcTypeSetByUser(), getValueLength()); + + // Otherwise, send the updated value via RPC + updaterDTV.sendByRPC(baseColumnName, typeInfo, + null != cryptoMetadata ? cryptoMetadata.getBaseTypeInfo().getSQLCollation() : typeInfo.getSQLCollation(), + null != cryptoMetadata ? cryptoMetadata.getBaseTypeInfo().getPrecision() : typeInfo.getPrecision(), + null != cryptoMetadata ? cryptoMetadata.getBaseTypeInfo().getScale() : typeInfo.getScale(), false, // isOutParameter (always false + // for column updates) + tdsWriter, conn); + } + finally { + // this is for updateRow() stuff + updaterDTV.sendCryptoMetaData(null, tdsWriter); + } + } + + JDBCType getJdbcTypeSetByUser() { + return jdbcTypeSetByUser; + } + + void setJdbcTypeSetByUser(JDBCType jdbcTypeSetByUser) { + this.jdbcTypeSetByUser = jdbcTypeSetByUser; + } + + int getValueLength() { + return valueLength; + } } -abstract class ColumnFilter -{ - abstract Object apply(Object value, JDBCType jdbcType) throws SQLServerException; +abstract class ColumnFilter { + abstract Object apply(Object value, + JDBCType jdbcType) throws SQLServerException; } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/DDC.java b/src/main/java/com/microsoft/sqlserver/jdbc/DDC.java index 6e7b167c0..8010c1b32 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/DDC.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/DDC.java @@ -1,23 +1,13 @@ -//--------------------------------------------------------------------------------------------------------------------------------- -// File: DDC.java -// -// -// Microsoft JDBC Driver for SQL Server -// Copyright(c) Microsoft Corporation -// All rights reserved. -// MIT License -// Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), -// to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : -// The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -// IN THE SOFTWARE. -//--------------------------------------------------------------------------------------------------------------------------------- - - +/* + * 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; + import static java.nio.charset.StandardCharsets.US_ASCII; import java.io.BufferedReader; @@ -30,7 +20,6 @@ import java.io.UnsupportedEncodingException; import java.math.BigDecimal; import java.math.BigInteger; -import java.math.RoundingMode; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; @@ -44,1454 +33,1364 @@ * Utility class for all Data Dependant Conversions (DDC). */ -final class DDC -{ - - /** - * Convert an Integer object to desired target user type. - * @param intvalue the value to convert. - * @param valueLength the value to convert. - * @param jdbcType the jdbc type required. - * @param streamType the type of stream required. - * @return the required object. - */ - static final Object convertIntegerToObject( - int intValue, - int valueLength, - JDBCType jdbcType, - StreamType streamType) - { - switch (jdbcType) - { - case INTEGER: - return new Integer(intValue); - case SMALLINT: //2.21 small and tinyint returned as short - case TINYINT: - return new Short((short) intValue); - case BIT: - case BOOLEAN: - return new Boolean(0 != intValue); - case BIGINT: - return new Long(intValue); - case DECIMAL: - case NUMERIC: - case MONEY: - case SMALLMONEY: - return new BigDecimal(Integer.toString(intValue)); - case FLOAT: - case DOUBLE: - return new Double(intValue); - case REAL: - return new Float(intValue); - case BINARY: - return convertIntToBytes(intValue, valueLength); - default: - return Integer.toString(intValue); - } - } - - /** - * Convert a Long object to desired target user type. - * @param longVal the value to convert. - * @param jdbcType the jdbc type required. - * @param baseSSType the base SQLServer type. - * @param streamType the stream type. - * @return the required object. - */ - static final Object convertLongToObject(long longVal, JDBCType jdbcType, SSType baseSSType, StreamType streamType) - { - switch (jdbcType) - { - case BIGINT: - return new Long(longVal); - case INTEGER: - return new Integer((int) longVal); - case SMALLINT: // small and tinyint returned as short - case TINYINT: - return new Short((short) longVal); - case BIT: - case BOOLEAN: - return new Boolean(0 != longVal); - case DECIMAL: - case NUMERIC: - case MONEY: - case SMALLMONEY: - return new BigDecimal(Long.toString(longVal)); - case FLOAT: - case DOUBLE: - return new Double(longVal); - case REAL: - return new Float(longVal); - case BINARY: - byte[] convertedBytes = convertLongToBytes(longVal); - int bytesToReturnLength = 0; - byte[] bytesToReturn; - - switch(baseSSType){ - case BIT: - case TINYINT: - bytesToReturnLength = 1; - bytesToReturn = new byte[bytesToReturnLength]; - System.arraycopy(convertedBytes, convertedBytes.length - bytesToReturnLength, bytesToReturn, 0, bytesToReturnLength); - return bytesToReturn; - case SMALLINT: - bytesToReturnLength = 2; - bytesToReturn = new byte[bytesToReturnLength]; - System.arraycopy(convertedBytes, convertedBytes.length - bytesToReturnLength, bytesToReturn, 0, bytesToReturnLength); - return bytesToReturn; - case INTEGER: - bytesToReturnLength = 4; - bytesToReturn = new byte[bytesToReturnLength]; - System.arraycopy(convertedBytes, convertedBytes.length - bytesToReturnLength, bytesToReturn, 0, bytesToReturnLength); - return bytesToReturn; - case BIGINT: - bytesToReturnLength = 8; - bytesToReturn = new byte[bytesToReturnLength]; - System.arraycopy(convertedBytes, convertedBytes.length - bytesToReturnLength, bytesToReturn, 0, bytesToReturnLength); - return bytesToReturn; - default: - return convertedBytes; - } - - case VARBINARY: - switch(baseSSType) - { - case BIGINT: - return new Long(longVal); - case INTEGER: - return new Integer((int) longVal); - case SMALLINT: // small and tinyint returned as short - case TINYINT: - return new Short((short) longVal); - case BIT: - return new Boolean(0 != longVal); - case DECIMAL: - case NUMERIC: - case MONEY: - case SMALLMONEY: - return new BigDecimal(Long.toString(longVal)); - case FLOAT: - return new Double(longVal); - case REAL: - return new Float(longVal); - case BINARY: - return convertLongToBytes(longVal); - default: - return Long.toString(longVal); - } - default: - return Long.toString(longVal); - } - } - - /** - * Encodes an integer value to a byte array in big-endian order. - * @param intValue the integer value to encode. - * @param valueLength the number of bytes to encode. - * @return the byte array containing the big-endian encoded value. - */ - static final byte[] convertIntToBytes(int intValue, int valueLength) - { - byte bytes[] = new byte[valueLength]; - for (int i = valueLength; i-- > 0; ) - { - bytes[i] = (byte)(intValue & 0xFF); - intValue >>= 8; - } - return bytes; - } - - /** - * Convert a Float object to desired target user type. - * @param floatVal the value to convert. - * @param jdbcType the jdbc type required. - * @param streamType the stream type. - * @return the required object. - */ - static final Object convertFloatToObject(float floatVal, JDBCType jdbcType, StreamType streamType) - { - switch (jdbcType) - { - case REAL: - return new Float(floatVal); - case INTEGER: - return new Integer((int) floatVal); - case SMALLINT: // small and tinyint returned as short - case TINYINT: - return new Short((short) floatVal); - case BIT: - case BOOLEAN: - return new Boolean(0 != Float.compare(0.0f, floatVal)); - case BIGINT: - return new Long((long) floatVal); - case DECIMAL: - case NUMERIC: - case MONEY: - case SMALLMONEY: - return new BigDecimal(Float.toString(floatVal)); - case FLOAT: - case DOUBLE: - return new Double((new Float(floatVal)).doubleValue()); - case BINARY: - return convertIntToBytes(Float.floatToRawIntBits(floatVal), 4); - default: - return Float.toString(floatVal); - } - } - - /** - * Encodes a long value to a byte array in big-endian order. - * @param longValue the long value to encode. - * @return the byte array containing the big-endian encoded value. - */ - static final byte[] convertLongToBytes(long longValue) - { - byte bytes[] = new byte[8]; - for (int i = 8; i-- > 0; ) - { - bytes[i] = (byte)(longValue & 0xFF); - longValue >>= 8; - } - return bytes; - } - - /** - * Convert a Double object to desired target user type. - * @param doubleVal the value to convert. - * @param jdbcType the jdbc type required. - * @param streamType the stream type. - * @return the required object. - */ - static final Object convertDoubleToObject(double doubleVal, JDBCType jdbcType, StreamType streamType) - { - switch (jdbcType) - { - case FLOAT: - case DOUBLE: - return new Double(doubleVal); - case REAL: - return new Float((new Double(doubleVal)).floatValue()); - case INTEGER: - return new Integer((int) doubleVal); - case SMALLINT: // small and tinyint returned as short - case TINYINT: - return new Short((short) doubleVal); - case BIT: - case BOOLEAN: - return new Boolean(0 != Double.compare(0.0d, doubleVal)); - case BIGINT: - return new Long((long) doubleVal); - case DECIMAL: - case NUMERIC: - case MONEY: - case SMALLMONEY: - return new BigDecimal(Double.toString(doubleVal)); - case BINARY: - return convertLongToBytes(Double.doubleToRawLongBits(doubleVal)); - default: - return Double.toString(doubleVal); - } - } - - static final byte[] convertBigDecimalToBytes(BigDecimal bigDecimalVal, int scale) - { - byte[] valueBytes; - - if (bigDecimalVal==null) - { - valueBytes = new byte[2]; - valueBytes[0] = (byte) scale; - valueBytes[1] = 0; // data length - } - else - { - boolean isNegative = (bigDecimalVal.signum() < 0); - - // NOTE: Handle negative scale as a special case for JDK 1.5 and later VMs. - if (bigDecimalVal.scale() < 0) - bigDecimalVal = bigDecimalVal.setScale(0); - - BigInteger bi = bigDecimalVal.unscaledValue(); - - if (isNegative) - bi=bi.negate(); - - byte[] unscaledBytes = bi.toByteArray(); - - valueBytes = new byte[unscaledBytes.length + 3]; - int j = 0; - valueBytes[j++] = (byte) bigDecimalVal.scale(); - valueBytes[j++] = (byte) (unscaledBytes.length + 1); // data length + sign - valueBytes[j++] = (byte) (isNegative ? 0 : 1); // 1 = +ve, 0 = -ve - for (int i = unscaledBytes.length - 1; i >= 0; i--) - valueBytes[j++] = unscaledBytes[i]; - } - - return valueBytes; - } - - /** - * Convert a BigDecimal object to desired target user type. - * @param bigDecimalVal the value to convert. - * @param jdbcType the jdbc type required. - * @param streamType the stream type. - * @return the required object. - */ - static final Object convertBigDecimalToObject(BigDecimal bigDecimalVal, JDBCType jdbcType, StreamType streamType) - { - switch (jdbcType) - { - case DECIMAL: - case NUMERIC: - case MONEY: - case SMALLMONEY: - return bigDecimalVal; - case FLOAT: - case DOUBLE: - return new Double(bigDecimalVal.doubleValue()); - case REAL: - return new Float(bigDecimalVal.floatValue()); - case INTEGER: - return new Integer(bigDecimalVal.intValue()); - case SMALLINT: // small and tinyint returned as short - case TINYINT: - return new Short(bigDecimalVal.shortValue()); - case BIT: - case BOOLEAN: - return new Boolean(0 != bigDecimalVal.compareTo(BigDecimal.valueOf(0))); - case BIGINT: - return new Long(bigDecimalVal.longValue()); - case BINARY: - return convertBigDecimalToBytes(bigDecimalVal, bigDecimalVal.scale()); - default: - return bigDecimalVal.toString(); - } - } - - /** - * Convert a Money object to desired target user type. - * @param bigDecimalVal the value to convert. - * @param jdbcType the jdbc type required. - * @param streamType the stream type. - * @param numberOfBytes the number of bytes to convert - * @return the required object. - */ - static final Object convertMoneyToObject(BigDecimal bigDecimalVal, JDBCType jdbcType, StreamType streamType, int numberOfBytes) - { - switch (jdbcType) - { - case DECIMAL: - case NUMERIC: - case MONEY: - case SMALLMONEY: - return bigDecimalVal; - case FLOAT: - case DOUBLE: - return new Double(bigDecimalVal.doubleValue()); - case REAL: - return new Float(bigDecimalVal.floatValue()); - case INTEGER: - return new Integer(bigDecimalVal.intValue()); - case SMALLINT: // small and tinyint returned as short - case TINYINT: - return new Short(bigDecimalVal.shortValue()); - case BIT: - case BOOLEAN: - return new Boolean(0 != bigDecimalVal.compareTo(BigDecimal.valueOf(0))); - case BIGINT: - return new Long(bigDecimalVal.longValue()); - case BINARY: - return convertToBytes(bigDecimalVal, bigDecimalVal.scale(), numberOfBytes); - default: - return bigDecimalVal.toString(); - } - } - - //converts big decimal to money and smallmoney - private static byte[] convertToBytes(BigDecimal value, int scale, int numBytes) - { - boolean isNeg = value.signum() < 0; - - value = value.setScale(scale); - - BigInteger bigInt = value.unscaledValue(); - - byte[] unscaledBytes = bigInt.toByteArray(); - - byte[] ret = new byte[numBytes]; - if (unscaledBytes.length < numBytes) - { - for (int i = 0; i < numBytes - unscaledBytes.length; ++i) - { - ret[i] = (byte) (isNeg ? -1 : 0); - } - } - int offset = numBytes - unscaledBytes.length; - for (int i = offset; i < numBytes; ++i) - { - ret[i] = unscaledBytes[i - offset]; - } - return ret; - } - - /** - * Convert a byte array to desired target user type. - * @param bytesValue the value to convert. - * @param jdbcType the jdbc type required. - * @param baseTypeInfo the type information associated with bytesValue. - * @return the required object. - * @throws SQLServerException when an error occurs. - */ - static final Object convertBytesToObject(byte[] bytesValue, JDBCType jdbcType, TypeInfo baseTypeInfo) throws SQLServerException - { - switch(jdbcType) - { - case CHAR: - String str = Util.bytesToHexString(bytesValue, bytesValue.length); - - if((SSType.BINARY ==baseTypeInfo.getSSType()) - && (str.length() < (baseTypeInfo.getPrecision()*2))){ - - StringBuffer strbuf = new StringBuffer(str); - - while(strbuf.length() < (baseTypeInfo.getPrecision()*2)){ - strbuf.append('0'); - } - return strbuf.toString(); - } - return str; - - case BINARY: - case VARBINARY: - case LONGVARBINARY: - if((SSType.BINARY == baseTypeInfo.getSSType()) - && (bytesValue.length < baseTypeInfo.getPrecision())){ - - byte[] newBytes = new byte[baseTypeInfo.getPrecision()]; - System.arraycopy(bytesValue, 0, newBytes, 0, bytesValue.length); - return newBytes; - } - - return bytesValue; - - default: - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_unsupportedConversionFromTo")); - throw new SQLServerException(form.format(new Object[] {baseTypeInfo.getSSType().name(), jdbcType}), null, 0, null); - } - } - - /** - * Convert a String object to desired target user type. - * @param stringVal the value to convert. - * @param charset the character set. - * @param jdbcType the jdbc type required. - * @return the required object. - */ - static final Object convertStringToObject( - String stringVal, - Charset charset, - JDBCType jdbcType, - StreamType streamType) throws UnsupportedEncodingException, IllegalArgumentException - { - switch (jdbcType) - { - // Convert String to Numeric types. - case DECIMAL: - case NUMERIC: - case MONEY: - case SMALLMONEY: - return new BigDecimal(stringVal.trim()); - case FLOAT: - case DOUBLE: - return Double.valueOf(stringVal.trim()); - case REAL: - return Float.valueOf(stringVal.trim()); - case INTEGER: - return Integer.valueOf(stringVal.trim()); - case SMALLINT: // small and tinyint returned as short - case TINYINT: - return Short.valueOf(stringVal.trim()); - case BIT: - case BOOLEAN: - String trimmedString = stringVal.trim(); - return (1 == trimmedString.length()) ? - Boolean.valueOf('1' == trimmedString.charAt(0)) : - Boolean.valueOf(trimmedString); - case BIGINT: - return Long.valueOf(stringVal.trim()); - - // Convert String to Temporal types. - case TIMESTAMP: - return java.sql.Timestamp.valueOf(stringVal.trim()); - case DATE: - return java.sql.Date.valueOf(getDatePart(stringVal.trim())); - case TIME: - { - // Accepted character formats for conversion to java.sql.Time are: - // hh:mm:ss[.nnnnnnnnn] - // YYYY-MM-DD hh:mm:ss[.nnnnnnnnn] - // - // To handle either of these formats: - // 1) Normalize and parse as a Timestamp - // 2) Round fractional seconds up to the nearest millisecond (max resolution of java.sql.Time) - // 3) Renormalize (as rounding may have changed the date) to a java.sql.Time - java.sql.Timestamp ts = java.sql.Timestamp.valueOf(TDS.BASE_DATE_1970 +" "+ getTimePart(stringVal.trim())); - GregorianCalendar cal = new GregorianCalendar(Locale.US); - cal.clear(); - cal.setTimeInMillis(ts.getTime()); - if (ts.getNanos() % Nanos.PER_MILLISECOND >= Nanos.PER_MILLISECOND / 2) - cal.add(Calendar.MILLISECOND, 1); - cal.set(TDS.BASE_YEAR_1970, Calendar.JANUARY, 1); - return new java.sql.Time(cal.getTimeInMillis()); - } - - case BINARY: - return stringVal.getBytes(charset); - - default: - // For everything else, just return either a string or appropriate stream. - switch (streamType) - { - case CHARACTER: - return new StringReader(stringVal); - case ASCII: - return new ByteArrayInputStream(stringVal.getBytes(US_ASCII)); - case BINARY: - return new ByteArrayInputStream(stringVal.getBytes()); - - default: - return stringVal; - } - } - } - - static final Object convertStreamToObject( - BaseInputStream stream, - TypeInfo typeInfo, - JDBCType jdbcType, - InputStreamGetterArgs getterArgs) throws SQLServerException - { - // Need to handle the simple case of a null value here, as it is not done - // outside this function. - if (null == stream) - return null; - - assert null != typeInfo; - assert null != getterArgs; - - SSType ssType = typeInfo.getSSType(); - - try - { - switch (jdbcType) - { - case CHAR: - case VARCHAR: - case LONGVARCHAR: - case NCHAR: - case NVARCHAR: - case LONGNVARCHAR: - default: - - // Binary streams to character types: - // - Direct conversion to ASCII stream - // - Convert as hexized value to other character types - if (SSType.BINARY == ssType || - SSType.VARBINARY == ssType || - SSType.VARBINARYMAX == ssType || - SSType.TIMESTAMP == ssType || - SSType.IMAGE == ssType || - SSType.UDT == ssType) - { - if (StreamType.ASCII == getterArgs.streamType) - { - return stream; - } - else - { - assert StreamType.CHARACTER == getterArgs.streamType || - StreamType.NONE == getterArgs.streamType; - - byte[] byteValue = stream.getBytes(); - if(JDBCType.GUID == jdbcType) - { - return Util.readGUID(byteValue); - } - else - { - String hexString = Util.bytesToHexString(byteValue, byteValue.length); - - if (StreamType.NONE == getterArgs.streamType) - return hexString; - - return new StringReader(hexString); - } - } - } - - // Handle streams converting to ASCII - if (StreamType.ASCII == getterArgs.streamType) - { - // Fast path for SBCS data that converts directly/easily to ASCII - if (typeInfo.supportsFastAsciiConversion()) - return new AsciiFilteredInputStream(stream); - - // Slightly less fast path for MBCS data that converts directly/easily to ASCII - if (getterArgs.isAdaptive) - { - return AsciiFilteredUnicodeInputStream.MakeAsciiFilteredUnicodeInputStream( - stream, - new BufferedReader(new InputStreamReader(stream, typeInfo.getCharset()))); - } - else - { - return new ByteArrayInputStream((new String(stream.getBytes(), typeInfo.getCharset())).getBytes(US_ASCII)); - } - } - else if (StreamType.CHARACTER == getterArgs.streamType || - StreamType.NCHARACTER == getterArgs.streamType) - { - if (getterArgs.isAdaptive) - return new BufferedReader(new InputStreamReader(stream, typeInfo.getCharset())); - else - return new StringReader(new String(stream.getBytes(), typeInfo.getCharset())); - } - - // None of the special/fast textual conversion cases applied. Just go the normal route of converting via String. - return convertStringToObject(new String(stream.getBytes(), typeInfo.getCharset()), typeInfo.getCharset(), jdbcType, getterArgs.streamType); - - case CLOB: - return new SQLServerClob(stream, typeInfo); - - case NCLOB: - return new SQLServerNClob(stream, typeInfo); - case SQLXML: - return new SQLServerSQLXML(stream, getterArgs, typeInfo); - - case BINARY: - case VARBINARY: - case LONGVARBINARY: - case BLOB: - - // Where allowed, streams convert directly to binary representation - - if (StreamType.BINARY == getterArgs.streamType) - return stream; - - if (JDBCType.BLOB == jdbcType) - return new SQLServerBlob(stream); - - return stream.getBytes(); - } - } - - // Conversion can throw either of these exceptions: - // - // UnsupportedEncodingException (binary conversions) - // IllegalArgumentException (any conversion - note: numerics throw NumberFormatException subclass) - // - // Catch them and translate them to a SQLException so that we don't propagate an unexpected exception - // type all the way up to the app, which may not catch it either... - catch (IllegalArgumentException e) - { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_errorConvertingValue")); - throw new SQLServerException(form.format(new Object[] {typeInfo.getSSType(), jdbcType}), null, 0, e); - } - catch (UnsupportedEncodingException e) - { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_errorConvertingValue")); - throw new SQLServerException(form.format(new Object[] {typeInfo.getSSType(), jdbcType}), null, 0, e); - } - } - - // Returns date portion of string. - // Expects one of "" or "