diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/Util.java b/src/main/java/com/microsoft/sqlserver/jdbc/Util.java index d1b0decf76..f99e8fc75e 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/Util.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/Util.java @@ -244,7 +244,7 @@ static BigDecimal readBigDecimal(byte valueBytes[], String name = ""; String value = ""; StringBuilder builder; - + if (!tmpUrl.startsWith(sPrefix)) return null; @@ -911,7 +911,7 @@ else if (("" + value).contains("E")) { case TIME: case DATETIMEOFFSET: return ((null == scale) ? TDS.MAX_FRACTIONAL_SECONDS_SCALE : scale); - + case CLOB: return ((null == value) ? 0 : (DataTypes.NTEXT_MAX_CHARS * 2)); @@ -953,7 +953,7 @@ static synchronized boolean checkIfNeedNewAccessToken(SQLServerConnection connec } static final boolean use42Wrapper; - + static { boolean supportJDBC42 = true; try { diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java index b646d8e450..b164f004dd 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java @@ -13,11 +13,11 @@ import java.io.IOException; import java.sql.DriverManager; import java.sql.SQLException; -import java.sql.Statement; import java.util.Properties; import javax.xml.bind.DatatypeConverter; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.platform.runner.JUnitPlatform; import org.junit.runner.RunWith; @@ -27,71 +27,84 @@ import com.microsoft.sqlserver.jdbc.SQLServerColumnEncryptionKeyStoreProvider; import com.microsoft.sqlserver.jdbc.SQLServerConnection; import com.microsoft.sqlserver.jdbc.SQLServerException; +import com.microsoft.sqlserver.jdbc.SQLServerStatement; +import com.microsoft.sqlserver.jdbc.SQLServerStatementColumnEncryptionSetting; import com.microsoft.sqlserver.testframework.AbstractTest; import com.microsoft.sqlserver.testframework.DBConnection; import com.microsoft.sqlserver.testframework.Utils; +import com.microsoft.sqlserver.testframework.util.Util; + import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assumptions.assumeTrue; /** - * Setup for Always Encrypted test - * This test will work on Appveyor and Travis-ci as java key store gets created from the .yml scripts. Users on their local machine should create the - * keystore manually and save the alias name in JavaKeyStore.txt file. For local test purposes, put this in the target/test-classes directory + * Setup for Always Encrypted test This test will work on Appveyor and Travis-ci as java key store gets created from the .yml scripts. Users on their + * local machine should create the keystore manually and save the alias name in JavaKeyStore.txt file. For local test purposes, put this in the + * target/test-classes directory * */ @RunWith(JUnitPlatform.class) public class AESetup extends AbstractTest { - static String javaKeyStoreInputFile = "JavaKeyStore.txt"; - static String keyStoreName = "MSSQL_JAVA_KEYSTORE"; - static String jksName = "clientcert.jks"; + static final String javaKeyStoreInputFile = "JavaKeyStore.txt"; + static final String keyStoreName = "MSSQL_JAVA_KEYSTORE"; + static final String jksName = "clientcert.jks"; + static final String cmkName = "JDBC_CMK"; + static final String cekName = "JDBC_CEK"; + static final String secretstrJks = "password"; + static final String numericTable = "JDBCEncrpytedNumericTable"; + static final String charTable = "JDBCEncrpytedCharTable"; + static final String binaryTable = "JDBCEncrpytedBinaryTable"; + static final String dateTable = "JDBCEncrpytedDateTable"; + static final String uid = "171fbe25-4331-4765-a838-b2e3eea3e7ea"; + static String filePath = null; static String thumbprint = null; static SQLServerConnection con = null; - static Statement stmt = null; - static String cmkName = "JDBC_CMK"; - static String cekName = "JDBC_CEK"; + static SQLServerStatement stmt = null; static String keyPath = null; static String javaKeyAliases = null; static String OS = System.getProperty("os.name").toLowerCase(); static SQLServerColumnEncryptionKeyStoreProvider storeProvider = null; - static String secretstrJks = "password"; - static String numericTable = "numericTable"; + static SQLServerStatementColumnEncryptionSetting stmtColEncSetting = null; /** * Create connection, statement and generate path of resource file - * @throws Exception - * @throws TestAbortedException + * + * @throws Exception + * @throws TestAbortedException */ @BeforeAll static void setUpConnection() throws TestAbortedException, Exception { assumeTrue(13 <= new DBConnection(connectionString).getServerVersion(), "Aborting test case as SQL Server version is not compatible with Always encrypted "); + String AETestConenctionString = connectionString + ";sendTimeAsDateTime=false"; + readFromFile(javaKeyStoreInputFile, "Alias name"); - con = (SQLServerConnection) DriverManager.getConnection(connectionString); - stmt = con.createStatement(); - Utils.dropTableIfExists(numericTable, stmt); + con = (SQLServerConnection) DriverManager.getConnection(AETestConenctionString); + stmt = (SQLServerStatement) con.createStatement(); dropCEK(); dropCMK(); con.close(); - keyPath = Utils.getCurrentClassPath() + jksName; storeProvider = new SQLServerColumnEncryptionJavaKeyStoreProvider(keyPath, secretstrJks.toCharArray()); + stmtColEncSetting = SQLServerStatementColumnEncryptionSetting.Enabled; Properties info = new Properties(); info.setProperty("ColumnEncryptionSetting", "Enabled"); info.setProperty("keyStoreAuthentication", "JavaKeyStorePassword"); info.setProperty("keyStoreLocation", keyPath); info.setProperty("keyStoreSecret", secretstrJks); - con = (SQLServerConnection) DriverManager.getConnection(connectionString, info); - stmt = con.createStatement(); + con = (SQLServerConnection) DriverManager.getConnection(AETestConenctionString, info); + stmt = (SQLServerStatement) con.createStatement(); createCMK(keyStoreName, javaKeyAliases); + createCEK(storeProvider); } /** - * Read the alias from file which is created during creating jks - * If the jks and alias name in JavaKeyStore.txt does not exists, will not run! + * Read the alias from file which is created during creating jks If the jks and alias name in JavaKeyStore.txt does not exists, will not run! + * * @param inputFile * @param lookupValue * @throws IOException @@ -109,7 +122,7 @@ private static void readFromFile(String inputFile, while ((readLine = buffer.readLine()) != null) { if (readLine.trim().contains(lookupValue)) { - linecontents = readLine.split(" "); + linecontents = readLine.split(" "); javaKeyAliases = linecontents[2]; break; } @@ -117,10 +130,10 @@ private static void readFromFile(String inputFile, } catch (IOException e) { - fail(e.toString());; + fail(e.toString()); } - finally{ - if (null != buffer){ + finally { + if (null != buffer) { buffer.close(); } } @@ -128,17 +141,265 @@ private static void readFromFile(String inputFile, } /** - * Creating numeric table + * Create encrypted table for Binary + * + * @throws SQLException + */ + static void createBinaryTable() throws SQLException { + String sql = "create table " + binaryTable + " (" + "PlainBinary binary(20) null," + + "RandomizedBinary binary(20) ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicBinary binary(20) ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainVarbinary varbinary(50) null," + + "RandomizedVarbinary varbinary(50) ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicVarbinary varbinary(50) ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainVarbinaryMax varbinary(max) null," + + "RandomizedVarbinaryMax varbinary(max) ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicVarbinaryMax varbinary(max) ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainBinary512 binary(512) null," + + "RandomizedBinary512 binary(512) ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicBinary512 binary(512) ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainBinary8000 varbinary(8000) null," + + "RandomizedBinary8000 varbinary(8000) ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicBinary8000 varbinary(8000) ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + ");"; + + stmt.execute(sql); + } + + /** + * Create encrypted table for Char + * + * @throws SQLException + */ + static void createCharTable() throws SQLException { + String sql = "create table " + charTable + " (" + "PlainChar char(20) null," + + "RandomizedChar char(20) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicChar char(20) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainVarchar varchar(50) null," + + "RandomizedVarchar varchar(50) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicVarchar varchar(50) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainVarcharMax varchar(max) null," + + "RandomizedVarcharMax varchar(max) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicVarcharMax varchar(max) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainNchar nchar(30) null," + + "RandomizedNchar nchar(30) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicNchar nchar(30) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainNvarchar nvarchar(60) null," + + "RandomizedNvarchar nvarchar(60) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicNvarchar nvarchar(60) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainNvarcharMax nvarchar(max) null," + + "RandomizedNvarcharMax nvarchar(max) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicNvarcharMax nvarchar(max) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainUniqueidentifier uniqueidentifier null," + + "RandomizedUniqueidentifier uniqueidentifier ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicUniqueidentifier uniqueidentifier ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainVarchar8000 varchar(8000) null," + + "RandomizedVarchar8000 varchar(8000) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicVarchar8000 varchar(8000) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainNvarchar4000 nvarchar(4000) null," + + "RandomizedNvarchar4000 nvarchar(4000) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicNvarchar4000 nvarchar(4000) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + ");"; + + stmt.execute(sql); + } + + /** + * Create encrypted table for Date + * + * @throws SQLException + */ + static void createDateTable() throws SQLException { + String sql = "create table " + dateTable + " (" + "PlainDate date null," + + "RandomizedDate date ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicDate date ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainDatetime2Default datetime2 null," + + "RandomizedDatetime2Default datetime2 ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicDatetime2Default datetime2 ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainDatetimeoffsetDefault datetimeoffset null," + + "RandomizedDatetimeoffsetDefault datetimeoffset ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicDatetimeoffsetDefault datetimeoffset ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainTimeDefault time null," + + "RandomizedTimeDefault time ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicTimeDefault time ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainDatetime datetime null," + + "RandomizedDatetime datetime ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicDatetime datetime ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainSmalldatetime smalldatetime null," + + "RandomizedSmalldatetime smalldatetime ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicSmalldatetime smalldatetime ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + ");"; + + stmt.execute(sql); + } + + /** + * Create encrypted table for Numeric + * + * @throws SQLException */ - static void createNumericTable() { - String sql = "create table " + numericTable + " (" + "PlainSmallint smallint null," + static void createNumericTable() throws SQLException { + String sql = "create table " + numericTable + " (" + "PlainBit bit null," + + "RandomizedBit bit ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicBit bit ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainTinyint tinyint null," + + "RandomizedTinyint tinyint ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicTinyint tinyint ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainSmallint smallint null," + "RandomizedSmallint smallint ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + cekName + ") NULL," + "DeterministicSmallint smallint ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " - + cekName + ") NULL" + ");"; + + cekName + ") NULL," + + + "PlainInt int null," + + "RandomizedInt int ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicInt int ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainBigint bigint null," + + "RandomizedBigint bigint ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicBigint bigint ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainFloatDefault float null," + + "RandomizedFloatDefault float ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicFloatDefault float ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainFloat float(30) null," + + "RandomizedFloat float(30) ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicFloat float(30) ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainReal real null," + + "RandomizedReal real ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicReal real ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainDecimalDefault decimal null," + + "RandomizedDecimalDefault decimal ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicDecimalDefault decimal ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainDecimal decimal(10,5) null," + + "RandomizedDecimal decimal(10,5) ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicDecimal decimal(10,5) ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainNumericDefault numeric null," + + "RandomizedNumericDefault numeric ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicNumericDefault numeric ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainNumeric numeric(8,2) null," + + "RandomizedNumeric numeric(8,2) ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicNumeric numeric(8,2) ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainSmallMoney smallmoney null," + + "RandomizedSmallMoney smallmoney ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicSmallMoney smallmoney ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainMoney money null," + + "RandomizedMoney money ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicMoney money ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainDecimal2 decimal(28,4) null," + + "RandomizedDecimal2 decimal(28,4) ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicDecimal2 decimal(28,4) ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainNumeric2 numeric(28,4) null," + + "RandomizedNumeric2 numeric(28,4) ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + "DeterministicNumeric2 numeric(28,4) ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + ");"; try { stmt.execute(sql); + stmt.execute("DBCC FREEPROCCACHE"); } catch (SQLException e) { fail(e.toString()); @@ -147,6 +408,7 @@ static void createNumericTable() { /** * Create column master key + * * @param keyStoreName * @param keyPath * @throws SQLException @@ -160,6 +422,7 @@ private static void createCMK(String keyStoreName, /** * Create column encryption key + * * @param storeProvider * @param certStore * @throws SQLException @@ -170,12 +433,25 @@ static void createCEK(SQLServerColumnEncryptionKeyStoreProvider storeProvider) t String cekSql = null; byte[] key = storeProvider.encryptColumnEncryptionKey(javaKeyAliases, "RSA_OAEP", valuesDefault); cekSql = "CREATE COLUMN ENCRYPTION KEY " + cekName + " WITH VALUES " + "(COLUMN_MASTER_KEY = " + cmkName - + ", ALGORITHM = 'RSA_OAEP', ENCRYPTED_VALUE = 0x" + DatatypeConverter.printHexBinary(key) + ")" + ";"; + + ", ALGORITHM = 'RSA_OAEP', ENCRYPTED_VALUE = 0x" + DatatypeConverter.printHexBinary(key) + ")" + ";"; stmt.execute(cekSql); } + /** + * Drop all tables that are in use by AE + * + * @throws SQLException + */ + static void dropTables() throws SQLException { + Utils.dropTableIfExists(numericTable, stmt); + Utils.dropTableIfExists(charTable, stmt); + Utils.dropTableIfExists(binaryTable, stmt); + Utils.dropTableIfExists(dateTable, stmt); + } + /** * Dropping column encryption key + * * @throws SQLServerException * @throws SQLException */ @@ -187,6 +463,7 @@ static void dropCEK() throws SQLServerException, SQLException { /** * Dropping column master key + * * @throws SQLServerException * @throws SQLException */ diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/JDBCEncryptionDecryptionTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/JDBCEncryptionDecryptionTest.java index ad3729d7af..2f647ef37e 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/JDBCEncryptionDecryptionTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/JDBCEncryptionDecryptionTest.java @@ -7,14 +7,21 @@ */ package com.microsoft.sqlserver.jdbc.AlwaysEncrypted; -import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assumptions.assumeTrue; +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.SQLException; +import java.sql.Statement; +import java.sql.Time; +import java.sql.Timestamp; +import java.util.LinkedList; import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.platform.runner.JUnitPlatform; import org.junit.runner.RunWith; @@ -22,9 +29,12 @@ import com.microsoft.sqlserver.jdbc.SQLServerException; import com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement; -import com.microsoft.sqlserver.jdbc.SQLServerStatementColumnEncryptionSetting; -import com.microsoft.sqlserver.testframework.DBConnection; -import com.microsoft.sqlserver.testframework.Utils; +import com.microsoft.sqlserver.jdbc.SQLServerResultSet; +import com.microsoft.sqlserver.jdbc.SQLServerStatement; +import com.microsoft.sqlserver.testframework.util.RandomData; +import com.microsoft.sqlserver.testframework.util.Util; + +import microsoft.sql.DateTimeOffset; /** * Tests Decryption and encryption of values @@ -32,30 +42,482 @@ */ @RunWith(JUnitPlatform.class) public class JDBCEncryptionDecryptionTest extends AESetup { - private static SQLServerPreparedStatement pstmt = null; - String[] values = {"10"}; + private SQLServerPreparedStatement pstmt = null; + + private boolean nullable = false; + private String[] numericValues = null; + private String[] numericValues2 = null; + private String[] numericValuesNull = null; + private String[] numericValuesNull2 = null; + private String[] charValues = null; + + private LinkedList byteValuesSetObject = null; + private LinkedList byteValuesNull = null; + + private LinkedList dateValues = null; /** - * Test encryption and decryption of numeric values + * Junit test case for char set string for string values * - * @throws Exception - * @throws TestAbortedException + * @throws SQLException */ @Test - @DisplayName("test numeric values") - public void testNumeric() throws TestAbortedException, Exception { - assumeTrue(13 <= new DBConnection(connectionString).getServerVersion(), - "Aborting test case as SQL Server version is not compatible with Always encrypted "); + public void testCharSpecificSetter() throws SQLException { + charValues = createCharValues(); + dropTables(); + createCharTable(); + populateCharNormalCase(charValues); + testChar(stmt, charValues); + testChar(null, charValues); + } - try { - createCEK(storeProvider); - createNumericTable(); - populateNumeric(values); - verifyResults(); - } - finally { - Utils.dropTableIfExists(numericTable, stmt); - } + /** + * Junit test case for char set object for string values + * + * @throws SQLException + */ + @Test + public void testCharSetObject() throws SQLException { + charValues = createCharValues(); + dropTables(); + createCharTable(); + populateCharSetObject(charValues); + testChar(stmt, charValues); + testChar(null, charValues); + } + + /** + * Junit test case for char set object for jdbc string values + * + * @throws SQLException + */ + @Test + public void testCharSetObjectWithJDBCTypes() throws SQLException { + skipTestForJava7(); + + charValues = createCharValues(); + dropTables(); + createCharTable(); + populateCharSetObjectWithJDBCTypes(charValues); + testChar(stmt, charValues); + testChar(null, charValues); + } + + /** + * Junit test case for char set string for null values + * + * @throws SQLException + */ + @Test + public void testCharSpecificSetterNull() throws SQLException { + String[] charValuesNull = {null, null, null, null, null, null, null, null, null}; + dropTables(); + createCharTable(); + populateCharNormalCase(charValuesNull); + testChar(stmt, charValuesNull); + testChar(null, charValuesNull); + } + + /** + * Junit test case for char set object for null values + * + * @throws SQLException + */ + @Test + public void testCharSetObjectNull() throws SQLException { + String[] charValuesNull = {null, null, null, null, null, null, null, null, null}; + dropTables(); + createCharTable(); + populateCharSetObject(charValuesNull); + testChar(stmt, charValuesNull); + testChar(null, charValuesNull); + } + + /** + * Junit test case for char set null for null values + * + * @throws SQLException + */ + @Test + public void testCharSetNull() throws SQLException { + String[] charValuesNull = {null, null, null, null, null, null, null, null, null}; + dropTables(); + createCharTable(); + populateCharNullCase(); + testChar(stmt, charValuesNull); + testChar(null, charValuesNull); + } + + /** + * Junit test case for binary set binary for binary values + * + * @throws SQLException + */ + @Test + public void testBinarySpecificSetter() throws SQLException { + LinkedList byteValues = createbinaryValues(false); + dropTables(); + createBinaryTable(); + populateBinaryNormalCase(byteValues); + testBinary(stmt, byteValues); + testBinary(null, byteValues); + } + + /** + * Junit test case for binary set object for binary values + * + * @throws SQLException + */ + @Test + public void testBinarySetobject() throws SQLException { + byteValuesSetObject = createbinaryValues(false); + dropTables(); + createBinaryTable(); + populateBinarySetObject(byteValuesSetObject); + testBinary(stmt, byteValuesSetObject); + testBinary(null, byteValuesSetObject); + } + + /** + * Junit test case for binary set null for binary values + * + * @throws SQLException + */ + @Test + public void testBinarySetNull() throws SQLException { + byteValuesNull = createbinaryValues(true); + dropTables(); + createBinaryTable(); + populateBinaryNullCase(); + testBinary(stmt, byteValuesNull); + testBinary(null, byteValuesNull); + } + + /** + * Junit test case for binary set binary for null values + * + * @throws SQLException + */ + @Test + public void testBinarySpecificSetterNull() throws SQLException { + byteValuesNull = createbinaryValues(true); + dropTables(); + createBinaryTable(); + populateBinaryNormalCase(null); + testBinary(stmt, byteValuesNull); + testBinary(null, byteValuesNull); + } + + /** + * Junit test case for binary set object for null values + * + * @throws SQLException + */ + @Test + public void testBinarysetObjectNull() throws SQLException { + byteValuesNull = createbinaryValues(true); + dropTables(); + createBinaryTable(); + populateBinarySetObject(null); + testBinary(stmt, byteValuesNull); + testBinary(null, byteValuesNull); + } + + /** + * Junit test case for binary set object for jdbc type binary values + * + * @throws SQLException + */ + @Test + public void testBinarySetObjectWithJDBCTypes() throws SQLException { + skipTestForJava7(); + + byteValuesSetObject = createbinaryValues(false); + dropTables(); + createBinaryTable(); + populateBinarySetObjectWithJDBCType(byteValuesSetObject); + testBinary(stmt, byteValuesSetObject); + testBinary(null, byteValuesSetObject); + } + + /** + * Junit test case for date set date for date values + * + * @throws SQLException + */ + @Test + public void testDateSpecificSetter() throws SQLException { + dateValues = createTemporalTypes(); + dropTables(); + createDateTable(); + populateDateNormalCase(dateValues); + testDate(stmt, dateValues); + testDate(null, dateValues); + } + + /** + * Junit test case for date set object for date values + * + * @throws SQLException + */ + @Test + public void testDateSetObject() throws SQLException { + dateValues = createTemporalTypes(); + dropTables(); + createDateTable(); + populateDateSetObject(dateValues, ""); + testDate(stmt, dateValues); + testDate(null, dateValues); + } + + /** + * Junit test case for date set object for java date values + * + * @throws SQLException + */ + @Test + public void testDateSetObjectWithJavaType() throws SQLException { + dateValues = createTemporalTypes(); + dropTables(); + createDateTable(); + populateDateSetObject(dateValues, "setwithJavaType"); + testDate(stmt, dateValues); + testDate(null, dateValues); + } + + /** + * Junit test case for date set object for jdbc date values + * + * @throws SQLException + */ + @Test + public void testDateSetObjectWithJDBCType() throws SQLException { + dateValues = createTemporalTypes(); + dropTables(); + createDateTable(); + populateDateSetObject(dateValues, "setwithJDBCType"); + testDate(stmt, dateValues); + testDate(null, dateValues); + } + + /** + * Junit test case for date set date for min/max date values + * + * @throws SQLException + */ + @Test + public void testDateSpecificSetterMinMaxValue() throws SQLException { + RandomData.returnMinMax = true; + dateValues = createTemporalTypes(); + dropTables(); + createDateTable(); + populateDateNormalCase(dateValues); + testDate(stmt, dateValues); + testDate(null, dateValues); + } + + /** + * Junit test case for date set date for null values + * + * @throws SQLException + */ + @Test + public void testDateSetNull() throws SQLException { + RandomData.returnNull = true; + nullable = true; + + dateValues = createTemporalTypes(); + dropTables(); + createDateTable(); + populateDateNullCase(); + testDate(stmt, dateValues); + testDate(null, dateValues); + + nullable = false; + RandomData.returnNull = false; + } + + /** + * Junit test case for date set object for null values + * + * @throws SQLException + */ + @Test + public void testDateSetObjectNull() throws SQLException { + RandomData.returnNull = true; + nullable = true; + + dateValues = createTemporalTypes(); + dropTables(); + createDateTable(); + populateDateSetObjectNull(); + testDate(stmt, dateValues); + testDate(null, dateValues); + + nullable = false; + RandomData.returnNull = false; + } + + /** + * Junit test case for numeric set numeric for numeric values + * + * @throws SQLException + */ + @Test + public void testNumericSpecificSetter() throws TestAbortedException, Exception { + numericValues = createNumericValues(); + numericValues2 = new String[numericValues.length]; + System.arraycopy(numericValues, 0, numericValues2, 0, numericValues.length); + + dropTables(); + createNumericTable(); + populateNumeric(numericValues); + testNumeric(stmt, numericValues, false); + testNumeric(null, numericValues2, false); + } + + /** + * Junit test case for numeric set object for numeric values + * + * @throws SQLException + */ + @Test + public void testNumericSetObject() throws SQLException { + numericValues = createNumericValues(); + numericValues2 = new String[numericValues.length]; + System.arraycopy(numericValues, 0, numericValues2, 0, numericValues.length); + + dropTables(); + createNumericTable(); + populateNumericSetObject(numericValues); + testNumeric(null, numericValues, false); + testNumeric(stmt, numericValues2, false); + } + + /** + * Junit test case for numeric set object for jdbc type numeric values + * + * @throws SQLException + */ + @Test + public void testNumericSetObjectWithJDBCTypes() throws SQLException { + skipTestForJava7(); + + numericValues = createNumericValues(); + numericValues2 = new String[numericValues.length]; + System.arraycopy(numericValues, 0, numericValues2, 0, numericValues.length); + + dropTables(); + createNumericTable(); + populateNumericSetObjectWithJDBCTypes(numericValues); + testNumeric(stmt, numericValues, false); + testNumeric(null, numericValues2, false); + } + + /** + * Junit test case for numeric set numeric for max numeric values + * + * @throws SQLException + */ + @Test + public void testNumericSpecificSetterMaxValue() throws SQLException { + String[] numericValuesBoundaryPositive = {"true", "255", "32767", "2147483647", "9223372036854775807", "1.79E308", "1.123", "3.4E38", + "999999999999999999", "12345.12345", "999999999999999999", "567812.78", "214748.3647", "922337203685477.5807", + "999999999999999999999999.9999", "999999999999999999999999.9999"}; + String[] numericValuesBoundaryPositive2 = {"true", "255", "32767", "2147483647", "9223372036854775807", "1.79E308", "1.123", "3.4E38", + "999999999999999999", "12345.12345", "999999999999999999", "567812.78", "214748.3647", "922337203685477.5807", + "999999999999999999999999.9999", "999999999999999999999999.9999"}; + + dropTables(); + createNumericTable(); + populateNumeric(numericValuesBoundaryPositive); + testNumeric(stmt, numericValuesBoundaryPositive, false); + testNumeric(null, numericValuesBoundaryPositive2, false); + } + + /** + * Junit test case for numeric set numeric for min numeric values + * + * @throws SQLException + */ + @Test + public void testNumericSpecificSetterMinValue() throws SQLException { + String[] numericValuesBoundaryNegtive = {"false", "0", "-32768", "-2147483648", "-9223372036854775808", "-1.79E308", "1.123", "-3.4E38", + "999999999999999999", "12345.12345", "999999999999999999", "567812.78", "-214748.3648", "-922337203685477.5808", + "999999999999999999999999.9999", "999999999999999999999999.9999"}; + String[] numericValuesBoundaryNegtive2 = {"false", "0", "-32768", "-2147483648", "-9223372036854775808", "-1.79E308", "1.123", "-3.4E38", + "999999999999999999", "12345.12345", "999999999999999999", "567812.78", "-214748.3648", "-922337203685477.5808", + "999999999999999999999999.9999", "999999999999999999999999.9999"}; + + dropTables(); + createNumericTable(); + populateNumeric(numericValuesBoundaryNegtive); + testNumeric(stmt, numericValuesBoundaryNegtive, false); + testNumeric(null, numericValuesBoundaryNegtive2, false); + } + + /** + * Junit test case for numeric set numeric for null values + * + * @throws SQLException + */ + @Test + public void testNumericSpecificSetterNull() throws SQLException { + nullable = true; + RandomData.returnNull = true; + numericValuesNull = createNumericValues(); + numericValuesNull2 = new String[numericValuesNull.length]; + System.arraycopy(numericValuesNull, 0, numericValuesNull2, 0, numericValuesNull.length); + + dropTables(); + createNumericTable(); + populateNumericNullCase(numericValuesNull); + testNumeric(stmt, numericValuesNull, true); + testNumeric(null, numericValuesNull2, true); + + nullable = false; + RandomData.returnNull = false; + } + + /** + * Junit test case for numeric set object for null values + * + * @throws SQLException + */ + @Test + public void testNumericSpecificSetterSetObjectNull() throws SQLException { + nullable = true; + RandomData.returnNull = true; + numericValuesNull = createNumericValues(); + numericValuesNull2 = new String[numericValuesNull.length]; + System.arraycopy(numericValuesNull, 0, numericValuesNull2, 0, numericValuesNull.length); + + dropTables(); + createNumericTable(); + populateNumericSetObjectNull(); + testNumeric(stmt, numericValuesNull, true); + testNumeric(null, numericValuesNull2, true); + + nullable = false; + RandomData.returnNull = false; + } + + /** + * Junit test case for numeric set numeric for null normalization values + * + * @throws SQLException + */ + @Test + public void testNumericNormalization() throws SQLException { + String[] numericValuesNormalization = {"true", "1", "127", "100", "100", "1.123", "1.123", "1.123", "123456789123456789", "12345.12345", + "987654321123456789", "567812.78", "7812.7812", "7812.7812", "999999999999999999999999.9999", "999999999999999999999999.9999"}; + String[] numericValuesNormalization2 = {"true", "1", "127", "100", "100", "1.123", "1.123", "1.123", "123456789123456789", "12345.12345", + "987654321123456789", "567812.78", "7812.7812", "7812.7812", "999999999999999999999999.9999", "999999999999999999999999.9999"}; + dropTables(); + createNumericTable(); + populateNumericNormalization(numericValuesNormalization); + testNumeric(stmt, numericValuesNormalization, false); + testNumeric(null, numericValuesNormalization2, false); } /** @@ -66,64 +528,1940 @@ public void testNumeric() throws TestAbortedException, Exception { */ @AfterAll static void dropAll() throws SQLServerException, SQLException { - Utils.dropTableIfExists(numericTable, stmt); + dropTables(); dropCEK(); dropCMK(); - if (null != stmt) { - stmt.close(); + Util.close(null, stmt, connection); + } + + private void populateBinaryNormalCase(LinkedList byteValues) throws SQLException { + String sql = "insert into " + binaryTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; + + pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting); + + // binary20 + for (int i = 1; i <= 3; i++) { + if (null == byteValues) { + pstmt.setBytes(i, null); + } + else { + pstmt.setBytes(i, byteValues.get(0)); + } + } + + // varbinary50 + for (int i = 4; i <= 6; i++) { + if (null == byteValues) { + pstmt.setBytes(i, null); + } + else { + pstmt.setBytes(i, byteValues.get(1)); + } + } + + // varbinary(max) + for (int i = 7; i <= 9; i++) { + if (null == byteValues) { + pstmt.setBytes(i, null); + } + else { + pstmt.setBytes(i, byteValues.get(2)); + } + } + + // binary(512) + for (int i = 10; i <= 12; i++) { + if (null == byteValues) { + pstmt.setBytes(i, null); + } + else { + pstmt.setBytes(i, byteValues.get(3)); + } } - if (null != con) { - con.close(); + + // varbinary(8000) + for (int i = 13; i <= 15; i++) { + if (null == byteValues) { + pstmt.setBytes(i, null); + } + else { + pstmt.setBytes(i, byteValues.get(4)); + } } + + pstmt.execute(); + Util.close(null, pstmt, null); } - /** - * Populating the table - * - * @param values - * @throws SQLException - */ - private void populateNumeric(String[] values) throws SQLException { - String sql = "insert into " + numericTable + " values( " + "?,?,?" + ")"; + private void populateBinarySetObject(LinkedList byteValues) throws SQLException { + String sql = "insert into " + binaryTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; - pstmt = (SQLServerPreparedStatement) con.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, - connection.getHoldability(), SQLServerStatementColumnEncryptionSetting.Enabled); + pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting); + // binary(20) for (int i = 1; i <= 3; i++) { - pstmt.setShort(i, Short.valueOf(values[0])); + if (null == byteValues) { + pstmt.setObject(i, null, java.sql.Types.BINARY); + } + else { + pstmt.setObject(i, byteValues.get(0)); + } } - pstmt.execute(); - if (null != pstmt) { - pstmt.close(); + + // varbinary(50) + for (int i = 4; i <= 6; i++) { + if (null == byteValues) { + pstmt.setObject(i, null, java.sql.Types.BINARY); + } + else { + pstmt.setObject(i, byteValues.get(1)); + } + } + + // varbinary(max) + for (int i = 7; i <= 9; i++) { + if (null == byteValues) { + pstmt.setObject(i, null, java.sql.Types.BINARY); + } + else { + pstmt.setObject(i, byteValues.get(2)); + } + } + + // binary(512) + for (int i = 10; i <= 12; i++) { + if (null == byteValues) { + pstmt.setObject(i, null, java.sql.Types.BINARY); + } + else { + pstmt.setObject(i, byteValues.get(3)); + } + } + + // varbinary(8000) + for (int i = 13; i <= 15; i++) { + if (null == byteValues) { + pstmt.setObject(i, null, java.sql.Types.BINARY); + } + else { + pstmt.setObject(i, byteValues.get(4)); + } } + + pstmt.execute(); + Util.close(null, pstmt, null); } - /** - * Verify the decryption and encryption of values - * - * @throws NumberFormatException - * @throws SQLException - */ - private void verifyResults() throws NumberFormatException, SQLException { - String sql = "select * from " + numericTable; - pstmt = (SQLServerPreparedStatement) connection.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, - connection.getHoldability(), SQLServerStatementColumnEncryptionSetting.Enabled); - ResultSet rs = null; + private void populateBinarySetObjectWithJDBCType(LinkedList byteValues) throws SQLException { + String sql = "insert into " + binaryTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; - rs = pstmt.executeQuery(); + pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting); - while (rs.next()) { - assertEquals(Short.valueOf(values[0]), rs.getObject(1)); - assertEquals(Short.valueOf(values[0]), rs.getObject(2)); - assertEquals(Short.valueOf(values[0]), rs.getObject(3)); + // binary(20) + for (int i = 1; i <= 3; i++) { + if (null == byteValues) { + pstmt.setObject(i, null, JDBCType.BINARY); + } + else { + pstmt.setObject(i, byteValues.get(0), JDBCType.BINARY); + } + } + + // varbinary(50) + for (int i = 4; i <= 6; i++) { + if (null == byteValues) { + pstmt.setObject(i, null, JDBCType.VARBINARY); + } + else { + pstmt.setObject(i, byteValues.get(1), JDBCType.VARBINARY); + } + } + + // varbinary(max) + for (int i = 7; i <= 9; i++) { + if (null == byteValues) { + pstmt.setObject(i, null, JDBCType.VARBINARY); + } + else { + pstmt.setObject(i, byteValues.get(2), JDBCType.VARBINARY); + } } - if (null != rs) { - rs.close(); + // binary(512) + for (int i = 10; i <= 12; i++) { + if (null == byteValues) { + pstmt.setObject(i, null, JDBCType.BINARY); + } + else { + pstmt.setObject(i, byteValues.get(3), JDBCType.BINARY); + } } - if (null != pstmt) { - pstmt.close(); + + // varbinary(8000) + for (int i = 13; i <= 15; i++) { + if (null == byteValues) { + pstmt.setObject(i, null, JDBCType.VARBINARY); + } + else { + pstmt.setObject(i, byteValues.get(4), JDBCType.VARBINARY); + } } + + pstmt.execute(); + Util.close(null, pstmt, null); } + private void populateBinaryNullCase() throws SQLException { + String sql = "insert into " + binaryTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; + + pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting); + + // binary + for (int i = 1; i <= 3; i++) { + pstmt.setNull(i, java.sql.Types.BINARY); + } + + // varbinary, varbinary(max) + for (int i = 4; i <= 9; i++) { + pstmt.setNull(i, java.sql.Types.VARBINARY); + } + + // binary512 + for (int i = 10; i <= 12; i++) { + pstmt.setNull(i, java.sql.Types.BINARY); + } + + // varbinary(8000) + for (int i = 13; i <= 15; i++) { + pstmt.setNull(i, java.sql.Types.VARBINARY); + } + + pstmt.execute(); + Util.close(null, pstmt, null); + } + + private void populateCharNormalCase(String[] charValues) throws SQLException { + String sql = "insert into " + charTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?" + ")"; + + pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting); + + // char + for (int i = 1; i <= 3; i++) { + pstmt.setString(i, charValues[0]); + } + + // varchar + for (int i = 4; i <= 6; i++) { + pstmt.setString(i, charValues[1]); + } + + // varchar(max) + for (int i = 7; i <= 9; i++) { + pstmt.setString(i, charValues[2]); + } + + // nchar + for (int i = 10; i <= 12; i++) { + pstmt.setNString(i, charValues[3]); + } + + // nvarchar + for (int i = 13; i <= 15; i++) { + pstmt.setNString(i, charValues[4]); + } + + // varchar(max) + for (int i = 16; i <= 18; i++) { + pstmt.setNString(i, charValues[5]); + } + + // uniqueidentifier + for (int i = 19; i <= 21; i++) { + if (null == charValues[6]) { + pstmt.setUniqueIdentifier(i, null); + } + else { + pstmt.setUniqueIdentifier(i, uid); + } + } + + // varchar8000 + for (int i = 22; i <= 24; i++) { + pstmt.setString(i, charValues[7]); + } + + // nvarchar4000 + for (int i = 25; i <= 27; i++) { + pstmt.setNString(i, charValues[8]); + } + + pstmt.execute(); + Util.close(null, pstmt, null); + } + + private void populateCharSetObject(String[] charValues) throws SQLException { + String sql = "insert into " + charTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?" + ")"; + + pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting); + + // char + for (int i = 1; i <= 3; i++) { + pstmt.setObject(i, charValues[0]); + } + + // varchar + for (int i = 4; i <= 6; i++) { + pstmt.setObject(i, charValues[1]); + } + + // varchar(max) + for (int i = 7; i <= 9; i++) { + pstmt.setObject(i, charValues[2], java.sql.Types.LONGVARCHAR); + } + + // nchar + for (int i = 10; i <= 12; i++) { + pstmt.setObject(i, charValues[3], java.sql.Types.NCHAR); + } + + // nvarchar + for (int i = 13; i <= 15; i++) { + pstmt.setObject(i, charValues[4], java.sql.Types.NCHAR); + } + + // nvarchar(max) + for (int i = 16; i <= 18; i++) { + pstmt.setObject(i, charValues[5], java.sql.Types.LONGNVARCHAR); + } + + // uniqueidentifier + for (int i = 19; i <= 21; i++) { + pstmt.setObject(i, charValues[6], microsoft.sql.Types.GUID); + } + + // varchar8000 + for (int i = 22; i <= 24; i++) { + pstmt.setObject(i, charValues[7]); + } + + // nvarchar4000 + for (int i = 25; i <= 27; i++) { + pstmt.setObject(i, charValues[8], java.sql.Types.NCHAR); + } + + pstmt.execute(); + Util.close(null, pstmt, null); + } + + private void populateCharSetObjectWithJDBCTypes(String[] charValues) throws SQLException { + String sql = "insert into " + charTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?" + ")"; + + pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting); + + // char + for (int i = 1; i <= 3; i++) { + pstmt.setObject(i, charValues[0], JDBCType.CHAR); + } + + // varchar + for (int i = 4; i <= 6; i++) { + pstmt.setObject(i, charValues[1], JDBCType.VARCHAR); + } + + // varchar(max) + for (int i = 7; i <= 9; i++) { + pstmt.setObject(i, charValues[2], JDBCType.LONGVARCHAR); + } + + // nchar + for (int i = 10; i <= 12; i++) { + pstmt.setObject(i, charValues[3], JDBCType.NCHAR); + } + + // nvarchar + for (int i = 13; i <= 15; i++) { + pstmt.setObject(i, charValues[4], JDBCType.NVARCHAR); + } + + // nvarchar(max) + for (int i = 16; i <= 18; i++) { + pstmt.setObject(i, charValues[5], JDBCType.LONGNVARCHAR); + } + + // uniqueidentifier + for (int i = 19; i <= 21; i++) { + pstmt.setObject(i, charValues[6], microsoft.sql.Types.GUID); + } + + // varchar8000 + for (int i = 22; i <= 24; i++) { + pstmt.setObject(i, charValues[7], JDBCType.VARCHAR); + } + + // vnarchar4000 + for (int i = 25; i <= 27; i++) { + pstmt.setObject(i, charValues[8], JDBCType.NVARCHAR); + } + + pstmt.execute(); + Util.close(null, pstmt, null); + } + + private void populateCharNullCase() throws SQLException { + String sql = "insert into " + charTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?" + ")"; + + pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting); + + // char + for (int i = 1; i <= 3; i++) { + pstmt.setNull(i, java.sql.Types.CHAR); + } + + // varchar, varchar(max) + for (int i = 4; i <= 9; i++) { + pstmt.setNull(i, java.sql.Types.VARCHAR); + } + + // nchar + for (int i = 10; i <= 12; i++) { + pstmt.setNull(i, java.sql.Types.NCHAR); + } + + // nvarchar, varchar(max) + for (int i = 13; i <= 18; i++) { + pstmt.setNull(i, java.sql.Types.NVARCHAR); + } + + // uniqueidentifier + for (int i = 19; i <= 21; i++) { + pstmt.setNull(i, microsoft.sql.Types.GUID); + + } + + // varchar8000 + for (int i = 22; i <= 24; i++) { + pstmt.setNull(i, java.sql.Types.VARCHAR); + } + + // nvarchar4000 + for (int i = 25; i <= 27; i++) { + pstmt.setNull(i, java.sql.Types.NVARCHAR); + } + + pstmt.execute(); + Util.close(null, pstmt, null); + } + + private void populateDateNormalCase(LinkedList dateValues) throws SQLException { + String sql = "insert into " + dateTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; + + SQLServerPreparedStatement sqlPstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting); + + // date + for (int i = 1; i <= 3; i++) { + sqlPstmt.setDate(i, (Date) dateValues.get(0)); + } + + // datetime2 default + for (int i = 4; i <= 6; i++) { + sqlPstmt.setTimestamp(i, (Timestamp) dateValues.get(1)); + } + + // datetimeoffset default + for (int i = 7; i <= 9; i++) { + sqlPstmt.setDateTimeOffset(i, (DateTimeOffset) dateValues.get(2)); + } + + // time default + for (int i = 10; i <= 12; i++) { + sqlPstmt.setTime(i, (Time) dateValues.get(3)); + } + + // datetime + for (int i = 13; i <= 15; i++) { + sqlPstmt.setDateTime(i, (Timestamp) dateValues.get(4)); + } + + // smalldatetime + for (int i = 16; i <= 18; i++) { + sqlPstmt.setSmallDateTime(i, (Timestamp) dateValues.get(5)); + } + + sqlPstmt.execute(); + Util.close(null, sqlPstmt, null); + } + + private void populateDateSetObject(LinkedList dateValues, + String setter) throws SQLException { + if (setter.equalsIgnoreCase("setwithJDBCType")) { + skipTestForJava7(); + } + + String sql = "insert into " + dateTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; + + SQLServerPreparedStatement sqlPstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting); + + // date + for (int i = 1; i <= 3; i++) { + if (setter.equalsIgnoreCase("setwithJavaType")) + sqlPstmt.setObject(i, (Date) dateValues.get(0), java.sql.Types.DATE); + else if (setter.equalsIgnoreCase("setwithJDBCType")) + sqlPstmt.setObject(i, (Date) dateValues.get(0), JDBCType.DATE); + else + sqlPstmt.setObject(i, (Date) dateValues.get(0)); + } + + // datetime2 default + for (int i = 4; i <= 6; i++) { + if (setter.equalsIgnoreCase("setwithJavaType")) + sqlPstmt.setObject(i, (Timestamp) dateValues.get(1), java.sql.Types.TIMESTAMP); + else if (setter.equalsIgnoreCase("setwithJDBCType")) + sqlPstmt.setObject(i, (Timestamp) dateValues.get(1), JDBCType.TIMESTAMP); + else + sqlPstmt.setObject(i, (Timestamp) dateValues.get(1)); + } + + // datetimeoffset default + for (int i = 7; i <= 9; i++) { + if (setter.equalsIgnoreCase("setwithJavaType")) + sqlPstmt.setObject(i, (DateTimeOffset) dateValues.get(2), microsoft.sql.Types.DATETIMEOFFSET); + else if (setter.equalsIgnoreCase("setwithJDBCType")) + sqlPstmt.setObject(i, (DateTimeOffset) dateValues.get(2), microsoft.sql.Types.DATETIMEOFFSET); + else + sqlPstmt.setObject(i, (DateTimeOffset) dateValues.get(2)); + } + + // time default + for (int i = 10; i <= 12; i++) { + if (setter.equalsIgnoreCase("setwithJavaType")) + sqlPstmt.setObject(i, (Time) dateValues.get(3), java.sql.Types.TIME); + else if (setter.equalsIgnoreCase("setwithJDBCType")) + sqlPstmt.setObject(i, (Time) dateValues.get(3), JDBCType.TIME); + else + sqlPstmt.setObject(i, (Time) dateValues.get(3)); + } + + // datetime + for (int i = 13; i <= 15; i++) { + sqlPstmt.setObject(i, (Timestamp) dateValues.get(4), microsoft.sql.Types.DATETIME); + } + + // smalldatetime + for (int i = 16; i <= 18; i++) { + sqlPstmt.setObject(i, (Timestamp) dateValues.get(5), microsoft.sql.Types.SMALLDATETIME); + } + + sqlPstmt.execute(); + Util.close(null, sqlPstmt, null); + } + + private void populateDateSetObjectNull() throws SQLException { + String sql = "insert into " + dateTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; + + SQLServerPreparedStatement sqlPstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting); + + // date + for (int i = 1; i <= 3; i++) { + sqlPstmt.setObject(i, null, java.sql.Types.DATE); + } + + // datetime2 default + for (int i = 4; i <= 6; i++) { + sqlPstmt.setObject(i, null, java.sql.Types.TIMESTAMP); + } + + // datetimeoffset default + for (int i = 7; i <= 9; i++) { + sqlPstmt.setObject(i, null, microsoft.sql.Types.DATETIMEOFFSET); + } + + // time default + for (int i = 10; i <= 12; i++) { + sqlPstmt.setObject(i, null, java.sql.Types.TIME); + } + + // datetime + for (int i = 13; i <= 15; i++) { + sqlPstmt.setObject(i, null, microsoft.sql.Types.DATETIME); + } + + // smalldatetime + for (int i = 16; i <= 18; i++) { + sqlPstmt.setObject(i, null, microsoft.sql.Types.SMALLDATETIME); + } + + sqlPstmt.execute(); + Util.close(null, sqlPstmt, null); + } + + private void populateDateNullCase() throws SQLException { + String sql = "insert into " + dateTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; + + SQLServerPreparedStatement sqlPstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting); + + // date + for (int i = 1; i <= 3; i++) { + sqlPstmt.setNull(i, java.sql.Types.DATE); + } + + // datetime2 default + for (int i = 4; i <= 6; i++) { + sqlPstmt.setNull(i, java.sql.Types.TIMESTAMP); + } + + // datetimeoffset default + for (int i = 7; i <= 9; i++) { + sqlPstmt.setNull(i, microsoft.sql.Types.DATETIMEOFFSET); + } + + // time default + for (int i = 10; i <= 12; i++) { + sqlPstmt.setNull(i, java.sql.Types.TIME); + } + + // datetime + for (int i = 13; i <= 15; i++) { + sqlPstmt.setNull(i, microsoft.sql.Types.DATETIME); + } + + // smalldatetime + for (int i = 16; i <= 18; i++) { + sqlPstmt.setNull(i, microsoft.sql.Types.SMALLDATETIME); + } + + sqlPstmt.execute(); + Util.close(null, sqlPstmt, null); + } + + /** + * Populating the table + * + * @param values + * @throws SQLException + */ + private void populateNumeric(String[] values) throws SQLException { + String sql = "insert into " + numericTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; + + pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting); + + // bit + for (int i = 1; i <= 3; i++) { + if (values[0].equalsIgnoreCase("true")) { + pstmt.setBoolean(i, true); + } + else { + pstmt.setBoolean(i, false); + } + } + + // tinyint + for (int i = 4; i <= 6; i++) { + pstmt.setShort(i, Short.valueOf(values[1])); + } + + // smallint + for (int i = 7; i <= 9; i++) { + pstmt.setShort(i, Short.valueOf(values[2])); + } + + // int + for (int i = 10; i <= 12; i++) { + pstmt.setInt(i, Integer.valueOf(values[3])); + } + + // bigint + for (int i = 13; i <= 15; i++) { + pstmt.setLong(i, Long.valueOf(values[4])); + } + + // float default + for (int i = 16; i <= 18; i++) { + pstmt.setDouble(i, Double.valueOf(values[5])); + } + + // float(30) + for (int i = 19; i <= 21; i++) { + pstmt.setDouble(i, Double.valueOf(values[6])); + } + + // real + for (int i = 22; i <= 24; i++) { + pstmt.setFloat(i, Float.valueOf(values[7])); + } + + // decimal default + for (int i = 25; i <= 27; i++) { + if (values[8].equalsIgnoreCase("0")) + pstmt.setBigDecimal(i, new BigDecimal(values[8]), 18, 0); + else + pstmt.setBigDecimal(i, new BigDecimal(values[8])); + } + + // decimal(10,5) + for (int i = 28; i <= 30; i++) { + pstmt.setBigDecimal(i, new BigDecimal(values[9]), 10, 5); + } + + // numeric + for (int i = 31; i <= 33; i++) { + if (values[10].equalsIgnoreCase("0")) + pstmt.setBigDecimal(i, new BigDecimal(values[10]), 18, 0); + else + pstmt.setBigDecimal(i, new BigDecimal(values[10])); + } + + // numeric(8,2) + for (int i = 34; i <= 36; i++) { + pstmt.setBigDecimal(i, new BigDecimal(values[11]), 8, 2); + } + + // small money + for (int i = 37; i <= 39; i++) { + pstmt.setSmallMoney(i, new BigDecimal(values[12])); + } + + // money + for (int i = 40; i <= 42; i++) { + pstmt.setMoney(i, new BigDecimal(values[13])); + } + + // decimal(28,4) + for (int i = 43; i <= 45; i++) { + pstmt.setBigDecimal(i, new BigDecimal(values[14]), 28, 4); + } + + // numeric(28,4) + for (int i = 46; i <= 48; i++) { + pstmt.setBigDecimal(i, new BigDecimal(values[15]), 28, 4); + } + + pstmt.execute(); + Util.close(null, pstmt, null); + } + + private void populateNumericSetObject(String[] values) throws SQLException { + String sql = "insert into " + numericTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; + + pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting); + + // bit + for (int i = 1; i <= 3; i++) { + if (values[0].equalsIgnoreCase("true")) { + pstmt.setObject(i, true); + } + else { + pstmt.setObject(i, false); + } + } + + // tinyint + for (int i = 4; i <= 6; i++) { + pstmt.setObject(i, Short.valueOf(values[1])); + } + + // smallint + for (int i = 7; i <= 9; i++) { + pstmt.setObject(i, Short.valueOf(values[2])); + } + + // int + for (int i = 10; i <= 12; i++) { + pstmt.setObject(i, Integer.valueOf(values[3])); + } + + // bigint + for (int i = 13; i <= 15; i++) { + pstmt.setObject(i, Long.valueOf(values[4])); + } + + // float default + for (int i = 16; i <= 18; i++) { + pstmt.setObject(i, Double.valueOf(values[5])); + } + + // float(30) + for (int i = 19; i <= 21; i++) { + pstmt.setObject(i, Double.valueOf(values[6])); + } + + // real + for (int i = 22; i <= 24; i++) { + pstmt.setObject(i, Float.valueOf(values[7])); + } + + // decimal default + for (int i = 25; i <= 27; i++) { + if (RandomData.returnZero) + pstmt.setObject(i, new BigDecimal(values[8]), java.sql.Types.DECIMAL, 18, 0); + else + pstmt.setObject(i, new BigDecimal(values[8])); + } + + // decimal(10,5) + for (int i = 28; i <= 30; i++) { + pstmt.setObject(i, new BigDecimal(values[9]), java.sql.Types.DECIMAL, 10, 5); + } + + // numeric + for (int i = 31; i <= 33; i++) { + if (RandomData.returnZero) + pstmt.setObject(i, new BigDecimal(values[10]), java.sql.Types.NUMERIC, 18, 0); + else + pstmt.setObject(i, new BigDecimal(values[10])); + } + + // numeric(8,2) + for (int i = 34; i <= 36; i++) { + pstmt.setObject(i, new BigDecimal(values[11]), java.sql.Types.NUMERIC, 8, 2); + } + + // small money + for (int i = 37; i <= 39; i++) { + pstmt.setObject(i, new BigDecimal(values[12]), microsoft.sql.Types.SMALLMONEY); + } + + // money + for (int i = 40; i <= 42; i++) { + pstmt.setObject(i, new BigDecimal(values[13]), microsoft.sql.Types.MONEY); + } + + // decimal(28,4) + for (int i = 43; i <= 45; i++) { + pstmt.setObject(i, new BigDecimal(values[14]), java.sql.Types.DECIMAL, 28, 4); + } + + // numeric + for (int i = 46; i <= 48; i++) { + pstmt.setObject(i, new BigDecimal(values[15]), java.sql.Types.NUMERIC, 28, 4); + } + + pstmt.execute(); + Util.close(null, pstmt, null); + } + + private void populateNumericSetObjectWithJDBCTypes(String[] values) throws SQLException { + String sql = "insert into " + numericTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; + + pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting); + + // bit + for (int i = 1; i <= 3; i++) { + if (values[0].equalsIgnoreCase("true")) { + pstmt.setObject(i, true); + } + else { + pstmt.setObject(i, false); + } + } + + // tinyint + for (int i = 4; i <= 6; i++) { + pstmt.setObject(i, Short.valueOf(values[1]), JDBCType.TINYINT); + } + + // smallint + for (int i = 7; i <= 9; i++) { + pstmt.setObject(i, Short.valueOf(values[2]), JDBCType.SMALLINT); + } + + // int + for (int i = 10; i <= 12; i++) { + pstmt.setObject(i, Integer.valueOf(values[3]), JDBCType.INTEGER); + } + + // bigint + for (int i = 13; i <= 15; i++) { + pstmt.setObject(i, Long.valueOf(values[4]), JDBCType.BIGINT); + } + + // float default + for (int i = 16; i <= 18; i++) { + pstmt.setObject(i, Double.valueOf(values[5]), JDBCType.DOUBLE); + } + + // float(30) + for (int i = 19; i <= 21; i++) { + pstmt.setObject(i, Double.valueOf(values[6]), JDBCType.DOUBLE); + } + + // real + for (int i = 22; i <= 24; i++) { + pstmt.setObject(i, Float.valueOf(values[7]), JDBCType.REAL); + } + + // decimal default + for (int i = 25; i <= 27; i++) { + if (RandomData.returnZero) + pstmt.setObject(i, new BigDecimal(values[8]), java.sql.Types.DECIMAL, 18, 0); + else + pstmt.setObject(i, new BigDecimal(values[8])); + } + + // decimal(10,5) + for (int i = 28; i <= 30; i++) { + pstmt.setObject(i, new BigDecimal(values[9]), java.sql.Types.DECIMAL, 10, 5); + } + + // numeric + for (int i = 31; i <= 33; i++) { + if (RandomData.returnZero) + pstmt.setObject(i, new BigDecimal(values[10]), java.sql.Types.NUMERIC, 18, 0); + else + pstmt.setObject(i, new BigDecimal(values[10])); + } + + // numeric(8,2) + for (int i = 34; i <= 36; i++) { + pstmt.setObject(i, new BigDecimal(values[11]), java.sql.Types.NUMERIC, 8, 2); + } + + // small money + for (int i = 37; i <= 39; i++) { + pstmt.setObject(i, new BigDecimal(values[12]), microsoft.sql.Types.SMALLMONEY); + } + + // money + for (int i = 40; i <= 42; i++) { + pstmt.setObject(i, new BigDecimal(values[13]), microsoft.sql.Types.MONEY); + } + + // decimal(28,4) + for (int i = 43; i <= 45; i++) { + pstmt.setObject(i, new BigDecimal(values[14]), java.sql.Types.DECIMAL, 28, 4); + } + + // numeric + for (int i = 46; i <= 48; i++) { + pstmt.setObject(i, new BigDecimal(values[15]), java.sql.Types.NUMERIC, 28, 4); + } + + pstmt.execute(); + Util.close(null, pstmt, null); + } + + private void populateNumericSetObjectNull() throws SQLException { + String sql = "insert into " + numericTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; + + pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting); + + // bit + for (int i = 1; i <= 3; i++) { + pstmt.setObject(i, null, java.sql.Types.BIT); + } + + // tinyint + for (int i = 4; i <= 6; i++) { + pstmt.setObject(i, null, java.sql.Types.TINYINT); + } + + // smallint + for (int i = 7; i <= 9; i++) { + pstmt.setObject(i, null, java.sql.Types.SMALLINT); + } + + // int + for (int i = 10; i <= 12; i++) { + pstmt.setObject(i, null, java.sql.Types.INTEGER); + } + + // bigint + for (int i = 13; i <= 15; i++) { + pstmt.setObject(i, null, java.sql.Types.BIGINT); + } + + // float default + for (int i = 16; i <= 18; i++) { + pstmt.setObject(i, null, java.sql.Types.DOUBLE); + } + + // float(30) + for (int i = 19; i <= 21; i++) { + pstmt.setObject(i, null, java.sql.Types.DOUBLE); + } + + // real + for (int i = 22; i <= 24; i++) { + pstmt.setObject(i, null, java.sql.Types.REAL); + } + + // decimal default + for (int i = 25; i <= 27; i++) { + pstmt.setObject(i, null, java.sql.Types.DECIMAL); + } + + // decimal(10,5) + for (int i = 28; i <= 30; i++) { + pstmt.setObject(i, null, java.sql.Types.DECIMAL, 10, 5); + } + + // numeric + for (int i = 31; i <= 33; i++) { + pstmt.setObject(i, null, java.sql.Types.NUMERIC); + } + + // numeric(8,2) + for (int i = 34; i <= 36; i++) { + pstmt.setObject(i, null, java.sql.Types.NUMERIC, 8, 2); + } + + // small money + for (int i = 37; i <= 39; i++) { + pstmt.setObject(i, null, microsoft.sql.Types.SMALLMONEY); + } + + // money + for (int i = 40; i <= 42; i++) { + pstmt.setObject(i, null, microsoft.sql.Types.MONEY); + } + + // decimal(28,4) + for (int i = 43; i <= 45; i++) { + pstmt.setObject(i, null, java.sql.Types.DECIMAL, 28, 4); + } + + // numeric + for (int i = 46; i <= 48; i++) { + pstmt.setObject(i, null, java.sql.Types.NUMERIC, 28, 4); + } + + pstmt.execute(); + Util.close(null, pstmt, null); + } + + private void populateNumericNullCase(String[] values) throws SQLException { + String sql = "insert into " + numericTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + + + ")"; + + pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting); + + // bit + for (int i = 1; i <= 3; i++) { + pstmt.setNull(i, java.sql.Types.BIT); + } + + // tinyint + for (int i = 4; i <= 6; i++) { + pstmt.setNull(i, java.sql.Types.TINYINT); + } + + // smallint + for (int i = 7; i <= 9; i++) { + pstmt.setNull(i, java.sql.Types.SMALLINT); + } + + // int + for (int i = 10; i <= 12; i++) { + pstmt.setNull(i, java.sql.Types.INTEGER); + } + + // bigint + for (int i = 13; i <= 15; i++) { + pstmt.setNull(i, java.sql.Types.BIGINT); + } + + // float default + for (int i = 16; i <= 18; i++) { + pstmt.setNull(i, java.sql.Types.DOUBLE); + } + + // float(30) + for (int i = 19; i <= 21; i++) { + pstmt.setNull(i, java.sql.Types.DOUBLE); + } + + // real + for (int i = 22; i <= 24; i++) { + pstmt.setNull(i, java.sql.Types.REAL); + } + + // decimal default + for (int i = 25; i <= 27; i++) { + pstmt.setBigDecimal(i, null); + } + + // decimal(10,5) + for (int i = 28; i <= 30; i++) { + pstmt.setBigDecimal(i, null, 10, 5); + } + + // numeric + for (int i = 31; i <= 33; i++) { + pstmt.setBigDecimal(i, null); + } + + // numeric(8,2) + for (int i = 34; i <= 36; i++) { + pstmt.setBigDecimal(i, null, 8, 2); + } + + // small money + for (int i = 37; i <= 39; i++) { + pstmt.setSmallMoney(i, null); + } + + // money + for (int i = 40; i <= 42; i++) { + pstmt.setMoney(i, null); + } + + // decimal(28,4) + for (int i = 43; i <= 45; i++) { + pstmt.setBigDecimal(i, null, 28, 4); + } + + // decimal(28,4) + for (int i = 46; i <= 48; i++) { + pstmt.setBigDecimal(i, null, 28, 4); + } + pstmt.execute(); + Util.close(null, pstmt, null); + } + + private void populateNumericNormalization(String[] numericValues) throws SQLException { + String sql = "insert into " + numericTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + + + ")"; + + pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting); + + // bit + for (int i = 1; i <= 3; i++) { + if (numericValues[0].equalsIgnoreCase("true")) { + pstmt.setBoolean(i, true); + } + else { + pstmt.setBoolean(i, false); + } + } + + // tinyint + for (int i = 4; i <= 6; i++) { + if (1 == Integer.valueOf(numericValues[1])) { + pstmt.setBoolean(i, true); + } + else { + pstmt.setBoolean(i, false); + } + } + + // smallint + for (int i = 7; i <= 9; i++) { + if (numericValues[2].equalsIgnoreCase("255")) { + pstmt.setByte(i, (byte) 255); + } + else { + pstmt.setByte(i, Byte.valueOf(numericValues[2])); + } + } + + // int + for (int i = 10; i <= 12; i++) { + pstmt.setShort(i, Short.valueOf(numericValues[3])); + } + + // bigint + for (int i = 13; i <= 15; i++) { + pstmt.setInt(i, Integer.valueOf(numericValues[4])); + } + + // float default + for (int i = 16; i <= 18; i++) { + pstmt.setDouble(i, Double.valueOf(numericValues[5])); + } + + // float(30) + for (int i = 19; i <= 21; i++) { + pstmt.setDouble(i, Double.valueOf(numericValues[6])); + } + + // real + for (int i = 22; i <= 24; i++) { + pstmt.setFloat(i, Float.valueOf(numericValues[7])); + } + + // decimal default + for (int i = 25; i <= 27; i++) { + pstmt.setBigDecimal(i, new BigDecimal(numericValues[8])); + } + + // decimal(10,5) + for (int i = 28; i <= 30; i++) { + pstmt.setBigDecimal(i, new BigDecimal(numericValues[9]), 10, 5); + } + + // numeric + for (int i = 31; i <= 33; i++) { + pstmt.setBigDecimal(i, new BigDecimal(numericValues[10])); + } + + // numeric(8,2) + for (int i = 34; i <= 36; i++) { + pstmt.setBigDecimal(i, new BigDecimal(numericValues[11]), 8, 2); + } + + // small money + for (int i = 37; i <= 39; i++) { + pstmt.setSmallMoney(i, new BigDecimal(numericValues[12])); + } + + // money + for (int i = 40; i <= 42; i++) { + pstmt.setSmallMoney(i, new BigDecimal(numericValues[13])); + } + + // decimal(28,4) + for (int i = 43; i <= 45; i++) { + pstmt.setBigDecimal(i, new BigDecimal(numericValues[14]), 28, 4); + } + + // numeric + for (int i = 46; i <= 48; i++) { + pstmt.setBigDecimal(i, new BigDecimal(numericValues[15]), 28, 4); + } + + pstmt.execute(); + Util.close(null, pstmt, null); + } + + private void testChar(SQLServerStatement stmt, + String[] values) throws SQLException { + String sql = "select * from " + charTable; + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting); + ResultSet rs = null; + if (stmt == null) { + rs = pstmt.executeQuery(); + } + else { + rs = stmt.executeQuery(sql); + } + int numberOfColumns = rs.getMetaData().getColumnCount(); + + while (rs.next()) { + testGetString(rs, numberOfColumns, values); + testGetObject(rs, numberOfColumns, values); + } + + Util.close(rs, pstmt, null); + } + + private void testBinary(SQLServerStatement stmt, + LinkedList values) throws SQLException { + String sql = "select * from " + binaryTable; + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting); + ResultSet rs = null; + if (stmt == null) { + rs = pstmt.executeQuery(); + } + else { + rs = stmt.executeQuery(sql); + } + int numberOfColumns = rs.getMetaData().getColumnCount(); + + while (rs.next()) { + testGetStringForBinary(rs, numberOfColumns, values); + testGetBytes(rs, numberOfColumns, values); + testGetObjectForBinary(rs, numberOfColumns, values); + } + + Util.close(rs, pstmt, null); + } + + private void testDate(SQLServerStatement stmt, + LinkedList values1) throws SQLException { + + String sql = "select * from " + dateTable; + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting); + ResultSet rs = null; + if (stmt == null) { + rs = pstmt.executeQuery(); + } + else { + rs = stmt.executeQuery(sql); + } + int numberOfColumns = rs.getMetaData().getColumnCount(); + + while (rs.next()) { + // testGetStringForDate(rs, numberOfColumns, values1); //TODO: Disabling, since getString throws verification error for zero temporal + // types + testGetObjectForTemporal(rs, numberOfColumns, values1); + testGetDate(rs, numberOfColumns, values1); + } + + Util.close(rs, pstmt, null); + } + + private void testGetObject(ResultSet rs, + int numberOfColumns, + String[] values) throws SQLException { + int index = 0; + for (int i = 1; i <= numberOfColumns; i = i + 3) { + try { + String objectValue1 = ("" + rs.getObject(i)).trim(); + String objectValue2 = ("" + rs.getObject(i + 1)).trim(); + String objectValue3 = ("" + rs.getObject(i + 2)).trim(); + + boolean matches = objectValue1.equalsIgnoreCase("" + values[index]) && objectValue2.equalsIgnoreCase("" + values[index]) + && objectValue3.equalsIgnoreCase("" + values[index]); + + if (("" + values[index]).length() >= 1000) { + assertTrue(matches, "\nDecryption failed with getObject() at index: " + i + ", " + (i + 1) + ", " + (i + 2) + + ".\nExpected Value at index: " + index); + } + else { + assertTrue(matches, "\nDecryption failed with getObject(): " + objectValue1 + ", " + objectValue2 + ", " + objectValue3 + + ".\nExpected Value: " + values[index]); + } + } + finally { + index++; + } + } + } + + private void testGetObjectForTemporal(ResultSet rs, + int numberOfColumns, + LinkedList values) throws SQLException { + int index = 0; + for (int i = 1; i <= numberOfColumns; i = i + 3) { + try { + String objectValue1 = ("" + rs.getObject(i)).trim(); + String objectValue2 = ("" + rs.getObject(i + 1)).trim(); + String objectValue3 = ("" + rs.getObject(i + 2)).trim(); + + Object expected = null; + if (rs.getMetaData().getColumnTypeName(i).equalsIgnoreCase("smalldatetime")) { + expected = Util.roundSmallDateTimeValue(values.get(index)); + } + else if (rs.getMetaData().getColumnTypeName(i).equalsIgnoreCase("datetime")) { + expected = Util.roundDatetimeValue(values.get(index)); + } + else { + expected = values.get(index); + } + assertTrue( + objectValue1.equalsIgnoreCase("" + expected) && objectValue2.equalsIgnoreCase("" + expected) + && objectValue3.equalsIgnoreCase("" + expected), + "\nDecryption failed with getObject(): " + objectValue1 + ", " + objectValue2 + ", " + objectValue3 + ".\nExpected Value: " + + expected); + } + finally { + index++; + } + } + } + + private void testGetObjectForBinary(ResultSet rs, + int numberOfColumns, + LinkedList values) throws SQLException { + int index = 0; + for (int i = 1; i <= numberOfColumns; i = i + 3) { + byte[] objectValue1 = (byte[]) rs.getObject(i); + byte[] objectValue2 = (byte[]) rs.getObject(i + 1); + byte[] objectValue3 = (byte[]) rs.getObject(i + 2); + + byte[] expectedBytes = null; + + if (null != values.get(index)) { + expectedBytes = values.get(index); + } + + try { + if (null != values.get(index)) { + for (int j = 0; j < expectedBytes.length; j++) { + assertTrue(expectedBytes[j] == objectValue1[j] && expectedBytes[j] == objectValue2[j] && expectedBytes[j] == objectValue3[j], + "Decryption failed with getObject(): " + objectValue1 + ", " + objectValue2 + ", " + objectValue3 + ".\n"); + } + } + } + finally { + index++; + } + } + } + + private void testGetBigDecimal(ResultSet rs, + int numberOfColumns, + String[] values) throws SQLException { + + int index = 0; + for (int i = 1; i <= numberOfColumns; i = i + 3) { + + String decimalValue1 = "" + rs.getBigDecimal(i); + String decimalValue2 = "" + rs.getBigDecimal(i + 1); + String decimalValue3 = "" + rs.getBigDecimal(i + 2); + + if (decimalValue1.equalsIgnoreCase("0") && (values[index].equalsIgnoreCase("true") || values[index].equalsIgnoreCase("false"))) { + decimalValue1 = "false"; + decimalValue2 = "false"; + decimalValue3 = "false"; + } + else if (decimalValue1.equalsIgnoreCase("1") && (values[index].equalsIgnoreCase("true") || values[index].equalsIgnoreCase("false"))) { + decimalValue1 = "true"; + decimalValue2 = "true"; + decimalValue3 = "true"; + } + + if (null != values[index]) { + if (values[index].equalsIgnoreCase("1.79E308")) { + values[index] = "1.79E+308"; + } + else if (values[index].equalsIgnoreCase("3.4E38")) { + values[index] = "3.4E+38"; + } + + if (values[index].equalsIgnoreCase("-1.79E308")) { + values[index] = "-1.79E+308"; + } + else if (values[index].equalsIgnoreCase("-3.4E38")) { + values[index] = "-3.4E+38"; + } + } + + try { + assertTrue( + decimalValue1.equalsIgnoreCase("" + values[index]) && decimalValue2.equalsIgnoreCase("" + values[index]) + && decimalValue3.equalsIgnoreCase("" + values[index]), + "\nDecryption failed with getBigDecimal(): " + decimalValue1 + ", " + decimalValue2 + ", " + decimalValue3 + + ".\nExpected Value: " + values[index]); + } + finally { + index++; + } + } + } + + private void testGetString(ResultSet rs, + int numberOfColumns, + String[] values) throws SQLException { + + int index = 0; + for (int i = 1; i <= numberOfColumns; i = i + 3) { + String stringValue1 = ("" + rs.getString(i)).trim(); + String stringValue2 = ("" + rs.getString(i + 1)).trim(); + String stringValue3 = ("" + rs.getString(i + 2)).trim(); + + if (stringValue1.equalsIgnoreCase("0") && (values[index].equalsIgnoreCase("true") || values[index].equalsIgnoreCase("false"))) { + stringValue1 = "false"; + stringValue2 = "false"; + stringValue3 = "false"; + } + else if (stringValue1.equalsIgnoreCase("1") && (values[index].equalsIgnoreCase("true") || values[index].equalsIgnoreCase("false"))) { + stringValue1 = "true"; + stringValue2 = "true"; + stringValue3 = "true"; + } + try { + + boolean matches = stringValue1.equalsIgnoreCase("" + values[index]) && stringValue2.equalsIgnoreCase("" + values[index]) + && stringValue3.equalsIgnoreCase("" + values[index]); + + if (("" + values[index]).length() >= 1000) { + assertTrue(matches, "\nDecryption failed with getString() at index: " + i + ", " + (i + 1) + ", " + (i + 2) + + ".\nExpected Value at index: " + index); + + } + else { + assertTrue(matches, "\nDecryption failed with getString(): " + stringValue1 + ", " + stringValue2 + ", " + stringValue3 + + ".\nExpected Value: " + values[index]); + } + } + finally { + index++; + } + } + } + + // not testing this for now. + @SuppressWarnings("unused") + private void testGetStringForDate(ResultSet rs, + int numberOfColumns, + LinkedList values) throws SQLException { + + int index = 0; + for (int i = 1; i <= numberOfColumns; i = i + 3) { + String stringValue1 = ("" + rs.getString(i)).trim(); + String stringValue2 = ("" + rs.getString(i + 1)).trim(); + String stringValue3 = ("" + rs.getString(i + 2)).trim(); + + try { + if (index == 3) { + assertTrue( + stringValue1.contains("" + values.get(index)) && stringValue2.contains("" + values.get(index)) + && stringValue3.contains("" + values.get(index)), + "\nDecryption failed with getString(): " + stringValue1 + ", " + stringValue2 + ", " + stringValue3 + + ".\nExpected Value: " + values.get(index)); + } + else if (index == 4) // round value for datetime + { + Object datetimeValue = "" + Util.roundDatetimeValue(values.get(index)); + assertTrue( + stringValue1.equalsIgnoreCase("" + datetimeValue) && stringValue2.equalsIgnoreCase("" + datetimeValue) + && stringValue3.equalsIgnoreCase("" + datetimeValue), + "\nDecryption failed with getString(): " + stringValue1 + ", " + stringValue2 + ", " + stringValue3 + + ".\nExpected Value: " + datetimeValue); + } + else if (index == 5) // round value for smalldatetime + { + Object smalldatetimeValue = "" + Util.roundSmallDateTimeValue(values.get(index)); + assertTrue( + stringValue1.equalsIgnoreCase("" + smalldatetimeValue) && stringValue2.equalsIgnoreCase("" + smalldatetimeValue) + && stringValue3.equalsIgnoreCase("" + smalldatetimeValue), + "\nDecryption failed with getString(): " + stringValue1 + ", " + stringValue2 + ", " + stringValue3 + + ".\nExpected Value: " + smalldatetimeValue); + } + else { + assertTrue( + stringValue1.contains("" + values.get(index)) && stringValue2.contains("" + values.get(index)) + && stringValue3.contains("" + values.get(index)), + "\nDecryption failed with getString(): " + stringValue1 + ", " + stringValue2 + ", " + stringValue3 + + ".\nExpected Value: " + values.get(index)); + } + } + finally { + index++; + } + } + } + + private void testGetBytes(ResultSet rs, + int numberOfColumns, + LinkedList values) throws SQLException { + int index = 0; + for (int i = 1; i <= numberOfColumns; i = i + 3) { + byte[] b1 = rs.getBytes(i); + byte[] b2 = rs.getBytes(i + 1); + byte[] b3 = rs.getBytes(i + 2); + + byte[] expectedBytes = null; + + if (null != values.get(index)) { + expectedBytes = values.get(index); + } + + try { + if (null != values.get(index)) { + for (int j = 0; j < expectedBytes.length; j++) { + assertTrue(expectedBytes[j] == b1[j] && expectedBytes[j] == b2[j] && expectedBytes[j] == b3[j], + "Decryption failed with getObject(): " + b1 + ", " + b2 + ", " + b3 + ".\n"); + } + } + } + finally { + index++; + } + } + } + + private void testGetStringForBinary(ResultSet rs, + int numberOfColumns, + LinkedList values) throws SQLException { + + int index = 0; + for (int i = 1; i <= numberOfColumns; i = i + 3) { + String stringValue1 = ("" + rs.getString(i)).trim(); + String stringValue2 = ("" + rs.getString(i + 1)).trim(); + String stringValue3 = ("" + rs.getString(i + 2)).trim(); + + StringBuffer expected = new StringBuffer(); + String expectedStr = null; + + if (null != values.get(index)) { + for (byte b : values.get(index)) { + expected.append(String.format("%02X", b)); + } + expectedStr = "" + expected.toString(); + } + else { + expectedStr = "null"; + } + + try { + assertTrue(stringValue1.startsWith(expectedStr) && stringValue2.startsWith(expectedStr) && stringValue3.startsWith(expectedStr), + "\nDecryption failed with getString(): " + stringValue1 + ", " + stringValue2 + ", " + stringValue3 + ".\nExpected Value: " + + expectedStr); + } + finally { + index++; + } + } + } + + private void testGetDate(ResultSet rs, + int numberOfColumns, + LinkedList values) throws SQLException { + for (int i = 1; i <= numberOfColumns; i = i + 3) { + + if (rs instanceof SQLServerResultSet) { + + String stringValue1 = null; + String stringValue2 = null; + String stringValue3 = null; + String expected = null; + + switch (i) { + + case 1: + stringValue1 = "" + ((SQLServerResultSet) rs).getDate(i); + stringValue2 = "" + ((SQLServerResultSet) rs).getDate(i + 1); + stringValue3 = "" + ((SQLServerResultSet) rs).getDate(i + 2); + expected = "" + values.get(0); + break; + + case 4: + stringValue1 = "" + ((SQLServerResultSet) rs).getTimestamp(i); + stringValue2 = "" + ((SQLServerResultSet) rs).getTimestamp(i + 1); + stringValue3 = "" + ((SQLServerResultSet) rs).getTimestamp(i + 2); + expected = "" + values.get(1); + break; + + case 7: + stringValue1 = "" + ((SQLServerResultSet) rs).getDateTimeOffset(i); + stringValue2 = "" + ((SQLServerResultSet) rs).getDateTimeOffset(i + 1); + stringValue3 = "" + ((SQLServerResultSet) rs).getDateTimeOffset(i + 2); + expected = "" + values.get(2); + break; + + case 10: + stringValue1 = "" + ((SQLServerResultSet) rs).getTime(i); + stringValue2 = "" + ((SQLServerResultSet) rs).getTime(i + 1); + stringValue3 = "" + ((SQLServerResultSet) rs).getTime(i + 2); + expected = "" + values.get(3); + break; + + case 13: + stringValue1 = "" + ((SQLServerResultSet) rs).getDateTime(i); + stringValue2 = "" + ((SQLServerResultSet) rs).getDateTime(i + 1); + stringValue3 = "" + ((SQLServerResultSet) rs).getDateTime(i + 2); + expected = "" + Util.roundDatetimeValue(values.get(4)); + break; + + case 16: + stringValue1 = "" + ((SQLServerResultSet) rs).getSmallDateTime(i); + stringValue2 = "" + ((SQLServerResultSet) rs).getSmallDateTime(i + 1); + stringValue3 = "" + ((SQLServerResultSet) rs).getSmallDateTime(i + 2); + expected = "" + Util.roundSmallDateTimeValue(values.get(5)); + break; + + default: + fail("Switch case is not matched with data"); + } + + assertTrue( + stringValue1.equalsIgnoreCase(expected) && stringValue2.equalsIgnoreCase(expected) && stringValue3.equalsIgnoreCase(expected), + "\nDecryption failed with testGetDate: " + stringValue1 + ", " + stringValue2 + ", " + stringValue3 + ".\nExpected Value: " + + expected); + } + + else { + fail("Result set is not instance of SQLServerResultSet"); + } + } + } + + private void testNumeric(Statement stmt, + String[] numericValues, + boolean isNull) throws SQLException { + String sql = "select * from " + numericTable; + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting); + SQLServerResultSet rs = null; + if (stmt == null) { + rs = (SQLServerResultSet) pstmt.executeQuery(); + } + else { + rs = (SQLServerResultSet) stmt.executeQuery(sql); + } + int numberOfColumns = rs.getMetaData().getColumnCount(); + + while (rs.next()) { + testGetString(rs, numberOfColumns, numericValues); + testGetObject(rs, numberOfColumns, numericValues); + testGetBigDecimal(rs, numberOfColumns, numericValues); + if (!isNull) + testWithSpecifiedtype(rs, numberOfColumns, numericValues); + else { + String[] nullNumericValues = {"false", "0", "0", "0", "0", "0.0", "0.0", "0.0", null, null, null, null, null, null, null, null}; + testWithSpecifiedtype(rs, numberOfColumns, nullNumericValues); + } + } + + Util.close(rs, pstmt, null); + } + + private void testWithSpecifiedtype(SQLServerResultSet rs, + int numberOfColumns, + String[] values) throws SQLException { + + String value1, value2, value3, expectedValue = null; + int index = 0; + + // bit + value1 = "" + rs.getBoolean(1); + value2 = "" + rs.getBoolean(2); + value3 = "" + rs.getBoolean(3); + + expectedValue = values[index]; + Compare(expectedValue, value1, value2, value3); + index++; + + // tiny + value1 = "" + rs.getShort(4); + value2 = "" + rs.getShort(5); + value3 = "" + rs.getShort(6); + + expectedValue = values[index]; + Compare(expectedValue, value1, value2, value3); + index++; + + // smallint + value1 = "" + rs.getShort(7); + value2 = "" + rs.getShort(8); + value3 = "" + rs.getShort(8); + + expectedValue = values[index]; + Compare(expectedValue, value1, value2, value3); + index++; + + // int + value1 = "" + rs.getInt(10); + value2 = "" + rs.getInt(11); + value3 = "" + rs.getInt(12); + + expectedValue = values[index]; + Compare(expectedValue, value1, value2, value3); + index++; + + // bigint + value1 = "" + rs.getLong(13); + value2 = "" + rs.getLong(14); + value3 = "" + rs.getLong(15); + + expectedValue = values[index]; + Compare(expectedValue, value1, value2, value3); + index++; + + // float + value1 = "" + rs.getDouble(16); + value2 = "" + rs.getDouble(17); + value3 = "" + rs.getDouble(18); + + expectedValue = values[index]; + Compare(expectedValue, value1, value2, value3); + index++; + + // float(30) + value1 = "" + rs.getDouble(19); + value2 = "" + rs.getDouble(20); + value3 = "" + rs.getDouble(21); + + expectedValue = values[index]; + Compare(expectedValue, value1, value2, value3); + index++; + + // real + value1 = "" + rs.getFloat(22); + value2 = "" + rs.getFloat(23); + value3 = "" + rs.getFloat(24); + + expectedValue = values[index]; + Compare(expectedValue, value1, value2, value3); + index++; + + // decimal + value1 = "" + rs.getBigDecimal(25); + value2 = "" + rs.getBigDecimal(26); + value3 = "" + rs.getBigDecimal(27); + + expectedValue = values[index]; + Compare(expectedValue, value1, value2, value3); + index++; + + // decimal (10,5) + value1 = "" + rs.getBigDecimal(28); + value2 = "" + rs.getBigDecimal(29); + value3 = "" + rs.getBigDecimal(30); + + expectedValue = values[index]; + Compare(expectedValue, value1, value2, value3); + index++; + + // numeric + value1 = "" + rs.getBigDecimal(31); + value2 = "" + rs.getBigDecimal(32); + value3 = "" + rs.getBigDecimal(33); + + expectedValue = values[index]; + Compare(expectedValue, value1, value2, value3); + index++; + + // numeric (8,2) + value1 = "" + rs.getBigDecimal(34); + value2 = "" + rs.getBigDecimal(35); + value3 = "" + rs.getBigDecimal(36); + + expectedValue = values[index]; + Compare(expectedValue, value1, value2, value3); + index++; + + // smallmoney + value1 = "" + rs.getSmallMoney(37); + value2 = "" + rs.getSmallMoney(38); + value3 = "" + rs.getSmallMoney(39); + + expectedValue = values[index]; + Compare(expectedValue, value1, value2, value3); + index++; + + // money + value1 = "" + rs.getMoney(40); + value2 = "" + rs.getMoney(41); + value3 = "" + rs.getMoney(42); + + expectedValue = values[index]; + Compare(expectedValue, value1, value2, value3); + index++; + + // decimal(28,4) + value1 = "" + rs.getBigDecimal(43); + value2 = "" + rs.getBigDecimal(44); + value3 = "" + rs.getBigDecimal(45); + + expectedValue = values[index]; + Compare(expectedValue, value1, value2, value3); + index++; + + // numeric(28,4) + value1 = "" + rs.getBigDecimal(46); + value2 = "" + rs.getBigDecimal(47); + value3 = "" + rs.getBigDecimal(48); + + expectedValue = values[index]; + Compare(expectedValue, value1, value2, value3); + index++; + } + + private void Compare(String expectedValue, + String value1, + String value2, + String value3) { + + if (null != expectedValue) { + if (expectedValue.equalsIgnoreCase("1.79E+308")) { + expectedValue = "1.79E308"; + } + else if (expectedValue.equalsIgnoreCase("3.4E+38")) { + expectedValue = "3.4E38"; + } + + if (expectedValue.equalsIgnoreCase("-1.79E+308")) { + expectedValue = "-1.79E308"; + } + else if (expectedValue.equalsIgnoreCase("-3.4E+38")) { + expectedValue = "-3.4E38"; + } + } + + assertTrue( + value1.equalsIgnoreCase("" + expectedValue) && value2.equalsIgnoreCase("" + expectedValue) + && value3.equalsIgnoreCase("" + expectedValue), + "\nDecryption failed with getBigDecimal(): " + value1 + ", " + value2 + ", " + value3 + ".\nExpected Value: " + expectedValue); + } + + private String[] createCharValues() { + + boolean encrypted = true; + String char20 = RandomData.generateCharTypes("20", nullable, encrypted); + String varchar50 = RandomData.generateCharTypes("50", nullable, encrypted); + String varcharmax = RandomData.generateCharTypes("max", nullable, encrypted); + String nchar30 = RandomData.generateNCharTypes("30", nullable, encrypted); + String nvarchar60 = RandomData.generateNCharTypes("60", nullable, encrypted); + String nvarcharmax = RandomData.generateNCharTypes("max", nullable, encrypted); + String varchar8000 = RandomData.generateCharTypes("8000", nullable, encrypted); + String nvarchar4000 = RandomData.generateNCharTypes("4000", nullable, encrypted); + + String[] values = {char20.trim(), varchar50, varcharmax, nchar30, nvarchar60, nvarcharmax, uid, varchar8000, nvarchar4000}; + + return values; + } + + private LinkedList createbinaryValues(boolean nullable) { + + boolean encrypted = true; + RandomData.returnNull = nullable; + + byte[] binary20 = RandomData.generateBinaryTypes("20", nullable, encrypted); + byte[] varbinary50 = RandomData.generateBinaryTypes("50", nullable, encrypted); + byte[] varbinarymax = RandomData.generateBinaryTypes("max", nullable, encrypted); + byte[] binary512 = RandomData.generateBinaryTypes("512", nullable, encrypted); + byte[] varbinary8000 = RandomData.generateBinaryTypes("8000", nullable, encrypted); + + LinkedList list = new LinkedList<>(); + list.add(binary20); + list.add(varbinary50); + list.add(varbinarymax); + list.add(binary512); + list.add(varbinary8000); + + return list; + } + + private String[] createNumericValues() { + + Boolean boolValue = RandomData.generateBoolean(nullable); + Short tinyIntValue = RandomData.generateTinyint(nullable); + Short smallIntValue = RandomData.generateSmallint(nullable); + Integer intValue = RandomData.generateInt(nullable); + Long bigintValue = RandomData.generateLong(nullable); + Double floatValue = RandomData.generateFloat(24, nullable); + Double floatValuewithPrecision = RandomData.generateFloat(53, nullable); + Float realValue = RandomData.generateReal(nullable); + BigDecimal decimal = RandomData.generateDecimalNumeric(18, 0, nullable); + BigDecimal decimalPrecisionScale = RandomData.generateDecimalNumeric(10, 5, nullable); + BigDecimal numeric = RandomData.generateDecimalNumeric(18, 0, nullable); + BigDecimal numericPrecisionScale = RandomData.generateDecimalNumeric(8, 2, nullable); + BigDecimal smallMoney = RandomData.generateSmallMoney(nullable); + BigDecimal money = RandomData.generateMoney(nullable); + BigDecimal decimalPrecisionScale2 = RandomData.generateDecimalNumeric(28, 4, nullable); + BigDecimal numericPrecisionScale2 = RandomData.generateDecimalNumeric(28, 4, nullable); + + String[] numericValues = {"" + boolValue, "" + tinyIntValue, "" + smallIntValue, "" + intValue, "" + bigintValue, "" + floatValue, + "" + floatValuewithPrecision, "" + realValue, "" + decimal, "" + decimalPrecisionScale, "" + numeric, "" + numericPrecisionScale, + "" + smallMoney, "" + money, "" + decimalPrecisionScale2, "" + numericPrecisionScale2}; + + return numericValues; + } + + private LinkedList createTemporalTypes() { + + Date date = RandomData.generateDate(nullable); + Timestamp datetime2 = RandomData.generateDatetime2(7, nullable); + DateTimeOffset datetimeoffset = RandomData.generateDatetimeoffset(7, nullable); + Time time = RandomData.generateTime(7, nullable); + Timestamp datetime = RandomData.generateDatetime(nullable); + Timestamp smalldatetime = RandomData.generateSmalldatetime(nullable); + + LinkedList list = new LinkedList<>(); + list.add(date); + list.add(datetime2); + list.add(datetimeoffset); + list.add(time); + list.add(datetime); + list.add(smalldatetime); + + return list; + } + + private void skipTestForJava7() throws TestAbortedException, SQLException { + assumeTrue(Util.supportJDBC42(con)); // With Java 7, skip tests for JDBCType. + } } diff --git a/src/test/java/com/microsoft/sqlserver/testframework/AbstractTest.java b/src/test/java/com/microsoft/sqlserver/testframework/AbstractTest.java index 595c9fbfc7..e72ab2dc54 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/AbstractTest.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/AbstractTest.java @@ -149,14 +149,14 @@ public static void invokeLogging() { Handler handler = null; String enableLogging = getConfiguredProperty("mssql_jdbc_logging", "false"); - - //If logging is not enable then return. - if(!"true".equalsIgnoreCase(enableLogging)) { + + // If logging is not enable then return. + if (!"true".equalsIgnoreCase(enableLogging)) { return; } String loggingHandler = getConfiguredProperty("mssql_jdbc_logging_handler", "not_configured"); - + try { // handler = new FileHandler("Driver.log"); if ("console".equalsIgnoreCase(loggingHandler)) { diff --git a/src/test/java/com/microsoft/sqlserver/testframework/util/RandomData.java b/src/test/java/com/microsoft/sqlserver/testframework/util/RandomData.java new file mode 100644 index 0000000000..139d3a7529 --- /dev/null +++ b/src/test/java/com/microsoft/sqlserver/testframework/util/RandomData.java @@ -0,0 +1,798 @@ +package com.microsoft.sqlserver.testframework.util; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.sql.Date; +import java.sql.SQLException; +import java.sql.Time; +import java.sql.Timestamp; +import java.util.Calendar; +import java.util.Random; + +import microsoft.sql.DateTimeOffset; + +/** + * Utility class for generating random data for testing + */ +public class RandomData { + + private static Random r = new Random(); + + public static boolean returnNull = (0 == r.nextInt(5)); // 20% chance of return null + public static boolean returnFullLength = (0 == r.nextInt(2)); // 50% chance of return full length for char/nchar and binary types + public static boolean returnMinMax = (0 == r.nextInt(5)); // 20% chance of return Min/Max value + public static boolean returnZero = (0 == r.nextInt(10)); // 10% chance of return zero + + private static String specicalCharSet = "ÀÂÃÄËßîðÐ"; + private static String normalCharSet = "1234567890-=!@#$%^&*()_+qwertyuiop[]\\asdfghjkl;'zxcvbnm,./QWERTYUIOP{}|ASDFGHJKL:\"ZXCVBNM<>?"; + + private static String unicodeCharSet = "♠♣♥♦林花謝了春紅太匆匆無奈朝我附件为放假哇额外放我放问역사적으로본래한민족의영역은만주와연해주의일부를포함하였으나会和太空特工我來寒雨晚來風胭脂淚留人醉幾時重自是人生長恨水長東ྱོགས་སུ་འཁོར་བའི་ས་ཟླུུམ་ཞིག་ལ་ངོས་འཛིན་དགོས་ཏེ།ངག་ཕྱོαβγδεζηθικλμνξοπρστυφχψ太陽系の年齢もまた隕石の年代測定に依拠するので"; + + private static String numberCharSet = "1234567890"; + private static String numberCharSet2 = "123456789"; + + /** + * Utility method for generating a random boolean. + * + * @param nullable + * @return + */ + public static Boolean generateBoolean(boolean nullable) { + if (nullable) { + if (returnNull) { + return null; + } + } + + return r.nextBoolean(); + } + + /** + * Utility method for generating a random int. + * + * @param nullable + * @return + */ + public static Integer generateInt(boolean nullable) { + if (nullable) { + if (returnNull) { + return null; + } + } + + if (returnZero) { + return 0; + } + + if (returnMinMax) { + if (r.nextBoolean()) { + return 2147483647; + } + else { + return -2147483648; + } + } + + // can be either negative or positive + return r.nextInt(); + } + + /** + * Utility method for generating a random long. + * + * @param nullable + * @return + */ + public static Long generateLong(boolean nullable) { + if (nullable) { + if (returnNull) { + return null; + } + } + + if (returnZero) { + return 0L; + } + + if (returnMinMax) { + if (r.nextBoolean()) { + return 9223372036854775807L; + } + else { + return -9223372036854775808L; + } + } + + // can be either negative or positive + return r.nextLong(); + } + + /** + * Utility method for generating a random tinyint. + * + * @param nullable + * @return + */ + public static Short generateTinyint(boolean nullable) { + Integer value = pickInt(nullable, 255, 0); + + if (null != value) { + return value.shortValue(); + } + else { + return null; + } + } + + /** + * Utility method for generating a random short. + * + * @param nullable + * @return + */ + public static Short generateSmallint(boolean nullable) { + Integer value = pickInt(nullable, 32767, -32768); + + if (null != value) { + return value.shortValue(); + } + else { + return null; + } + } + + /** + * Utility method for generating a random BigDecimal. + * + * @param precision + * @param scale + * @param nullable + * @return + */ + public static BigDecimal generateDecimalNumeric(int precision, + int scale, + boolean nullable) { + + if (nullable) { + if (returnNull) { + return null; + } + } + + if (returnZero) { + return BigDecimal.ZERO.setScale(scale); + + } + + if (returnMinMax) { + BigInteger n; + if (r.nextBoolean()) { + n = BigInteger.TEN.pow(precision); + if (scale > 0) + return new BigDecimal(n, scale).subtract(new BigDecimal("" + Math.pow(10, -scale)).setScale(scale, BigDecimal.ROUND_HALF_UP)) + .negate(); + else + return new BigDecimal(n, scale).subtract(new BigDecimal("1")).negate(); + } + else { + n = BigInteger.TEN.pow(precision); + if (scale > 0) + return new BigDecimal(n, scale).subtract(new BigDecimal("" + Math.pow(10, -scale)).setScale(scale, BigDecimal.ROUND_HALF_UP)) + .negate(); + else + return new BigDecimal(n, scale).subtract(new BigDecimal("1")).negate(); + + } + + } + BigInteger n = BigInteger.TEN.pow(precision); + if (r.nextBoolean()) { + return new BigDecimal(newRandomBigInteger(n, r, precision), scale); + } + return (new BigDecimal(newRandomBigInteger(n, r, precision), scale).negate()); + + } + + /** + * Utility method for generating a random float. + * + * @param nullable + * @return + */ + public static Float generateReal(boolean nullable) { + Double doubleValue = generateFloat(24, nullable); + + if (null != doubleValue) { + return doubleValue.floatValue(); + } + else { + return null; + } + } + + /** + * Utility method for generating a random double. + * + * @param n + * integer + * @param nullable + * @return + */ + public static Double generateFloat(Integer n, + boolean nullable) { + if (nullable) { + if (returnNull) { + return null; + } + } + + if (returnZero) { + return new Double(0); + } + + // only 2 options: 24 or 53 + // The default value of n is 53. If 1<=n<=24, n is treated as 24. If 25<=n<=53, n is treated as 53. + // https://msdn.microsoft.com/en-us/library/ms173773.aspx + if (null == n) { + n = 53; + } + else if (25 <= n && 53 >= n) { + n = 53; + } + else { + n = 24; + } + + if (returnMinMax) { + if (53 == n) { + if (r.nextBoolean()) { + if (r.nextBoolean()) { + return Double.valueOf("1.79E+308"); + } + else { + return Double.valueOf("2.23E-308"); + } + } + else { + if (r.nextBoolean()) { + return Double.valueOf("-2.23E-308"); + } + else { + return Double.valueOf("-1.79E+308"); + } + } + } + else { + if (r.nextBoolean()) { + if (r.nextBoolean()) { + return Double.valueOf("3.40E+38"); + } + else { + return Double.valueOf("1.18E-38"); + } + } + else { + if (r.nextBoolean()) { + return Double.valueOf("-1.18E-38"); + } + else { + return Double.valueOf("-3.40E+38"); + } + } + } + } + + String intPart = "" + r.nextInt(10); + + // generate n bits of binary data and convert to long, then use the long as decimal part + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < n; i++) { + sb.append(r.nextInt(2)); + } + long longValue = Long.parseLong(sb.toString(), 2); + String stringValue = intPart + "." + longValue; + + return Double.valueOf(stringValue); + } + + /** + * Utility method for generating a random Money. + * + * @param nullable + * @return + */ + public static BigDecimal generateMoney(boolean nullable) { + String charSet = numberCharSet; + BigDecimal max = new BigDecimal("922337203685477.5807"); + BigDecimal min = new BigDecimal("-922337203685477.5808"); + float multiplier = 10000; + return generateMoneyOrSmallMoney(nullable, max, min, multiplier, charSet); + } + + /** + * Utility method for generating a random SmallMoney. + * + * @param nullable + * @return + */ + public static BigDecimal generateSmallMoney(boolean nullable) { + String charSet = numberCharSet; + BigDecimal max = new BigDecimal("214748.3647"); + BigDecimal min = new BigDecimal("-214748.3648"); + float multiplier = (float) (1.0 / 10000.0); + return generateMoneyOrSmallMoney(nullable, max, min, multiplier, charSet); + } + + /** + * Utility method for generating a random char or Nchar. + * + * @param columnLength + * @param nullable + * @param encrypted + * @return + */ + public static String generateCharTypes(String columnLength, + boolean nullable, + boolean encrypted) { + String charSet = normalCharSet; + + return buildCharOrNChar(columnLength, nullable, encrypted, charSet, 8001); + } + + public static String generateNCharTypes(String columnLength, + boolean nullable, + boolean encrypted) { + String charSet = specicalCharSet + normalCharSet + unicodeCharSet; + + return buildCharOrNChar(columnLength, nullable, encrypted, charSet, 4001); + } + + /** + * Utility method for generating a random binary. + * + * @param columnLength + * @param nullable + * @param encrypted + * @return + */ + public static byte[] generateBinaryTypes(String columnLength, + boolean nullable, + boolean encrypted) { + int maxBound = 8001; + + if (nullable) { + if (returnNull) { + return null; + } + } + + // if column is encrypted, string value cannot be "", not supported. + int minimumLength = 0; + if (encrypted) { + minimumLength = 1; + } + + 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); + if (returnFullLength) { + length = columnLengthInt; + byte[] bytes = new byte[length]; + r.nextBytes(bytes); + return bytes; + } + else { + length = r.nextInt(columnLengthInt - minimumLength) + minimumLength; + byte[] bytes = new byte[length]; + r.nextBytes(bytes); + return bytes; + } + } + } + + /** + * Utility method for generating a random date. + * + * @param nullable + * @return + */ + public static Date generateDate(boolean nullable) { + if (nullable) { + if (returnNull) { + return null; + } + } + + long max = Timestamp.valueOf("9999-12-31 00:00:00.000").getTime(); + long min = Timestamp.valueOf("0001-01-01 00:00:00.000").getTime(); + + if (returnMinMax) { + if (r.nextBoolean()) { + return new Date(max); + } + else { + return new Date(min); + } + } + + while (true) { + long longValue = r.nextLong(); + + if (longValue >= min && longValue <= max) { + return new Date(longValue); + } + } + } + + /** + * Utility method for generating a random timestamp. + * + * @param nullable + * @return + */ + public static Timestamp generateDatetime(boolean nullable) { + long max = Timestamp.valueOf("9999-12-31 23:59:59.997").getTime(); + long min = Timestamp.valueOf("1753-01-01 00:00:00.000").getTime(); + + return generateTimestamp(nullable, max, min); + } + + /** + * Utility method for generating a random datetimeoffset. + * + * @param nullable + * @return + */ + public static DateTimeOffset generateDatetimeoffset(Integer precision, + boolean nullable) { + 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(nullable, 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); + } + + /** + * Utility method for generating a random small datetime. + * + * @param nullable + * @return + */ + public static Timestamp generateSmalldatetime(boolean nullable) { + long max = Timestamp.valueOf("2079-06-06 23:59:00").getTime(); + long min = Timestamp.valueOf("1900-01-01 00:00:00").getTime(); + + return generateTimestamp(nullable, max, min); + } + + /** + * Utility method for generating a random datetime. + * + * @param precision + * @param nullable + * @return + */ + public static Timestamp generateDatetime2(Integer precision, + boolean nullable) { + if (null == precision) { + precision = 7; + } + + long max = Timestamp.valueOf("9999-12-31 23:59:59").getTime(); + long min = Timestamp.valueOf("0001-01-01 00:00:00").getTime(); + + Timestamp ts = generateTimestamp(nullable, max, min); + + if (null == ts) { + return ts; + } + + if (returnMinMax) { + if (ts.getTime() == max) { + int precisionDigits = buildPrecision(precision, "9"); + ts.setNanos(precisionDigits); + return ts; + } + else { + ts.setNanos(0); + return ts; + } + } + + int precisionDigits = buildPrecision(precision, numberCharSet2); // not to use 0 in the random data for now. E.g creates 9040330 and when set + // it is 904033. + ts.setNanos(precisionDigits); + return ts; + } + + /** + * Utility method for generating a random time. + * + * @param precision + * @param nullable + * @return + */ + public static Time generateTime(Integer precision, + boolean nullable) { + if (null == precision) { + precision = 7; + } + + long max = Timestamp.valueOf("9999-12-31 23:59:59").getTime(); + long min = Timestamp.valueOf("0001-01-01 00:00:00").getTime(); + + Timestamp ts = generateTimestamp(nullable, max, min); + + if (null == ts) { + return null; + } + + if (returnMinMax) { + if (ts.getTime() == max) { + int precisionDigits = buildPrecision(precision, "9"); + ts.setNanos(precisionDigits); + return new Time(ts.getTime()); + } + else { + ts.setNanos(0); + return new Time(ts.getTime()); + } + } + + int precisionDigits = buildPrecision(precision, numberCharSet); + ts.setNanos(precisionDigits); + return new Time(ts.getTime()); + } + + private static int buildPrecision(int precision, + String charSet) { + String stringValue = calculatePrecisionDigits(precision, charSet); + return Integer.parseInt(stringValue); + } + + private static String calculatePrecisionDigits(int precision, + String charSet) { + // setNanos(999999900) gives 00:00:00.9999999 + // so, this value has to be 9 digits + 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(boolean nullable, + long max, + long min) { + if (nullable) { + if (returnNull) { + return null; + } + } + + 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 BigDecimal generateMoneyOrSmallMoney(boolean nullable, + BigDecimal max, + BigDecimal min, + float multiplier, + String charSet) { + if (nullable) { + if (returnNull) { + return null; + } + } + + if (returnZero) { + return BigDecimal.ZERO.setScale(4); + } + + if (returnMinMax) { + if (r.nextBoolean()) { + return max; + } + else { + return min; + } + } + + long intPart = (long) (r.nextInt() * multiplier); + + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < 4; i++) { + char c = pickRandomChar(charSet); + sb.append(c); + } + + return new BigDecimal(intPart + "." + sb.toString()); + } + + 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 Integer pickInt(boolean nullable, + int max, + int min) { + if (nullable) { + if (returnNull) { + return null; + } + } + + if (returnZero) { + return 0; + } + + if (returnMinMax) { + if (r.nextBoolean()) { + return max; + } + else { + return min; + } + } + + return (int) r.nextInt(max - min) + min; + } + + private static String buildCharOrNChar(String columnLength, + boolean nullable, + boolean encrypted, + String charSet, + int maxBound) { + + if (nullable) { + if (returnNull) { + return null; + } + } + + // if column is encrypted, string value cannot be "", not supported. + int minimumLength = 0; + if (encrypted) { + minimumLength = 1; + } + + 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); + if (returnFullLength) { + length = columnLengthInt; + return buildRandomString(length, charSet); + } + else { + length = r.nextInt(columnLengthInt - minimumLength) + minimumLength; + 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); + } + + private static BigInteger newRandomBigInteger(BigInteger n, + Random rnd, + int precision) { + BigInteger r; + do { + r = new BigInteger(n.bitLength(), rnd); + } + while (r.toString().length() != precision); + + return r; + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/util/Util.java b/src/test/java/com/microsoft/sqlserver/testframework/util/Util.java new file mode 100644 index 0000000000..f1e5167c4f --- /dev/null +++ b/src/test/java/com/microsoft/sqlserver/testframework/util/Util.java @@ -0,0 +1,292 @@ +package com.microsoft.sqlserver.testframework.util; + +import java.sql.CallableStatement; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Timestamp; +import java.util.Calendar; + +import com.microsoft.sqlserver.jdbc.SQLServerConnection; +import com.microsoft.sqlserver.jdbc.SQLServerDatabaseMetaData; +import com.microsoft.sqlserver.jdbc.SQLServerStatementColumnEncryptionSetting; + +/** + * Utility class for testing + */ +public class Util { + + /** + * Utility method for generating a prepared statement + * + * @param connection + * connection object + * @param sql + * SQL string + * @param stmtColEncSetting + * SQLServerStatementColumnEncryptionSetting object + * @return + */ + public static PreparedStatement getPreparedStmt(Connection connection, + String sql, + SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLException { + if (null == stmtColEncSetting) { + return ((SQLServerConnection) connection).prepareStatement(sql); + } + else { + return ((SQLServerConnection) connection).prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, + connection.getHoldability(), stmtColEncSetting); + } + } + + /** + * Utility method for a statement + * + * @param connection + * connection object + * @param sql + * SQL string + * @param stmtColEncSetting + * SQLServerStatementColumnEncryptionSetting object + * @return + */ + public static Statement getStatement(Connection connection, + SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLException { + // default getStatement assumes resultSet is type_forward_only and concur_read_only + if (null == stmtColEncSetting) { + return ((SQLServerConnection) connection).createStatement(); + } + else { + return ((SQLServerConnection) connection).createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, + connection.getHoldability(), stmtColEncSetting); + } + } + + /** + * Utility method for a scrollable statement + * + * @param connection + * connection object + * @return + */ + public static Statement getScrollableStatement(Connection connection) throws SQLException { + return ((SQLServerConnection) connection).createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); + } + + /** + * Utility method for a scrollable statement + * + * @param connection + * connection object + * @param stmtColEncSetting + * SQLServerStatementColumnEncryptionSetting object + * @return + */ + public static Statement getScrollableStatement(Connection connection, + SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLException { + return ((SQLServerConnection) connection).createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.TYPE_SCROLL_SENSITIVE, + ResultSet.CONCUR_UPDATABLE, stmtColEncSetting); + } + + /** + * Utility method for a statement + * + * @param connection + * connection object + * @param stmtColEncSetting + * SQLServerStatementColumnEncryptionSetting object + * @param rsScrollSensitivity + * @param rsConcurrence + * @return + */ + public static Statement getStatement(Connection connection, + SQLServerStatementColumnEncryptionSetting stmtColEncSetting, + int rsScrollSensitivity, + int rsConcurrence) throws SQLException { + // overloaded getStatement allows setting resultSet type + if (null == stmtColEncSetting) { + return ((SQLServerConnection) connection).createStatement(rsScrollSensitivity, rsConcurrence, connection.getHoldability()); + } + else { + return ((SQLServerConnection) connection).createStatement(rsScrollSensitivity, rsConcurrence, connection.getHoldability(), + stmtColEncSetting); + } + } + + /** + * Utility method for a callable statement + * + * @param connection + * connection object + * @param stmtColEncSetting + * SQLServerStatementColumnEncryptionSetting object + * @param sql + * @return + */ + public static CallableStatement getCallableStmt(Connection connection, + String sql, + SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLException { + if (null == stmtColEncSetting) { + return ((SQLServerConnection) connection).prepareCall(sql); + } + else { + return ((SQLServerConnection) connection).prepareCall(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, + connection.getHoldability(), stmtColEncSetting); + } + } + + /** + * Utility method for a datetime value + * + * @param value + * @return + */ + 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; + } + } + + /** + * Utility method for a datetime value + * + * @param value + * @return + */ + 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; + } + + /** + * Utility function for safely closing open resultset/statement/connection + * + * @param ResultSet + * @param Statement + * @param Connection + */ + public static void close(ResultSet rs, + Statement stmt, + Connection con) { + if (rs != null) { + try { + rs.close(); + + } + catch (SQLException e) { + System.out.println("The result set cannot be closed."); + } + } + if (stmt != null) { + try { + stmt.close(); + } + catch (SQLException e) { + System.out.println("The statement cannot be closed."); + } + } + if (con != null) { + try { + con.close(); + } + catch (SQLException e) { + System.out.println("The data source connection cannot be closed."); + } + } + } + + /** + * Utility function for checking if the system supports JDBC 4.2 + * + * @param con + * @return + */ + public static boolean supportJDBC42(Connection con) throws SQLException { + SQLServerDatabaseMetaData meta = (SQLServerDatabaseMetaData) con.getMetaData(); + return (meta.getJDBCMajorVersion() >= 4 && meta.getJDBCMinorVersion() >= 2); + } +}