From 9106febb173bfbdc277a355ceacfa238f0cdd6f8 Mon Sep 17 00:00:00 2001 From: Cheena Malhotra Date: Tue, 31 Jul 2018 16:07:37 -0700 Subject: [PATCH] Update master post RTW 7.0 release (#766) * Update Snapshot for upcoming RTW release v7.0.0 * Change order of logic for checking the condition for using Bulk Copy API (#736) Fix | Change order of logic for checking the condition for using Bulk Copy API (#736) * Update CHANGELOG.md * Merge pull request #732 from cheenamalhotra/module (Export driver in automatic module) Introduce Automatic Module Name in POM. * Update CHANGELOG.md * Change Sha1HashKey to CityHash128Key for generating PreparedStatement handle and metadata cache keys (#717) * Change Sha1HashKey to CityHash128Key * Formatted code * Prepared statement performance fixes 1) Further speedups to prepared statement hashing 2) Caching of '?' chararacter positiobs in prepared statements to speed parameter substitution * String compare for hash keys added missing line for bulkcopy tests. * comment change * Move CityHash class to a separate file * spacings fixes cleaner code & logic * Add | Adding useBulkCopyForBatchInsert property to Request Boundary methods (#739) * Apply the collation name change to UTF8SupportTest * Package changes for CityHash with license information (#740) * Reformatted Code + Updated formatter (#742) * Reformatted Code + Updated formatter * Fix policheck issue with 'Country' keyword (#745) * Adding a new test for beginRequest()/endRequest() (#746) * Add | Adding a new test to notify the developers to consider beginRequest()/endRequest() when adding a new Connection API * Fix | Fixes for issues reported by static analysis tools (SonarQube + Fortify) (#747) * handle buffer reading for invalid buffer input by user * Revert "handle buffer reading" This reverts commit 11e2bf4212cac9812256ddc143310a00e42a73a4. * updated javadocs (#754) * fixed some typos in javadocs (#760) * API and JavaDoc changes for Spatial Datatypes (#752) Add | API and JavaDoc changes for Spatial Datatypes (#752) * Disallow non-parameterized queries for Bulk Copy API for batch insert (#756) fix | Disallow non-parameterized queries for Bulk Copy API for batch insert (#756) * Formatting | Change scope of unwanted Public APIs + Code Format (#757) * Fix unwanted Public APIs. * Updated formatter to add new line to EOF + formatted project * Release | Release 7.0 changelog and version update (#748) * Updated Changelog + release version changes * Changelog entry updated as per review. * Updated changelog for new changes * Terminology update: request boundary declaration APIs * Trigger Appveyor * Update Samples and add new samples for new features (#761) * Update Samples and add new Samples for new features * Update samples from Peter * Updated JavaDocs * Switch to block comment * Update License copyright (#767) --- CHANGELOG.md | 20 + LICENSE | 6 +- README.md | 9 +- build.gradle | 12 +- mssql-jdbc_formatter.xml | 628 ++--- pom.xml | 16 +- .../java/com/microsoft/sqlserver/jdbc/AE.java | 546 ++-- .../sqlserver/jdbc/ActivityCorrelator.java | 216 +- .../sqlserver/jdbc/AuthenticationJNI.java | 347 ++- .../com/microsoft/sqlserver/jdbc/Column.java | 958 ++++--- .../com/microsoft/sqlserver/jdbc/DDC.java | 299 +- .../sqlserver/jdbc/DLLException.java | 351 ++- .../microsoft/sqlserver/jdbc/DataTypes.java | 1590 ++++------- .../sqlserver/jdbc/FailOverInfo.java | 307 +-- .../sqlserver/jdbc/FailOverMapSingleton.java | 148 +- .../microsoft/sqlserver/jdbc/Geography.java | 340 +-- .../microsoft/sqlserver/jdbc/Geometry.java | 252 +- .../microsoft/sqlserver/jdbc/IOBuffer.java | 2014 +++++++------- .../sqlserver/jdbc/ISQLServerBulkRecord.java | 101 +- .../jdbc/ISQLServerCallableStatement.java | 1114 ++++---- .../sqlserver/jdbc/ISQLServerConnection.java | 322 +-- .../jdbc/ISQLServerConnection43.java | 54 +- .../sqlserver/jdbc/ISQLServerDataRecord.java | 72 +- .../sqlserver/jdbc/ISQLServerDataSource.java | 285 +- .../jdbc/ISQLServerPreparedStatement.java | 784 +++--- .../sqlserver/jdbc/ISQLServerResultSet.java | 1658 +++++------ .../jdbc/ISQLServerResultSetMetaData.java | 16 +- .../sqlserver/jdbc/ISQLServerSavepoint.java | 16 +- .../sqlserver/jdbc/ISQLServerStatement.java | 31 +- .../jdbc/InternalSpatialDatatype.java | 50 +- .../sqlserver/jdbc/JaasConfiguration.java | 143 +- .../sqlserver/jdbc/KerbAuthentication.java | 154 +- .../sqlserver/jdbc/KerbCallback.java | 25 +- .../jdbc/KeyStoreProviderCommon.java | 357 ++- .../sqlserver/jdbc/KeyVaultCredential.java | 33 +- .../sqlserver/jdbc/PLPInputStream.java | 1028 ++++--- .../microsoft/sqlserver/jdbc/Parameter.java | 485 ++-- .../sqlserver/jdbc/ParameterUtils.java | 255 +- .../sqlserver/jdbc/ParsedSQLMetadata.java | 19 +- .../sqlserver/jdbc/ReaderInputStream.java | 538 ++-- .../sqlserver/jdbc/SQLCollation.java | 845 +++--- .../sqlserver/jdbc/SQLJdbcVersion.java | 13 +- .../sqlserver/jdbc/SQLServerADAL4JUtils.java | 56 +- ...QLServerAeadAes256CbcHmac256Algorithm.java | 712 +++-- ...rverAeadAes256CbcHmac256EncryptionKey.java | 234 +- .../SQLServerAeadAes256CbcHmac256Factory.java | 121 +- .../sqlserver/jdbc/SQLServerBlob.java | 86 +- .../jdbc/SQLServerBulkBatchInsertRecord.java | 867 +++--- .../jdbc/SQLServerBulkCSVFileRecord.java | 221 +- .../sqlserver/jdbc/SQLServerBulkCommon.java | 269 +- .../sqlserver/jdbc/SQLServerBulkCopy.java | 1466 +++++----- .../jdbc/SQLServerBulkCopyOptions.java | 590 ++-- .../jdbc/SQLServerCallableStatement.java | 811 +++--- .../sqlserver/jdbc/SQLServerClob.java | 286 +- ...ColumnEncryptionAzureKeyVaultProvider.java | 186 +- ...umnEncryptionCertificateStoreProvider.java | 484 ++-- ...rColumnEncryptionJavaKeyStoreProvider.java | 649 +++-- ...erverColumnEncryptionKeyStoreProvider.java | 134 +- .../sqlserver/jdbc/SQLServerConnection.java | 1903 +++++++------ .../sqlserver/jdbc/SQLServerConnection43.java | 24 +- .../SQLServerConnectionPoolDataSource.java | 27 +- .../jdbc/SQLServerConnectionPoolProxy.java | 105 +- .../sqlserver/jdbc/SQLServerDataColumn.java | 100 +- .../sqlserver/jdbc/SQLServerDataSource.java | 559 ++-- .../SQLServerDataSourceObjectFactory.java | 37 +- .../sqlserver/jdbc/SQLServerDataTable.java | 81 +- .../jdbc/SQLServerDatabaseMetaData.java | 454 ++- .../sqlserver/jdbc/SQLServerDriver.java | 509 ++-- .../jdbc/SQLServerEncryptionAlgorithm.java | 67 +- .../SQLServerEncryptionAlgorithmFactory.java | 64 +- ...LServerEncryptionAlgorithmFactoryList.java | 157 +- .../jdbc/SQLServerEncryptionType.java | 90 +- .../sqlserver/jdbc/SQLServerException.java | 194 +- .../sqlserver/jdbc/SQLServerJdbc43.java | 21 +- ...LServerKeyVaultAuthenticationCallback.java | 25 +- .../sqlserver/jdbc/SQLServerLob.java | 10 +- .../sqlserver/jdbc/SQLServerMetaData.java | 405 +-- .../sqlserver/jdbc/SQLServerNClob.java | 34 +- .../jdbc/SQLServerParameterMetaData.java | 307 +-- .../jdbc/SQLServerPooledConnection.java | 46 +- .../jdbc/SQLServerPreparedStatement.java | 1511 +++++----- .../sqlserver/jdbc/SQLServerResource.java | 896 +++--- .../sqlserver/jdbc/SQLServerResultSet.java | 1377 ++++----- .../jdbc/SQLServerResultSetMetaData.java | 44 +- .../sqlserver/jdbc/SQLServerSQLXML.java | 160 +- .../sqlserver/jdbc/SQLServerSavepoint.java | 31 +- .../jdbc/SQLServerSecurityUtility.java | 390 ++- .../sqlserver/jdbc/SQLServerSortOrder.java | 49 +- .../jdbc/SQLServerSpatialDatatype.java | 905 +++--- .../sqlserver/jdbc/SQLServerStatement.java | 661 ++--- ...erverStatementColumnEncryptionSetting.java | 72 +- .../sqlserver/jdbc/SQLServerSymmetricKey.java | 82 +- .../jdbc/SQLServerSymmetricKeyCache.java | 353 +-- .../sqlserver/jdbc/SQLServerXAConnection.java | 27 +- .../sqlserver/jdbc/SQLServerXADataSource.java | 59 +- .../sqlserver/jdbc/SQLServerXAResource.java | 286 +- .../sqlserver/jdbc/SSPIAuthentication.java | 36 +- .../sqlserver/jdbc/ScrollWindow.java | 414 ++- .../sqlserver/jdbc/SimpleInputStream.java | 733 +++-- .../sqlserver/jdbc/SqlFedAuthToken.java | 20 +- .../microsoft/sqlserver/jdbc/SqlVariant.java | 420 ++- .../sqlserver/jdbc/StreamColInfo.java | 117 +- .../sqlserver/jdbc/StreamColumns.java | 43 +- .../microsoft/sqlserver/jdbc/StreamDone.java | 729 +++-- .../microsoft/sqlserver/jdbc/StreamError.java | 129 +- .../microsoft/sqlserver/jdbc/StreamInfo.java | 43 +- .../sqlserver/jdbc/StreamLoginAck.java | 72 +- .../sqlserver/jdbc/StreamPacket.java | 59 +- .../sqlserver/jdbc/StreamRetStatus.java | 61 +- .../sqlserver/jdbc/StreamRetValue.java | 95 +- .../microsoft/sqlserver/jdbc/StreamSSPI.java | 57 +- .../sqlserver/jdbc/StreamTabName.java | 104 +- .../microsoft/sqlserver/jdbc/StringUtils.java | 134 +- .../com/microsoft/sqlserver/jdbc/TVP.java | 946 ++++--- .../sqlserver/jdbc/ThreePartName.java | 23 +- .../sqlserver/jdbc/UDTTDSHeader.java | 97 +- .../com/microsoft/sqlserver/jdbc/Util.java | 243 +- .../sqlserver/jdbc/XMLTDSHeader.java | 93 +- .../dataclassification/ColumnSensitivity.java | 50 +- .../dataclassification/InformationType.java | 70 +- .../jdbc/dataclassification/Label.java | 70 +- .../SensitivityClassification.java | 111 +- .../SensitivityProperty.java | 72 +- .../jdbc/dns/DNSKerberosLocator.java | 87 +- .../sqlserver/jdbc/dns/DNSRecordSRV.java | 337 ++- .../sqlserver/jdbc/dns/DNSUtilities.java | 137 +- .../com/microsoft/sqlserver/jdbc/dtv.java | 1992 ++++++------- .../microsoft/sqlserver/jdbc/tdsparser.java | 40 +- .../java/microsoft/sql/DateTimeOffset.java | 548 ++-- src/main/java/microsoft/sql/Types.java | 45 +- .../mssql/googlecode/cityhash/CityHash.java | 358 +++ .../java/mssql/googlecode/cityhash/LICENSE | 201 ++ .../java/mssql/googlecode/cityhash/NOTICE | 5 + .../googlecode/cityhash/package-info.java | 18 + src/samples/README.md | 121 +- src/samples/adaptive/pom.xml | 41 +- .../main/java/ExecuteStoredProcedures.java | 151 + .../adaptive/src/main/java/ReadLargeData.java | 122 + .../src/main/java/UpdateLargeData.java | 120 + .../src/main/java/executeStoredProcedure.java | 178 -- .../adaptive/src/main/java/readLargeData.java | 147 - .../src/main/java/updateLargeData.java | 156 -- src/samples/alwaysencrypted/pom.xml | 19 +- .../src/main/java/AlwaysEncrypted.java | 136 +- .../pom.xml | 16 +- .../AzureActiveDirectoryAuthentication.java | 89 +- src/samples/connections/pom.xml | 30 +- .../src/main/java/ConnectDataSource.java | 72 + .../connections/src/main/java/ConnectURL.java | 69 + .../connections/src/main/java/connectDS.java | 97 - .../connections/src/main/java/connectURL.java | 93 - src/samples/constrained/pom.xml | 22 +- ...Sample.java => ConstrainedDelegation.java} | 46 +- src/samples/dataclassification/pom.xml | 58 + .../java/DataDiscoveryAndClassification.java | 185 ++ src/samples/datatypes/pom.xml | 49 +- .../src/main/java/BasicDataTypes.java | 145 + .../src/main/java/SpatialDataTypes.java | 90 + ...sqlxmlExample.java => SqlXmlDataType.java} | 208 +- .../datatypes/src/main/java/basicDT.java | 183 -- src/samples/resultsets/pom.xml | 38 +- .../{cacheRS.java => CacheResultSet.java} | 131 +- ...retrieveRS.java => RetrieveResultSet.java} | 99 +- .../src/main/java/UpdateResultSet.java | 117 + .../resultsets/src/main/java/updateRS.java | 143 - src/samples/sparse/pom.xml | 16 +- .../sparse/src/main/java/SparseColumns.java | 178 +- .../jdbc/AlwaysEncrypted/AESetup.java | 2456 +++++++++-------- .../CallableStatementTest.java | 866 +++--- .../JDBCEncryptionDecryptionTest.java | 365 ++- .../AlwaysEncrypted/PrecisionScaleTest.java | 554 ++-- .../microsoft/sqlserver/jdbc/JDBC43Test.java | 97 +- .../sqlserver/jdbc/TestResource.java | 86 +- .../microsoft/sqlserver/jdbc/UtilTest.java | 8 +- .../jdbc/bulkCopy/BulkCopyAllTypes.java | 68 +- .../jdbc/bulkCopy/BulkCopyCSVTest.java | 180 +- .../bulkCopy/BulkCopyColumnMappingTest.java | 97 +- .../jdbc/bulkCopy/BulkCopyConnectionTest.java | 66 +- .../BulkCopyISQLServerBulkRecordTest.java | 33 +- .../bulkCopy/BulkCopyResultSetCursorTest.java | 237 +- .../jdbc/bulkCopy/BulkCopyTestSetUp.java | 26 +- .../jdbc/bulkCopy/BulkCopyTestUtil.java | 423 ++- .../jdbc/bulkCopy/BulkCopyTestWrapper.java | 328 ++- .../jdbc/bulkCopy/BulkCopyTimeoutTest.java | 19 +- .../ISQLServerBulkRecordIssuesTest.java | 812 +++--- .../jdbc/bulkCopy/SqlTypeMapping.java | 155 +- .../microsoft/sqlserver/jdbc/bvt/bvtTest.java | 161 +- .../sqlserver/jdbc/bvt/bvtTestSetup.java | 85 +- .../CallableStatementTest.java | 38 +- .../jdbc/connection/ConnectionDriverTest.java | 241 +- .../connection/ConnectionWrapper43Test.java | 18 +- .../jdbc/connection/DBMetadataTest.java | 114 +- .../jdbc/connection/DriverVersionTest.java | 32 +- .../connection/NativeMSSQLDataSourceTest.java | 56 +- .../jdbc/connection/PoolingTest.java | 63 +- .../RequestBoundaryMethodsTest.java | 220 +- .../jdbc/connection/SSLProtocolTest.java | 23 +- .../jdbc/connection/TimeoutTest.java | 105 +- .../jdbc/connection/WarningTest.java | 8 +- .../DatabaseMetaDataForeignKeyTest.java | 95 +- .../DatabaseMetaDataTest.java | 167 +- .../datatypes/BulkCopyWithSqlVariantTest.java | 1433 +++++----- .../jdbc/datatypes/DateAndTimeTypeTest.java | 31 +- .../SQLServerSpatialDatatypeTest.java | 1018 ++++--- .../datatypes/SQLVariantResultSetTest.java | 86 +- .../jdbc/datatypes/TVPWithSqlVariantTest.java | 108 +- .../sqlserver/jdbc/dns/DNSRealmsTest.java | 54 +- .../jdbc/exception/ExceptionTest.java | 28 +- .../sqlserver/jdbc/fips/FipsEnvTest.java | 64 +- .../sqlserver/jdbc/fips/FipsTest.java | 57 +- .../ParameterMetaDataTest.java | 19 +- .../ParameterMetaDataWhiteSpaceTest.java | 289 +- .../BatchExecutionWithBulkCopyTest.java | 421 +-- .../BatchExecutionWithNullTest.java | 14 +- .../preparedStatement/RegressionTest.java | 75 +- .../resultset/DataClassificationTest.java | 40 +- .../jdbc/resultset/ResultSetTest.java | 125 +- .../trustmanager/CustomTrustManagerTest.java | 21 +- .../ssl/trustmanager/InvalidTrustManager.java | 21 +- .../trustmanager/PermissiveTrustManager.java | 16 +- .../TrustManagerWithConstructorArg.java | 28 +- .../sqlserver/jdbc/tvp/TVPAllTypes.java | 427 ++- .../sqlserver/jdbc/tvp/TVPIssuesTest.java | 44 +- .../sqlserver/jdbc/tvp/TVPNumericTest.java | 27 +- .../jdbc/tvp/TVPResultSetCursorTest.java | 96 +- .../sqlserver/jdbc/tvp/TVPSchemaTest.java | 31 +- .../sqlserver/jdbc/tvp/TVPTypesTest.java | 1176 ++++---- .../sqlserver/jdbc/unit/TestSavepoint.java | 20 +- .../sqlserver/jdbc/unit/UTF8SupportTest.java | 11 +- .../sqlserver/jdbc/unit/lobs/lobsTest.java | 206 +- .../statement/BatchExecuteWithErrorsTest.java | 211 +- .../unit/statement/BatchExecutionTest.java | 56 +- .../jdbc/unit/statement/BatchTriggerTest.java | 41 +- .../unit/statement/CallableMixedTest.java | 26 +- .../jdbc/unit/statement/LimitEscapeTest.java | 232 +- .../jdbc/unit/statement/MergeTest.java | 24 +- .../statement/NamedParamMultiPartTest.java | 15 +- .../jdbc/unit/statement/PQImpsTest.java | 338 ++- .../jdbc/unit/statement/PoolableTest.java | 35 +- .../unit/statement/PreparedStatementTest.java | 340 ++- .../jdbc/unit/statement/RegressionTest.java | 70 +- .../RegressionTestAlwaysEncrypted.java | 416 +-- .../statement/StatementCancellationTest.java | 23 +- .../jdbc/unit/statement/StatementTest.java | 663 ++--- .../jdbc/unit/statement/WrapperTest.java | 72 +- .../testframework/AbstractParentWrapper.java | 76 +- .../testframework/AbstractSQLGenerator.java | 178 +- .../sqlserver/testframework/AbstractTest.java | 29 +- .../testframework/DBCallableStatement.java | 140 +- .../sqlserver/testframework/DBCoercion.java | 128 +- .../sqlserver/testframework/DBCoercions.java | 56 +- .../sqlserver/testframework/DBColumn.java | 189 +- .../sqlserver/testframework/DBConnection.java | 41 +- .../testframework/DBInvalidUtil.java | 795 +++--- .../sqlserver/testframework/DBItems.java | 78 +- .../testframework/DBPreparedStatement.java | 214 +- .../sqlserver/testframework/DBResultSet.java | 132 +- .../testframework/DBResultSetMetaData.java | 382 ++- .../testframework/DBResultSetTypes.java | 64 +- .../sqlserver/testframework/DBSchema.java | 255 +- .../sqlserver/testframework/DBStatement.java | 21 +- .../sqlserver/testframework/DBTable.java | 78 +- .../sqlserver/testframework/PrepUtil.java | 113 +- .../sqlserver/testframework/Utils.java | 78 +- .../testframework/sqlType/SqlBigInt.java | 52 +- .../testframework/sqlType/SqlBinary.java | 98 +- .../testframework/sqlType/SqlBit.java | 46 +- .../testframework/sqlType/SqlChar.java | 159 +- .../testframework/sqlType/SqlDate.java | 73 +- .../testframework/sqlType/SqlDateTime.java | 35 +- .../testframework/sqlType/SqlDateTime2.java | 25 +- .../sqlType/SqlDateTimeOffset.java | 309 +-- .../testframework/sqlType/SqlDecimal.java | 42 +- .../testframework/sqlType/SqlFloat.java | 81 +- .../testframework/sqlType/SqlInt.java | 50 +- .../testframework/sqlType/SqlMoney.java | 29 +- .../testframework/sqlType/SqlNChar.java | 68 +- .../testframework/sqlType/SqlNVarChar.java | 34 +- .../testframework/sqlType/SqlNVarCharMax.java | 61 +- .../testframework/sqlType/SqlNumber.java | 41 +- .../testframework/sqlType/SqlNumeric.java | 34 +- .../testframework/sqlType/SqlReal.java | 48 +- .../sqlType/SqlSmallDateTime.java | 79 +- .../testframework/sqlType/SqlSmallInt.java | 50 +- .../testframework/sqlType/SqlSmallMoney.java | 30 +- .../testframework/sqlType/SqlTime.java | 24 +- .../testframework/sqlType/SqlTinyInt.java | 48 +- .../testframework/sqlType/SqlType.java | 536 ++-- .../testframework/sqlType/SqlTypeValue.java | 59 +- .../testframework/sqlType/SqlVarBinary.java | 87 +- .../sqlType/SqlVarBinaryMax.java | 51 +- .../testframework/sqlType/SqlVarChar.java | 34 +- .../testframework/sqlType/SqlVarCharMax.java | 52 +- .../sqlType/VariableLengthType.java | 37 +- .../testframework/util/ComparisonUtil.java | 86 +- .../testframework/util/RandomData.java | 177 +- .../testframework/util/RandomUtil.java | 207 +- .../sqlserver/testframework/util/Util.java | 129 +- 298 files changed, 34385 insertions(+), 36408 deletions(-) create mode 100644 src/main/java/mssql/googlecode/cityhash/CityHash.java create mode 100644 src/main/java/mssql/googlecode/cityhash/LICENSE create mode 100644 src/main/java/mssql/googlecode/cityhash/NOTICE create mode 100644 src/main/java/mssql/googlecode/cityhash/package-info.java create mode 100644 src/samples/adaptive/src/main/java/ExecuteStoredProcedures.java create mode 100644 src/samples/adaptive/src/main/java/ReadLargeData.java create mode 100644 src/samples/adaptive/src/main/java/UpdateLargeData.java delete mode 100644 src/samples/adaptive/src/main/java/executeStoredProcedure.java delete mode 100644 src/samples/adaptive/src/main/java/readLargeData.java delete mode 100644 src/samples/adaptive/src/main/java/updateLargeData.java create mode 100644 src/samples/connections/src/main/java/ConnectDataSource.java create mode 100644 src/samples/connections/src/main/java/ConnectURL.java delete mode 100644 src/samples/connections/src/main/java/connectDS.java delete mode 100644 src/samples/connections/src/main/java/connectURL.java rename src/samples/constrained/src/main/java/{ConstrainedSample.java => ConstrainedDelegation.java} (79%) create mode 100644 src/samples/dataclassification/pom.xml create mode 100644 src/samples/dataclassification/src/main/java/DataDiscoveryAndClassification.java create mode 100644 src/samples/datatypes/src/main/java/BasicDataTypes.java create mode 100644 src/samples/datatypes/src/main/java/SpatialDataTypes.java rename src/samples/datatypes/src/main/java/{sqlxmlExample.java => SqlXmlDataType.java} (52%) delete mode 100644 src/samples/datatypes/src/main/java/basicDT.java rename src/samples/resultsets/src/main/java/{cacheRS.java => CacheResultSet.java} (53%) rename src/samples/resultsets/src/main/java/{retrieveRS.java => RetrieveResultSet.java} (52%) create mode 100644 src/samples/resultsets/src/main/java/UpdateResultSet.java delete mode 100644 src/samples/resultsets/src/main/java/updateRS.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 700f4a6e4..ba5de404f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,26 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) +## [7.0.0] Stable Release +### Added +- Added 'Automatic-Module-Name' manifest entry to jre10 Jar, allowing JDK 10 users to access driver module 'com.microsoft.sqlserver.jdbc' [#732](https://github.com/Microsoft/mssql-jdbc/pull/732) +- Added setUseBulkCopyForBatchInsert() to request boundary declaration APIs [#739](https://github.com/Microsoft/mssql-jdbc/pull/739) +- Added new test for validation of supported public APIs in request boundary declaration APIs [#746](https://github.com/Microsoft/mssql-jdbc/pull/746) + +### Fixed Issues +- Fixed policheck issue with 'Country' keyword [#745](https://github.com/Microsoft/mssql-jdbc/pull/745) +- Fixed issues reported by static analysis tools (SonarQube, Fortify) [#747](https://github.com/Microsoft/mssql-jdbc/pull/747) + +### Changed +- Reformatted code and updated mssql-jdbc-formatter [#742](https://github.com/Microsoft/mssql-jdbc/pull/742) +- Changed Sha1HashKey to CityHash128Key for generating PreparedStatement handle and metadata cache keys [#717](https://github.com/Microsoft/mssql-jdbc/pull/717) +- Changed order of logic for checking the condition for using Bulk Copy API [#736](https://github.com/Microsoft/mssql-jdbc/pull/736) +- Changed collation name in UTF8SupportTest [#741](https://github.com/Microsoft/mssql-jdbc/pull/741) +- Changed scope of unwanted Public APIs [#757](https://github.com/Microsoft/mssql-jdbc/pull/757) +- Changed behavior of Bulk Copy API for batch inserts to disallow non-parameterized queries [#756](https://github.com/Microsoft/mssql-jdbc/pull/756) +- Changed APIs and JavaDocs for Spatial Datatypes [#752](https://github.com/Microsoft/mssql-jdbc/pull/752) +- Improved Javadoc comments in driver [#754](https://github.com/Microsoft/mssql-jdbc/pull/754), [#760](https://github.com/Microsoft/mssql-jdbc/pull/760) + ## [6.5.4] Preview Release ### Added - Added new connection property "useBulkCopyForBatchInsert" to enable Bulk Copy API support for batch insert operation [#686](https://github.com/Microsoft/mssql-jdbc/pull/686) diff --git a/LICENSE b/LICENSE index 2be48c8cd..0665a7cee 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright(c) 2017 Microsoft Corporation +Copyright(c) 2018 Microsoft Corporation All rights reserved. MIT License @@ -9,6 +9,6 @@ and / or sell copies of the Software, and to permit persons to whom the Software The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS -IN THE SOFTWARE. \ No newline at end of file +IN THE SOFTWARE. diff --git a/README.md b/README.md index ece0f9277..e0645c259 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ We're now on the Maven Central Repository. Add the following to your POM file to com.microsoft.sqlserver mssql-jdbc - 6.4.0.jre9 + 7.0.0.jre10 ``` The driver can be downloaded from the [Microsoft Download Center](https://go.microsoft.com/fwlink/?linkid=868287). @@ -91,7 +91,8 @@ To get the latest preview version of the driver, add the following to your POM f 6.5.4.jre10-preview ``` - +### Using driver as Java Module +Starting from version 7.0.0, the driver Jars (jre10 and above) will expose 'Automatic-Module' as **'com.microsoft.sqlserver.jdbc'**. The supporting Jar can now be added to ModulePath to access this module. ## Dependencies @@ -118,7 +119,7 @@ Projects that require either of the two features need to explicitly declare the com.microsoft.sqlserver mssql-jdbc - 6.5.4.jre10-preview + 7.0.0.jre10 compile @@ -134,7 +135,7 @@ Projects that require either of the two features need to explicitly declare the com.microsoft.sqlserver mssql-jdbc - 6.5.4.jre10-preview + 7.0.0.jre10 compile diff --git a/build.gradle b/build.gradle index d6955d5c3..876f451c1 100644 --- a/build.gradle +++ b/build.gradle @@ -10,7 +10,7 @@ apply plugin: 'java' -version = '6.5.4' +version = '7.0.0' def jreVersion = "" def testOutputDir = file("build/classes/java/test") def archivesBaseName = 'mssql-jdbc' @@ -29,7 +29,11 @@ if (!hasProperty('buildProfile') || (hasProperty('buildProfile') && buildProfile jreVersion = "jre10" excludedFile = 'com/microsoft/sqlserver/jdbc/SQLServerJdbc42.java' - + jar { + manifest { + attributes 'Automatic-Module-Name': 'com.microsoft.sqlserver.jdbc' + } + } sourceCompatibility = 10 targetCompatibility = 10 } @@ -43,7 +47,7 @@ if((hasProperty('buildProfile') && buildProfile == "build42")) { targetCompatibility = 1.8 } -jar.archiveName = "${archivesBaseName}-${version}.${jreVersion}-preview.jar" +jar.archiveName = "${archivesBaseName}-${version}.${jreVersion}.jar" jar { manifest { attributes 'Title': "Microsoft JDBC Driver ${version} for SQL Server", @@ -78,7 +82,7 @@ repositories { } dependencies { - compile 'com.microsoft.azure:azure-keyvault:1.0.0', + compileOnly 'com.microsoft.azure:azure-keyvault:1.0.0', 'com.microsoft.azure:adal4j:1.6.0' testCompile 'junit:junit:4.12', 'org.junit.platform:junit-platform-console:1.2.0', diff --git a/mssql-jdbc_formatter.xml b/mssql-jdbc_formatter.xml index d043ef249..d6d74d50e 100644 --- a/mssql-jdbc_formatter.xml +++ b/mssql-jdbc_formatter.xml @@ -1,313 +1,315 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pom.xml b/pom.xml index 8546b7cb8..8a03920cf 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.microsoft.sqlserver mssql-jdbc - 6.5.4 + 7.0.0 jar Microsoft JDBC Driver for SQL Server @@ -65,7 +65,6 @@ 4.12 test - org.junit.platform junit-platform-console @@ -132,11 +131,11 @@ build42 - ${project.artifactId}-${project.version}.jre8-preview + ${project.artifactId}-${project.version}.jre8 maven-compiler-plugin - 3.6.0 + 3.7.0 **/com/microsoft/sqlserver/jdbc/SQLServerJdbc43.java @@ -165,11 +164,11 @@ true - ${project.artifactId}-${project.version}.jre10-preview + ${project.artifactId}-${project.version}.jre10 maven-compiler-plugin - 3.6.0 + 3.7.0 **/com/microsoft/sqlserver/jdbc/SQLServerJdbc42.java @@ -185,6 +184,9 @@ ${project.build.outputDirectory}/META-INF/MANIFEST.MF + + com.microsoft.sqlserver.jdbc + @@ -302,7 +304,7 @@ org.apache.maven.plugins maven-surefire-plugin - 2.21.0 + 2.22.0 diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/AE.java b/src/main/java/com/microsoft/sqlserver/jdbc/AE.java index a59a39f98..fd5bc852d 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/AE.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/AE.java @@ -1,280 +1,266 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -import java.util.ArrayList; -import java.util.List; - -/** - * Represents a single encrypted value for a CEK. It contains the encrypted CEK,the store type, name,the key path and encryption algorithm. - */ -class EncryptionKeyInfo { - EncryptionKeyInfo(byte[] encryptedKeyVal, - int dbId, - int keyId, - int keyVersion, - byte[] mdVersion, - String keyPathVal, - String keyStoreNameVal, - String algorithmNameVal) { - encryptedKey = encryptedKeyVal; - databaseId = dbId; - cekId = keyId; - cekVersion = keyVersion; - cekMdVersion = mdVersion; - keyPath = keyPathVal; - keyStoreName = keyStoreNameVal; - algorithmName = algorithmNameVal; - } - - byte[] encryptedKey; // the encrypted "column encryption key" - int databaseId; - int cekId; - int cekVersion; - byte[] cekMdVersion; - String keyPath; - String keyStoreName; - String algorithmName; - byte normalizationRuleVersion; -} - -/** - * Represents a unique CEK as an entry in the CekTable. A unique (plaintext is unique) CEK can have multiple encrypted CEKs when using multiple CMKs. - * These encrypted CEKs are represented by a member ArrayList. - */ -class CekTableEntry { - static final private java.util.logging.Logger aeLogger = java.util.logging.Logger.getLogger("com.microsoft.sqlserver.jdbc.AE"); - - List columnEncryptionKeyValues; - int ordinal; - int databaseId; - int cekId; - int cekVersion; - byte[] cekMdVersion; - - List getColumnEncryptionKeyValues() { - return columnEncryptionKeyValues; - } - - int getOrdinal() { - return ordinal; - } - - int getDatabaseId() { - return databaseId; - } - - int getCekId() { - return cekId; - } - - int getCekVersion() { - return cekVersion; - } - - byte[] getCekMdVersion() { - return cekMdVersion; - } - - CekTableEntry(int ordinalVal) { - ordinal = ordinalVal; - databaseId = 0; - cekId = 0; - cekVersion = 0; - cekMdVersion = null; - columnEncryptionKeyValues = new ArrayList<>(); - } - - int getSize() { - return columnEncryptionKeyValues.size(); - } - - void add(byte[] encryptedKey, - int dbId, - int keyId, - int keyVersion, - byte[] mdVersion, - String keyPath, - String keyStoreName, - String algorithmName) { - - assert null != columnEncryptionKeyValues : "columnEncryptionKeyValues should already be initialized."; - - if (aeLogger.isLoggable(java.util.logging.Level.FINE)) { - aeLogger.fine("Retrieving CEK values"); - } - - EncryptionKeyInfo encryptionKey = new EncryptionKeyInfo(encryptedKey, dbId, keyId, keyVersion, mdVersion, keyPath, keyStoreName, - algorithmName); - columnEncryptionKeyValues.add(encryptionKey); - - if (0 == databaseId) { - databaseId = dbId; - cekId = keyId; - cekVersion = keyVersion; - cekMdVersion = mdVersion; - } - else { - assert (databaseId == dbId); - assert (cekId == keyId); - assert (cekVersion == keyVersion); - assert ((null != cekMdVersion) && (null != mdVersion) && (cekMdVersion.length == mdVersion.length)); - } - } -} - -/** - * Contains all CEKs, each row represents one unique CEK (represented by CekTableEntry). - */ -class CekTable { - CekTableEntry[] keyList; - - CekTable(int tableSize) { - keyList = new CekTableEntry[tableSize]; - } - - int getSize() { - return keyList.length; - } - - CekTableEntry getCekTableEntry(int index) { - return keyList[index]; - } - - void setCekTableEntry(int index, - CekTableEntry entry) { - keyList[index] = entry; - } -} - -/** - * Represents Encryption related information of the cipher data. - */ -class CryptoMetadata -{ - TypeInfo baseTypeInfo; - CekTableEntry cekTableEntry; - byte cipherAlgorithmId; - String cipherAlgorithmName; - SQLServerEncryptionType encryptionType; - byte normalizationRuleVersion; - SQLServerEncryptionAlgorithm cipherAlgorithm = null; - EncryptionKeyInfo encryptionKeyInfo; - short ordinal; - - CekTableEntry getCekTableEntry() { - return cekTableEntry; - } - - void setCekTableEntry(CekTableEntry cekTableEntryObj) { - cekTableEntry = cekTableEntryObj; - } - - TypeInfo getBaseTypeInfo() { - return baseTypeInfo; - } - - void setBaseTypeInfo(TypeInfo baseTypeInfoObj) { - baseTypeInfo = baseTypeInfoObj; - } - - SQLServerEncryptionAlgorithm getEncryptionAlgorithm() { - return cipherAlgorithm; - } - - void setEncryptionAlgorithm(SQLServerEncryptionAlgorithm encryptionAlgorithmObj) { - cipherAlgorithm = encryptionAlgorithmObj; - } - - EncryptionKeyInfo getEncryptionKeyInfo() { - return encryptionKeyInfo; - } - - void setEncryptionKeyInfo(EncryptionKeyInfo encryptionKeyInfoObj) { - encryptionKeyInfo = encryptionKeyInfoObj; - } - - byte getEncryptionAlgorithmId() { - return cipherAlgorithmId; - } - - String getEncryptionAlgorithmName() { - return cipherAlgorithmName; - } - - SQLServerEncryptionType getEncryptionType() { - return encryptionType; - } - - byte getNormalizationRuleVersion() { - return normalizationRuleVersion; - } - - short getOrdinal() { - return ordinal; - } - - CryptoMetadata(CekTableEntry cekTableEntryObj, - short ordinalVal, - byte cipherAlgorithmIdVal, - String cipherAlgorithmNameVal, - byte encryptionTypeVal, - byte normalizationRuleVersionVal) throws SQLServerException - { - cekTableEntry = cekTableEntryObj; - ordinal = ordinalVal; - cipherAlgorithmId = cipherAlgorithmIdVal; - cipherAlgorithmName = cipherAlgorithmNameVal; - encryptionType = SQLServerEncryptionType.of(encryptionTypeVal); - normalizationRuleVersion = normalizationRuleVersionVal; - encryptionKeyInfo = null; - } - - boolean IsAlgorithmInitialized() { - return null != cipherAlgorithm; - } -} - -// Fields in the first resultset of "sp_describe_parameter_encryption" -// We expect the server to return the fields in the resultset in the same order as mentioned below. -// If the server changes the below order, then transparent parameter encryption will break. -enum DescribeParameterEncryptionResultSet1 { - KeyOrdinal, - DbId, - KeyId, - KeyVersion, - KeyMdVersion, - EncryptedKey, - ProviderName, - KeyPath, - KeyEncryptionAlgorithm; - - int value() { - // Column indexing starts from 1; - return ordinal() + 1; - } -} - -// Fields in the second resultset of "sp_describe_parameter_encryption" -// We expect the server to return the fields in the resultset in the same order as mentioned below. -// If the server changes the below order, then transparent parameter encryption will break. -enum DescribeParameterEncryptionResultSet2 { - ParameterOrdinal, - ParameterName, - ColumnEncryptionAlgorithm, - ColumnEncrytionType, - ColumnEncryptionKeyOrdinal, - NormalizationRuleVersion; - - int value() { - // Column indexing starts from 1; - return ordinal() + 1; - } - -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +import java.util.ArrayList; +import java.util.List; + + +/** + * Represents a single encrypted value for a CEK. It contains the encrypted CEK,the store type, name,the key path and + * encryption algorithm. + */ +class EncryptionKeyInfo { + EncryptionKeyInfo(byte[] encryptedKeyVal, int dbId, int keyId, int keyVersion, byte[] mdVersion, String keyPathVal, + String keyStoreNameVal, String algorithmNameVal) { + encryptedKey = encryptedKeyVal; + databaseId = dbId; + cekId = keyId; + cekVersion = keyVersion; + cekMdVersion = mdVersion; + keyPath = keyPathVal; + keyStoreName = keyStoreNameVal; + algorithmName = algorithmNameVal; + } + + byte[] encryptedKey; // the encrypted "column encryption key" + int databaseId; + int cekId; + int cekVersion; + byte[] cekMdVersion; + String keyPath; + String keyStoreName; + String algorithmName; + byte normalizationRuleVersion; +} + + +/** + * Represents a unique CEK as an entry in the CekTable. A unique (plaintext is unique) CEK can have multiple encrypted + * CEKs when using multiple CMKs. These encrypted CEKs are represented by a member ArrayList. + */ +class CekTableEntry { + static final private java.util.logging.Logger aeLogger = java.util.logging.Logger + .getLogger("com.microsoft.sqlserver.jdbc.AE"); + + List columnEncryptionKeyValues; + int ordinal; + int databaseId; + int cekId; + int cekVersion; + byte[] cekMdVersion; + + List getColumnEncryptionKeyValues() { + return columnEncryptionKeyValues; + } + + int getOrdinal() { + return ordinal; + } + + int getDatabaseId() { + return databaseId; + } + + int getCekId() { + return cekId; + } + + int getCekVersion() { + return cekVersion; + } + + byte[] getCekMdVersion() { + return cekMdVersion; + } + + CekTableEntry(int ordinalVal) { + ordinal = ordinalVal; + databaseId = 0; + cekId = 0; + cekVersion = 0; + cekMdVersion = null; + columnEncryptionKeyValues = new ArrayList<>(); + } + + int getSize() { + return columnEncryptionKeyValues.size(); + } + + void add(byte[] encryptedKey, int dbId, int keyId, int keyVersion, byte[] mdVersion, String keyPath, + String keyStoreName, String algorithmName) { + + assert null != columnEncryptionKeyValues : "columnEncryptionKeyValues should already be initialized."; + + if (aeLogger.isLoggable(java.util.logging.Level.FINE)) { + aeLogger.fine("Retrieving CEK values"); + } + + EncryptionKeyInfo encryptionKey = new EncryptionKeyInfo(encryptedKey, dbId, keyId, keyVersion, mdVersion, + keyPath, keyStoreName, algorithmName); + columnEncryptionKeyValues.add(encryptionKey); + + if (0 == databaseId) { + databaseId = dbId; + cekId = keyId; + cekVersion = keyVersion; + cekMdVersion = mdVersion; + } else { + assert (databaseId == dbId); + assert (cekId == keyId); + assert (cekVersion == keyVersion); + assert ((null != cekMdVersion) && (null != mdVersion) && (cekMdVersion.length == mdVersion.length)); + } + } +} + + +/** + * Contains all CEKs, each row represents one unique CEK (represented by CekTableEntry). + */ +class CekTable { + CekTableEntry[] keyList; + + CekTable(int tableSize) { + keyList = new CekTableEntry[tableSize]; + } + + int getSize() { + return keyList.length; + } + + CekTableEntry getCekTableEntry(int index) { + return keyList[index]; + } + + void setCekTableEntry(int index, CekTableEntry entry) { + keyList[index] = entry; + } +} + + +/** + * Represents Encryption related information of the cipher data. + */ +class CryptoMetadata { + TypeInfo baseTypeInfo; + CekTableEntry cekTableEntry; + byte cipherAlgorithmId; + String cipherAlgorithmName; + SQLServerEncryptionType encryptionType; + byte normalizationRuleVersion; + SQLServerEncryptionAlgorithm cipherAlgorithm = null; + EncryptionKeyInfo encryptionKeyInfo; + short ordinal; + + CekTableEntry getCekTableEntry() { + return cekTableEntry; + } + + void setCekTableEntry(CekTableEntry cekTableEntryObj) { + cekTableEntry = cekTableEntryObj; + } + + TypeInfo getBaseTypeInfo() { + return baseTypeInfo; + } + + void setBaseTypeInfo(TypeInfo baseTypeInfoObj) { + baseTypeInfo = baseTypeInfoObj; + } + + SQLServerEncryptionAlgorithm getEncryptionAlgorithm() { + return cipherAlgorithm; + } + + void setEncryptionAlgorithm(SQLServerEncryptionAlgorithm encryptionAlgorithmObj) { + cipherAlgorithm = encryptionAlgorithmObj; + } + + EncryptionKeyInfo getEncryptionKeyInfo() { + return encryptionKeyInfo; + } + + void setEncryptionKeyInfo(EncryptionKeyInfo encryptionKeyInfoObj) { + encryptionKeyInfo = encryptionKeyInfoObj; + } + + byte getEncryptionAlgorithmId() { + return cipherAlgorithmId; + } + + String getEncryptionAlgorithmName() { + return cipherAlgorithmName; + } + + SQLServerEncryptionType getEncryptionType() { + return encryptionType; + } + + byte getNormalizationRuleVersion() { + return normalizationRuleVersion; + } + + short getOrdinal() { + return ordinal; + } + + CryptoMetadata(CekTableEntry cekTableEntryObj, short ordinalVal, byte cipherAlgorithmIdVal, + String cipherAlgorithmNameVal, byte encryptionTypeVal, + byte normalizationRuleVersionVal) throws SQLServerException { + cekTableEntry = cekTableEntryObj; + ordinal = ordinalVal; + cipherAlgorithmId = cipherAlgorithmIdVal; + cipherAlgorithmName = cipherAlgorithmNameVal; + encryptionType = SQLServerEncryptionType.of(encryptionTypeVal); + normalizationRuleVersion = normalizationRuleVersionVal; + encryptionKeyInfo = null; + } + + boolean IsAlgorithmInitialized() { + return null != cipherAlgorithm; + } +} + + +// Fields in the first resultset of "sp_describe_parameter_encryption" +// We expect the server to return the fields in the resultset in the same order as mentioned below. +// If the server changes the below order, then transparent parameter encryption will break. +enum DescribeParameterEncryptionResultSet1 { + KeyOrdinal, + DbId, + KeyId, + KeyVersion, + KeyMdVersion, + EncryptedKey, + ProviderName, + KeyPath, + KeyEncryptionAlgorithm; + + int value() { + // Column indexing starts from 1; + return ordinal() + 1; + } +} + + +// Fields in the second resultset of "sp_describe_parameter_encryption" +// We expect the server to return the fields in the resultset in the same order as mentioned below. +// If the server changes the below order, then transparent parameter encryption will break. +enum DescribeParameterEncryptionResultSet2 { + ParameterOrdinal, + ParameterName, + ColumnEncryptionAlgorithm, + ColumnEncrytionType, + ColumnEncryptionKeyOrdinal, + NormalizationRuleVersion; + + int value() { + // Column indexing starts from 1; + return ordinal() + 1; + } + +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ActivityCorrelator.java b/src/main/java/com/microsoft/sqlserver/jdbc/ActivityCorrelator.java index a036b5be6..cd008e54d 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ActivityCorrelator.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ActivityCorrelator.java @@ -1,109 +1,107 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; - -/** - * ActivityCorrelator provides the APIs to access the ActivityId in TLS - */ -final class ActivityCorrelator { - - private static Map ActivityIdTlsMap = new ConcurrentHashMap(); - - static void cleanupActivityId() { - //remove the ActivityId that belongs to this thread. - long uniqueThreadId = Thread.currentThread().getId(); - - if (ActivityIdTlsMap.containsKey(uniqueThreadId)) { - ActivityIdTlsMap.remove(uniqueThreadId); - } - } - - // Get the current ActivityId in TLS - static ActivityId getCurrent() { - // get the value in TLS, not reference - long uniqueThreadId = Thread.currentThread().getId(); - - //Since the Id for each thread is unique, this assures that the below if statement is run only once per thread. - if (!ActivityIdTlsMap.containsKey(uniqueThreadId)) { - ActivityIdTlsMap.put(uniqueThreadId, new ActivityId()); - } - - return ActivityIdTlsMap.get(uniqueThreadId); - } - - // Increment the Sequence number of the ActivityId in TLS - // and return the ActivityId with new Sequence number - static ActivityId getNext() { - // Get the current ActivityId in TLS - ActivityId activityId = getCurrent(); - - // Increment the Sequence number - activityId.Increment(); - - return activityId; - } - - static void setCurrentActivityIdSentFlag() { - ActivityId activityId = getCurrent(); - activityId.setSentFlag(); - } -} - -class ActivityId { - private final UUID Id; - private long Sequence; - private boolean isSentToServer; - - ActivityId() { - Id = UUID.randomUUID(); - Sequence = 0; - isSentToServer = false; - } - - UUID getId() { - return Id; - } - - long getSequence() { - return Sequence; - } - - void Increment() { - if (Sequence < 0xffffffffl) // to get to 32-bit unsigned - { - ++Sequence; - } - else { - Sequence = 0; - } - - isSentToServer = false; - } - - void setSentFlag() { - isSentToServer = true; - } - - boolean IsSentToServer() { - return isSentToServer; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append(Id.toString()); - sb.append("-"); - sb.append(Sequence); - return sb.toString(); - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + + +/** + * ActivityCorrelator provides the APIs to access the ActivityId in TLS + */ +final class ActivityCorrelator { + + private static Map ActivityIdTlsMap = new ConcurrentHashMap(); + + static void cleanupActivityId() { + // remove the ActivityId that belongs to this thread. + long uniqueThreadId = Thread.currentThread().getId(); + + if (ActivityIdTlsMap.containsKey(uniqueThreadId)) { + ActivityIdTlsMap.remove(uniqueThreadId); + } + } + + // Get the current ActivityId in TLS + static ActivityId getCurrent() { + // get the value in TLS, not reference + long uniqueThreadId = Thread.currentThread().getId(); + + // Since the Id for each thread is unique, this assures that the below if statement is run only once per thread. + if (!ActivityIdTlsMap.containsKey(uniqueThreadId)) { + ActivityIdTlsMap.put(uniqueThreadId, new ActivityId()); + } + + return ActivityIdTlsMap.get(uniqueThreadId); + } + + // Increment the Sequence number of the ActivityId in TLS + // and return the ActivityId with new Sequence number + static ActivityId getNext() { + // Get the current ActivityId in TLS + ActivityId activityId = getCurrent(); + + // Increment the Sequence number + activityId.Increment(); + + return activityId; + } + + static void setCurrentActivityIdSentFlag() { + ActivityId activityId = getCurrent(); + activityId.setSentFlag(); + } +} + + +class ActivityId { + private final UUID Id; + private long Sequence; + private boolean isSentToServer; + + ActivityId() { + Id = UUID.randomUUID(); + Sequence = 0; + isSentToServer = false; + } + + UUID getId() { + return Id; + } + + long getSequence() { + return Sequence; + } + + void Increment() { + if (Sequence < 0xffffffffl) // to get to 32-bit unsigned + { + ++Sequence; + } else { + Sequence = 0; + } + + isSentToServer = false; + } + + void setSentFlag() { + isSentToServer = true; + } + + boolean IsSentToServer() { + return isSentToServer; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(Id.toString()); + sb.append("-"); + sb.append(Sequence); + return sb.toString(); + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/AuthenticationJNI.java b/src/main/java/com/microsoft/sqlserver/jdbc/AuthenticationJNI.java index 112aac152..0364a3a78 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/AuthenticationJNI.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/AuthenticationJNI.java @@ -1,186 +1,161 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -import java.util.logging.Level; - -class FedAuthDllInfo { - byte[] accessTokenBytes = null; - long expiresIn = 0; - - FedAuthDllInfo(byte[] accessTokenBytes, - long expiresIn) { - this.accessTokenBytes = accessTokenBytes; - this.expiresIn = expiresIn; - } -} - -/** - * Encapsulation of the JNI native calls for trusted authentication. - */ -final class AuthenticationJNI extends SSPIAuthentication { - private final static int maximumpointersize = 128; // we keep the SNI_Sec pointer - private static boolean enabled = false; - private static java.util.logging.Logger authLogger = java.util.logging.Logger - .getLogger("com.microsoft.sqlserver.jdbc.internals.AuthenticationJNI"); - private static int sspiBlobMaxlen = 0; - private byte[] sniSec = new byte[maximumpointersize]; - private int sniSecLen[] = {0}; - private final String DNSName; - private final int port; - private SQLServerConnection con; - - private static final UnsatisfiedLinkError linkError; - - static int GetMaxSSPIBlobSize() { - return sspiBlobMaxlen; - } - - static boolean isDllLoaded() { - return enabled; - } - - static { - UnsatisfiedLinkError temp = null; - // Load the DLL - try { - String libName = "sqljdbc_auth"; - System.loadLibrary(libName); - int[] pkg = new int[1]; - pkg[0] = 0; - if (0 == SNISecInitPackage(pkg, authLogger)) { - sspiBlobMaxlen = pkg[0]; - } - else - throw new UnsatisfiedLinkError(); - enabled = true; - } - catch (UnsatisfiedLinkError e) { - temp = e; - authLogger.warning("Failed to load the sqljdbc_auth.dll cause : " + e.getMessage()); - // This is not re-thrown on purpose - the constructor will terminate the properly with the appropriate error string - } - finally { - linkError = temp; - } - - } - - AuthenticationJNI(SQLServerConnection con, - String address, - int serverport) throws SQLServerException { - if (!enabled) - con.terminate(SQLServerException.DRIVER_ERROR_NONE, SQLServerException.getErrString("R_notConfiguredForIntegrated"), linkError); - - this.con = con; - DNSName = GetDNSName(address); - port = serverport; - } - - static FedAuthDllInfo getAccessTokenForWindowsIntegrated(String stsURL, - String servicePrincipalName, - String clientConnectionId, - String clientId, - long expirationFileTime) throws DLLException { - FedAuthDllInfo dllInfo = ADALGetAccessTokenForWindowsIntegrated(stsURL, servicePrincipalName, clientConnectionId, clientId, - expirationFileTime, authLogger); - return dllInfo; - } - - // InitDNSName should be called to initialize the DNSName before calling this function - byte[] GenerateClientContext(byte[] pin, - boolean[] done) throws SQLServerException { - byte[] pOut; - int[] outsize; // This is where the size of the filled data returned - outsize = new int[1]; - outsize[0] = GetMaxSSPIBlobSize(); - pOut = new byte[outsize[0]]; - - // assert DNSName cant be null - assert DNSName != null; - - int failure = SNISecGenClientContext(sniSec, sniSecLen, pin, pin.length, pOut, outsize, done, DNSName, port, null, null, authLogger); - - if (failure != 0) { - if (authLogger.isLoggable(Level.WARNING)) { - authLogger.warning(toString() + " Authentication failed code : " + failure); - } - con.terminate(SQLServerException.DRIVER_ERROR_NONE, SQLServerException.getErrString("R_integratedAuthenticationFailed"), linkError); - } - // allocate space based on the size returned - byte output[] = new byte[outsize[0]]; - System.arraycopy(pOut, 0, output, 0, outsize[0]); - return output; - } - - /* L0 */ int ReleaseClientContext() { - int success = 0; - if (sniSecLen[0] > 0) { - success = SNISecReleaseClientContext(sniSec, sniSecLen[0], authLogger); - sniSecLen[0] = 0; - } - return success; - } - - // note we handle the failures of the GetDNSName in this function, this function will return an empty string if the underlying call fails. - private static String GetDNSName(String address) { - String DNS[] = new String[1]; - if (GetDNSName(address, DNS, authLogger) != 0) { - // Simply initialize the DNS to address - DNS[0] = address; - } - return DNS[0]; - } - - // we use arrays of size one in many places to retrieve output values - // Java Integer objects are immutable so we cant use them to get the output sizes. - // Same for String - /* L0 */private native static int SNISecGenClientContext(byte[] psec, - int[] secptrsize, - byte[] pin, - int insize, - byte[] pOut, - int[] outsize, - boolean[] done, - String servername, - int port, - String username, - String password, - java.util.logging.Logger log); - - /* L0 */ private native static int SNISecReleaseClientContext(byte[] psec, - int secptrsize, - java.util.logging.Logger log); - - private native static int SNISecInitPackage(int[] pcbMaxToken, - java.util.logging.Logger log); - - private native static int SNISecTerminatePackage(java.util.logging.Logger log); - - private native static int SNIGetSID(byte[] SID, - java.util.logging.Logger log); - - private native static boolean SNIIsEqualToCurrentSID(byte[] SID, - java.util.logging.Logger log); - - private native static int GetDNSName(String address, - String[] DNSName, - java.util.logging.Logger log); - - private native static FedAuthDllInfo ADALGetAccessTokenForWindowsIntegrated(String stsURL, - String servicePrincipalName, - String clientConnectionId, - String clientId, - long expirationFileTime, - java.util.logging.Logger log); - - native static byte[] DecryptColumnEncryptionKey(String masterKeyPath, - String encryptionAlgorithm, - byte[] encryptedColumnEncryptionKey) throws DLLException; -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +import java.util.logging.Level; + + +class FedAuthDllInfo { + byte[] accessTokenBytes = null; + long expiresIn = 0; + + FedAuthDllInfo(byte[] accessTokenBytes, long expiresIn) { + this.accessTokenBytes = accessTokenBytes; + this.expiresIn = expiresIn; + } +} + + +/** + * Encapsulation of the JNI native calls for trusted authentication. + */ +final class AuthenticationJNI extends SSPIAuthentication { + private final static int maximumpointersize = 128; // we keep the SNI_Sec pointer + private static boolean enabled = false; + private static java.util.logging.Logger authLogger = java.util.logging.Logger + .getLogger("com.microsoft.sqlserver.jdbc.internals.AuthenticationJNI"); + private static int sspiBlobMaxlen = 0; + private byte[] sniSec = new byte[maximumpointersize]; + private int sniSecLen[] = {0}; + private final String DNSName; + private final int port; + private SQLServerConnection con; + + private static final UnsatisfiedLinkError linkError; + + static int GetMaxSSPIBlobSize() { + return sspiBlobMaxlen; + } + + static boolean isDllLoaded() { + return enabled; + } + + static { + UnsatisfiedLinkError temp = null; + // Load the DLL + try { + String libName = "sqljdbc_auth"; + System.loadLibrary(libName); + int[] pkg = new int[1]; + pkg[0] = 0; + if (0 == SNISecInitPackage(pkg, authLogger)) { + sspiBlobMaxlen = pkg[0]; + } else + throw new UnsatisfiedLinkError(); + enabled = true; + } catch (UnsatisfiedLinkError e) { + temp = e; + authLogger.warning("Failed to load the sqljdbc_auth.dll cause : " + e.getMessage()); + // This is not re-thrown on purpose - the constructor will terminate the properly with the appropriate error + // string + } finally { + linkError = temp; + } + + } + + AuthenticationJNI(SQLServerConnection con, String address, int serverport) throws SQLServerException { + if (!enabled) + con.terminate(SQLServerException.DRIVER_ERROR_NONE, + SQLServerException.getErrString("R_notConfiguredForIntegrated"), linkError); + + this.con = con; + DNSName = GetDNSName(address); + port = serverport; + } + + static FedAuthDllInfo getAccessTokenForWindowsIntegrated(String stsURL, String servicePrincipalName, + String clientConnectionId, String clientId, long expirationFileTime) throws DLLException { + FedAuthDllInfo dllInfo = ADALGetAccessTokenForWindowsIntegrated(stsURL, servicePrincipalName, + clientConnectionId, clientId, expirationFileTime, authLogger); + return dllInfo; + } + + // InitDNSName should be called to initialize the DNSName before calling this function + byte[] GenerateClientContext(byte[] pin, boolean[] done) throws SQLServerException { + byte[] pOut; + int[] outsize; // This is where the size of the filled data returned + outsize = new int[1]; + outsize[0] = GetMaxSSPIBlobSize(); + pOut = new byte[outsize[0]]; + + // assert DNSName cant be null + assert DNSName != null; + + int failure = SNISecGenClientContext(sniSec, sniSecLen, pin, pin.length, pOut, outsize, done, DNSName, port, + null, null, authLogger); + + if (failure != 0) { + if (authLogger.isLoggable(Level.WARNING)) { + authLogger.warning(toString() + " Authentication failed code : " + failure); + } + con.terminate(SQLServerException.DRIVER_ERROR_NONE, + SQLServerException.getErrString("R_integratedAuthenticationFailed"), linkError); + } + // allocate space based on the size returned + byte output[] = new byte[outsize[0]]; + System.arraycopy(pOut, 0, output, 0, outsize[0]); + return output; + } + + /* L0 */ int ReleaseClientContext() { + int success = 0; + if (sniSecLen[0] > 0) { + success = SNISecReleaseClientContext(sniSec, sniSecLen[0], authLogger); + sniSecLen[0] = 0; + } + return success; + } + + // note we handle the failures of the GetDNSName in this function, this function will return an empty string if the + // underlying call fails. + private static String GetDNSName(String address) { + String DNS[] = new String[1]; + if (GetDNSName(address, DNS, authLogger) != 0) { + // Simply initialize the DNS to address + DNS[0] = address; + } + return DNS[0]; + } + + // we use arrays of size one in many places to retrieve output values + // Java Integer objects are immutable so we cant use them to get the output sizes. + // Same for String + /* L0 */private native static int SNISecGenClientContext(byte[] psec, int[] secptrsize, byte[] pin, int insize, + byte[] pOut, int[] outsize, boolean[] done, String servername, int port, String username, String password, + java.util.logging.Logger log); + + /* L0 */ private native static int SNISecReleaseClientContext(byte[] psec, int secptrsize, + java.util.logging.Logger log); + + private native static int SNISecInitPackage(int[] pcbMaxToken, java.util.logging.Logger log); + + private native static int SNISecTerminatePackage(java.util.logging.Logger log); + + private native static int SNIGetSID(byte[] SID, java.util.logging.Logger log); + + private native static boolean SNIIsEqualToCurrentSID(byte[] SID, java.util.logging.Logger log); + + private native static int GetDNSName(String address, String[] DNSName, java.util.logging.Logger log); + + private native static FedAuthDllInfo ADALGetAccessTokenForWindowsIntegrated(String stsURL, + String servicePrincipalName, String clientConnectionId, String clientId, long expirationFileTime, + java.util.logging.Logger log); + + native static byte[] DecryptColumnEncryptionKey(String masterKeyPath, String encryptionAlgorithm, + byte[] encryptedColumnEncryptionKey) throws DLLException; +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/Column.java b/src/main/java/com/microsoft/sqlserver/jdbc/Column.java index d6d8017bf..20453b2b7 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/Column.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/Column.java @@ -1,483 +1,475 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -import java.text.MessageFormat; -import java.util.Calendar; - -/** - * Column represents a database column definition (meta data) within a result set. - */ - -final class Column { - private TypeInfo typeInfo; - private CryptoMetadata cryptoMetadata; - private SqlVariant internalVariant; - - final void setInternalVariant(SqlVariant type){ - this.internalVariant = type; - } - - final SqlVariant getInternalVariant(){ - return this.internalVariant; - } - - final TypeInfo getTypeInfo() { - return typeInfo; - } - - private DTV updaterDTV; - private final DTV getterDTV = new DTV(); - - // updated if sendStringParametersAsUnicode=true for setNString, setNCharacterStream, and setNClob methods - private JDBCType jdbcTypeSetByUser = null; - - // set length of value for variable length type (String) - private int valueLength = 0; - - // The column name, which may be an alias, that is used with value setters and getters. - private String columnName; - - final void setColumnName(String name) { - columnName = name; - } - - final String getColumnName() { - return columnName; - } - - // The base column name which is the actual column name in an underlying table. - // This name must be used, rather than the column name above, when inserting or - // updating rows in the table. - private String baseColumnName; - - final void setBaseColumnName(String name) { - baseColumnName = name; - } - - final String getBaseColumnName() { - return baseColumnName; - } - - private int tableNum; - - final void setTableNum(int num) { - tableNum = num; - } - - final int getTableNum() { - return tableNum; - } - - private int infoStatus; - - final void setInfoStatus(int status) { - infoStatus = status; - } - - final boolean hasDifferentName() { - return 0 != (infoStatus & TDS.COLINFO_STATUS_DIFFERENT_NAME); - } - - final boolean isHidden() { - return 0 != (infoStatus & TDS.COLINFO_STATUS_HIDDEN); - } - - final boolean isKey() { - return 0 != (infoStatus & TDS.COLINFO_STATUS_KEY); - } - - final boolean isExpression() { - return 0 != (infoStatus & TDS.COLINFO_STATUS_EXPRESSION); - } - - final boolean isUpdatable() { - return !isExpression() && !isHidden() && tableName.getObjectName().length() > 0; - } - - private SQLIdentifier tableName; - - final void setTableName(SQLIdentifier name) { - tableName = name; - } - - final SQLIdentifier getTableName() { - return tableName; - } - - ColumnFilter filter; - - /** - * Create a new column - * - * @param typeInfo - * the column TYPE_INFO - * @param columnName - * the column name - * @param tableName - * the column's table name - * @param cryptoMeta - * the column's crypto metadata - */ - Column(TypeInfo typeInfo, - String columnName, - SQLIdentifier tableName, - CryptoMetadata cryptoMeta) { - this.typeInfo = typeInfo; - this.columnName = columnName; - this.baseColumnName = columnName; - this.tableName = tableName; - this.cryptoMetadata = cryptoMeta; - } - - CryptoMetadata getCryptoMetadata() { - return cryptoMetadata; - } - - /** - * Clears the values associated with this column. - */ - final void clear() { - getterDTV.clear(); - } - - /** - * Skip this column. - * - * The column's value may or may not already be marked. If this column's value has not yet been marked, this function assumes that the value is - * located at the current position in the response. - */ - final void skipValue(TDSReader tdsReader, - boolean isDiscard) throws SQLServerException { - getterDTV.skipValue(typeInfo, tdsReader, isDiscard); - } - - /** - * Sets Null value on the getterDTV of a column - */ - final void initFromCompressedNull() { - getterDTV.initFromCompressedNull(); - } - - void setFilter(ColumnFilter filter) { - this.filter = filter; - } - - /** - * Returns whether the value of this column is SQL NULL. - * - * If the column has not yet been read from the response then this method returns false. - */ - final boolean isNull() { - return getterDTV.isNull(); - } - - /** - * Returns true if the column value is initialized to some value by reading the stream from server i.e. it returns true, if impl of getterDTV is - * not set to null - */ - final boolean isInitialized() { - return getterDTV.isInitialized(); - } - - /** - * Retrieves this colum's value. - * - * If the column has not yet been read from the response then this method reads it. - */ - Object getValue(JDBCType jdbcType, - InputStreamGetterArgs getterArgs, - Calendar cal, - TDSReader tdsReader) throws SQLServerException { - Object value = getterDTV.getValue(jdbcType, typeInfo.getScale(), getterArgs, cal, typeInfo, cryptoMetadata, tdsReader); - setInternalVariant(getterDTV.getInternalVariant()); - return (null != filter) ? filter.apply(value, jdbcType) : value; - } - - int getInt(TDSReader tdsReader) throws SQLServerException { - return (Integer) getValue(JDBCType.INTEGER, null, null, tdsReader); - } - - void updateValue(JDBCType jdbcType, - Object value, - JavaType javaType, - StreamSetterArgs streamSetterArgs, - Calendar cal, - Integer scale, - SQLServerConnection con, - SQLServerStatementColumnEncryptionSetting stmtColumnEncriptionSetting, - Integer precision, - boolean forceEncrypt, - int parameterIndex) throws SQLServerException { - SSType ssType = typeInfo.getSSType(); - - if (null != cryptoMetadata) { - if (SSType.VARBINARYMAX == cryptoMetadata.baseTypeInfo.getSSType() && JDBCType.BINARY == jdbcType) { - jdbcType = cryptoMetadata.baseTypeInfo.getSSType().getJDBCType(); - } - - if (null != value) { - // for encrypted tinyint, we need to convert short value to byte value, otherwise it would be sent as smallint - if (JDBCType.TINYINT == cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType() && javaType == JavaType.SHORT) { - if (value instanceof Boolean) { - if (true == ((boolean) value)) { - value = 1; - } - else { - value = 0; - } - } - String stringValue = "" + value; - Short shortValue = Short.valueOf(stringValue); - - if (shortValue >= 0 && shortValue <= 255) { - value = shortValue.byteValue(); - javaType = JavaType.BYTE; - jdbcType = JDBCType.TINYINT; - } - } - } - // if the column is encrypted and value is null, get the real column type instead of binary types - else if (jdbcType.isBinary()) { - jdbcType = cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType(); - } - } - - if (null == scale && null != cryptoMetadata) { - scale = cryptoMetadata.getBaseTypeInfo().getScale(); - } - - // if jdbcType is char or varchar, check if the column is actually char/varchar or nchar/nvarchar - // in order to make updateString() work with encrypted Nchar typpes - if (null != cryptoMetadata && (JDBCType.CHAR == jdbcType || JDBCType.VARCHAR == jdbcType)) { - if (JDBCType.NVARCHAR == cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType() - || JDBCType.NCHAR == cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType() - || JDBCType.LONGNVARCHAR == cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType()) { - jdbcType = cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType(); - } - } - - if (Util.shouldHonorAEForParameters(stmtColumnEncriptionSetting, con)) { - if ((null == cryptoMetadata) && true == forceEncrypt) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_ForceEncryptionTrue_HonorAETrue_UnencryptedColumnRS")); - Object[] msgArgs = {parameterIndex}; - - throw new SQLServerException(null, form.format(msgArgs), null, 0, false); - } - else { - setJdbcTypeSetByUser(jdbcType); - - this.valueLength = Util.getValueLengthBaseOnJavaType(value, javaType, precision, scale, jdbcType); - - // for update encrypted nchar or nvarchar value on result set, must double the value length, - // otherwise, the data is truncated. - if (null != cryptoMetadata) { - if (JDBCType.NCHAR == cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType() - || JDBCType.NVARCHAR == cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType() - || JDBCType.LONGNVARCHAR == cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType()) { - this.valueLength = valueLength * 2; - } - } - } - } - else { - if (true == forceEncrypt) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_ForceEncryptionTrue_HonorAEFalseRS")); - Object[] msgArgs = {parameterIndex}; - - throw new SQLServerException(null, form.format(msgArgs), null, 0, false); - } - } - - if (null != streamSetterArgs) { - if (!streamSetterArgs.streamType.convertsTo(typeInfo)) - DataTypes.throwConversionError(streamSetterArgs.streamType.toString(), ssType.toString()); - } - else { - if (null != cryptoMetadata) { - // For GUID, set the JDBCType before checking for conversion - if ((JDBCType.UNKNOWN == jdbcType) && (value instanceof java.util.UUID)) { - javaType = JavaType.STRING; - jdbcType = JDBCType.GUID; - setJdbcTypeSetByUser(jdbcType); - } - - SSType basicSSType = cryptoMetadata.baseTypeInfo.getSSType(); - if (!jdbcType.convertsTo(basicSSType)) - DataTypes.throwConversionError(jdbcType.toString(), ssType.toString()); - - JDBCType jdbcTypeFromSSType = getJDBCTypeFromBaseSSType(basicSSType, jdbcType); - - if (jdbcTypeFromSSType != jdbcType) { - setJdbcTypeSetByUser(jdbcTypeFromSSType); - jdbcType = jdbcTypeFromSSType; - this.valueLength = Util.getValueLengthBaseOnJavaType(value, javaType, precision, scale, jdbcType); - } - } - else { - if (!jdbcType.convertsTo(ssType)) - DataTypes.throwConversionError(jdbcType.toString(), ssType.toString()); - } - } - - // DateTimeOffset is not supported with SQL Server versions earlier than Katmai - if ((JDBCType.DATETIMEOFFSET == jdbcType || JavaType.DATETIMEOFFSET == javaType) && !con.isKatmaiOrLater()) { - throw new SQLServerException(SQLServerException.getErrString("R_notSupported"), SQLState.DATA_EXCEPTION_NOT_SPECIFIC, DriverError.NOT_SET, - null); - } - - // sendStringParametersAsUnicode - // If set to true, this connection property tells the driver to send textual parameters - // to the server as Unicode rather than MBCS. This is accomplished here by re-tagging - // the value with the appropriate corresponding Unicode type. - if ((null != cryptoMetadata) && (con.sendStringParametersAsUnicode()) - && (JavaType.STRING == javaType || JavaType.READER == javaType || JavaType.CLOB == javaType || JavaType.OBJECT == javaType)) { - jdbcType = getSSPAUJDBCType(jdbcType); - } - - // Cheesy checks determine whether updating is allowed, but do not determine HOW to do - // the update (i.e. what JDBC type to use for the update). The JDBC type to use depends - // on the SQL Server type of the column and the JDBC type requested. - // - // In most cases the JDBCType to use is just the requested JDBCType. But in some cases - // a client side type conversion is necessary because SQL Server does not directly support - // conversion from the requested JDBCType to the column SSType, or the driver needs to - // provide special data conversion. - - // Update of Unicode SSType from textual JDBCType: Use Unicode. - if ((SSType.NCHAR == ssType || SSType.NVARCHAR == ssType || SSType.NVARCHARMAX == ssType || SSType.NTEXT == ssType || SSType.XML == ssType) && - - (JDBCType.CHAR == jdbcType || JDBCType.VARCHAR == jdbcType || JDBCType.LONGVARCHAR == jdbcType || JDBCType.CLOB == jdbcType)) { - jdbcType = (JDBCType.CLOB == jdbcType) ? JDBCType.NCLOB : JDBCType.NVARCHAR; - } - - // Update of binary SSType from textual JDBCType: Convert hex to binary. - else if ((SSType.BINARY == ssType || SSType.VARBINARY == ssType || SSType.VARBINARYMAX == ssType || SSType.IMAGE == ssType - || SSType.UDT == ssType) && - - (JDBCType.CHAR == jdbcType || JDBCType.VARCHAR == jdbcType || JDBCType.LONGVARCHAR == jdbcType)) { - jdbcType = JDBCType.VARBINARY; - } - - // Update of textual SSType from temporal JDBCType requires - // client-side conversion from temporal to textual. - else if ((JDBCType.TIMESTAMP == jdbcType || JDBCType.DATE == jdbcType || JDBCType.TIME == jdbcType || JDBCType.DATETIMEOFFSET == jdbcType) && - - (SSType.CHAR == ssType || SSType.VARCHAR == ssType || SSType.VARCHARMAX == ssType || SSType.TEXT == ssType || SSType.NCHAR == ssType - || SSType.NVARCHAR == ssType || SSType.NVARCHARMAX == ssType || SSType.NTEXT == ssType)) { - jdbcType = JDBCType.NCHAR; - } - - // Lazily create the updater DTV on first update of the column - if (null == updaterDTV) - updaterDTV = new DTV(); - - // Set the column's value - - updaterDTV.setValue(typeInfo.getSQLCollation(), jdbcType, value, javaType, streamSetterArgs, cal, scale, con, false); - } - - /** - * Used when sendStringParametersAsUnicode=true to derive the appropriate National Character Set JDBC type corresponding to the specified JDBC - * type. - */ - private static JDBCType getSSPAUJDBCType(JDBCType jdbcType) { - switch (jdbcType) { - case CHAR: - return JDBCType.NCHAR; - case VARCHAR: - return JDBCType.NVARCHAR; - case LONGVARCHAR: - return JDBCType.LONGNVARCHAR; - case CLOB: - return JDBCType.NCLOB; - default: - return jdbcType; - } - } - - private static JDBCType getJDBCTypeFromBaseSSType(SSType basicSSType, - JDBCType jdbcType) { - switch (jdbcType) { - case TIMESTAMP: - if (SSType.DATETIME == basicSSType) - return JDBCType.DATETIME; - else if (SSType.SMALLDATETIME == basicSSType) - return JDBCType.SMALLDATETIME; - return jdbcType; - - case NUMERIC: - case DECIMAL: - if (SSType.MONEY == basicSSType) - return JDBCType.MONEY; - if (SSType.SMALLMONEY == basicSSType) - return JDBCType.SMALLMONEY; - return jdbcType; - - case CHAR: - if (SSType.GUID == basicSSType) - return JDBCType.GUID; - if (SSType.VARCHARMAX == basicSSType) - return JDBCType.LONGVARCHAR; - return jdbcType; - - default: - return jdbcType; - } - } - - boolean hasUpdates() { - return null != updaterDTV; - } - - void cancelUpdates() { - updaterDTV = null; - } - - void sendByRPC(TDSWriter tdsWriter, - SQLServerConnection conn) throws SQLServerException { - // If the column has had no updates then there is nothing to send - if (null == updaterDTV) - return; - try { - // this is for updateRow() stuff - updaterDTV.sendCryptoMetaData(cryptoMetadata, tdsWriter); - updaterDTV.jdbcTypeSetByUser(getJdbcTypeSetByUser(), getValueLength()); - - // Otherwise, send the updated value via RPC - updaterDTV.sendByRPC(baseColumnName, typeInfo, - null != cryptoMetadata ? cryptoMetadata.getBaseTypeInfo().getSQLCollation() : typeInfo.getSQLCollation(), - null != cryptoMetadata ? cryptoMetadata.getBaseTypeInfo().getPrecision() : typeInfo.getPrecision(), - null != cryptoMetadata ? cryptoMetadata.getBaseTypeInfo().getScale() : typeInfo.getScale(), false, // isOutParameter (always false - // for column updates) - tdsWriter, conn); - } - finally { - // this is for updateRow() stuff - updaterDTV.sendCryptoMetaData(null, tdsWriter); - } - } - - JDBCType getJdbcTypeSetByUser() { - return jdbcTypeSetByUser; - } - - void setJdbcTypeSetByUser(JDBCType jdbcTypeSetByUser) { - this.jdbcTypeSetByUser = jdbcTypeSetByUser; - } - - int getValueLength() { - return valueLength; - } -} - -abstract class ColumnFilter { - abstract Object apply(Object value, - JDBCType jdbcType) throws SQLServerException; -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +import java.text.MessageFormat; +import java.util.Calendar; + + +/** + * Column represents a database column definition (meta data) within a result set. + */ + +final class Column { + private TypeInfo typeInfo; + private CryptoMetadata cryptoMetadata; + private SqlVariant internalVariant; + + final void setInternalVariant(SqlVariant type) { + this.internalVariant = type; + } + + final SqlVariant getInternalVariant() { + return this.internalVariant; + } + + final TypeInfo getTypeInfo() { + return typeInfo; + } + + private DTV updaterDTV; + private final DTV getterDTV = new DTV(); + + // updated if sendStringParametersAsUnicode=true for setNString, setNCharacterStream, and setNClob methods + private JDBCType jdbcTypeSetByUser = null; + + // set length of value for variable length type (String) + private int valueLength = 0; + + // The column name, which may be an alias, that is used with value setters and getters. + private String columnName; + + final void setColumnName(String name) { + columnName = name; + } + + final String getColumnName() { + return columnName; + } + + // The base column name which is the actual column name in an underlying table. + // This name must be used, rather than the column name above, when inserting or + // updating rows in the table. + private String baseColumnName; + + final void setBaseColumnName(String name) { + baseColumnName = name; + } + + final String getBaseColumnName() { + return baseColumnName; + } + + private int tableNum; + + final void setTableNum(int num) { + tableNum = num; + } + + final int getTableNum() { + return tableNum; + } + + private int infoStatus; + + final void setInfoStatus(int status) { + infoStatus = status; + } + + final boolean hasDifferentName() { + return 0 != (infoStatus & TDS.COLINFO_STATUS_DIFFERENT_NAME); + } + + final boolean isHidden() { + return 0 != (infoStatus & TDS.COLINFO_STATUS_HIDDEN); + } + + final boolean isKey() { + return 0 != (infoStatus & TDS.COLINFO_STATUS_KEY); + } + + final boolean isExpression() { + return 0 != (infoStatus & TDS.COLINFO_STATUS_EXPRESSION); + } + + final boolean isUpdatable() { + return !isExpression() && !isHidden() && tableName.getObjectName().length() > 0; + } + + private SQLIdentifier tableName; + + final void setTableName(SQLIdentifier name) { + tableName = name; + } + + final SQLIdentifier getTableName() { + return tableName; + } + + ColumnFilter filter; + + /** + * Create a new column + * + * @param typeInfo + * the column TYPE_INFO + * @param columnName + * the column name + * @param tableName + * the column's table name + * @param cryptoMeta + * the column's crypto metadata + */ + Column(TypeInfo typeInfo, String columnName, SQLIdentifier tableName, CryptoMetadata cryptoMeta) { + this.typeInfo = typeInfo; + this.columnName = columnName; + this.baseColumnName = columnName; + this.tableName = tableName; + this.cryptoMetadata = cryptoMeta; + } + + CryptoMetadata getCryptoMetadata() { + return cryptoMetadata; + } + + /** + * Clears the values associated with this column. + */ + final void clear() { + getterDTV.clear(); + } + + /** + * Skip this column. + * + * The column's value may or may not already be marked. If this column's value has not yet been marked, this + * function assumes that the value is located at the current position in the response. + */ + final void skipValue(TDSReader tdsReader, boolean isDiscard) throws SQLServerException { + getterDTV.skipValue(typeInfo, tdsReader, isDiscard); + } + + /** + * Sets Null value on the getterDTV of a column + */ + final void initFromCompressedNull() { + getterDTV.initFromCompressedNull(); + } + + void setFilter(ColumnFilter filter) { + this.filter = filter; + } + + /** + * Returns whether the value of this column is SQL NULL. + * + * If the column has not yet been read from the response then this method returns false. + */ + final boolean isNull() { + return getterDTV.isNull(); + } + + /** + * Returns true if the column value is initialized to some value by reading the stream from server i.e. it returns + * true, if impl of getterDTV is not set to null + */ + final boolean isInitialized() { + return getterDTV.isInitialized(); + } + + /** + * Retrieves this colum's value. + * + * If the column has not yet been read from the response then this method reads it. + */ + Object getValue(JDBCType jdbcType, InputStreamGetterArgs getterArgs, Calendar cal, + TDSReader tdsReader) throws SQLServerException { + Object value = getterDTV.getValue(jdbcType, typeInfo.getScale(), getterArgs, cal, typeInfo, cryptoMetadata, + tdsReader); + setInternalVariant(getterDTV.getInternalVariant()); + return (null != filter) ? filter.apply(value, jdbcType) : value; + } + + int getInt(TDSReader tdsReader) throws SQLServerException { + return (Integer) getValue(JDBCType.INTEGER, null, null, tdsReader); + } + + void updateValue(JDBCType jdbcType, Object value, JavaType javaType, StreamSetterArgs streamSetterArgs, + Calendar cal, Integer scale, SQLServerConnection con, + SQLServerStatementColumnEncryptionSetting stmtColumnEncriptionSetting, Integer precision, + boolean forceEncrypt, int parameterIndex) throws SQLServerException { + SSType ssType = typeInfo.getSSType(); + + if (null != cryptoMetadata) { + if (SSType.VARBINARYMAX == cryptoMetadata.baseTypeInfo.getSSType() && JDBCType.BINARY == jdbcType) { + jdbcType = cryptoMetadata.baseTypeInfo.getSSType().getJDBCType(); + } + + if (null != value) { + // for encrypted tinyint, we need to convert short value to byte value, otherwise it would be sent as + // smallint + if (JDBCType.TINYINT == cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType() + && javaType == JavaType.SHORT) { + if (value instanceof Boolean) { + if (true == ((boolean) value)) { + value = 1; + } else { + value = 0; + } + } + String stringValue = "" + value; + Short shortValue = Short.valueOf(stringValue); + + if (shortValue >= 0 && shortValue <= 255) { + value = shortValue.byteValue(); + javaType = JavaType.BYTE; + jdbcType = JDBCType.TINYINT; + } + } + } + // if the column is encrypted and value is null, get the real column type instead of binary types + else if (jdbcType.isBinary()) { + jdbcType = cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType(); + } + } + + if (null == scale && null != cryptoMetadata) { + scale = cryptoMetadata.getBaseTypeInfo().getScale(); + } + + // if jdbcType is char or varchar, check if the column is actually char/varchar or nchar/nvarchar + // in order to make updateString() work with encrypted Nchar typpes + if (null != cryptoMetadata && (JDBCType.CHAR == jdbcType || JDBCType.VARCHAR == jdbcType)) { + if (JDBCType.NVARCHAR == cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType() + || JDBCType.NCHAR == cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType() + || JDBCType.LONGNVARCHAR == cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType()) { + jdbcType = cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType(); + } + } + + if (Util.shouldHonorAEForParameters(stmtColumnEncriptionSetting, con)) { + if ((null == cryptoMetadata) && true == forceEncrypt) { + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_ForceEncryptionTrue_HonorAETrue_UnencryptedColumnRS")); + Object[] msgArgs = {parameterIndex}; + + throw new SQLServerException(null, form.format(msgArgs), null, 0, false); + } else { + setJdbcTypeSetByUser(jdbcType); + + this.valueLength = Util.getValueLengthBaseOnJavaType(value, javaType, precision, scale, jdbcType); + + // for update encrypted nchar or nvarchar value on result set, must double the value length, + // otherwise, the data is truncated. + if (null != cryptoMetadata) { + if (JDBCType.NCHAR == cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType() + || JDBCType.NVARCHAR == cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType() + || JDBCType.LONGNVARCHAR == cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType()) { + this.valueLength = valueLength * 2; + } + } + } + } else { + if (true == forceEncrypt) { + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_ForceEncryptionTrue_HonorAEFalseRS")); + Object[] msgArgs = {parameterIndex}; + + throw new SQLServerException(null, form.format(msgArgs), null, 0, false); + } + } + + if (null != streamSetterArgs) { + if (!streamSetterArgs.streamType.convertsTo(typeInfo)) + DataTypes.throwConversionError(streamSetterArgs.streamType.toString(), ssType.toString()); + } else { + if (null != cryptoMetadata) { + // For GUID, set the JDBCType before checking for conversion + if ((JDBCType.UNKNOWN == jdbcType) && (value instanceof java.util.UUID)) { + javaType = JavaType.STRING; + jdbcType = JDBCType.GUID; + setJdbcTypeSetByUser(jdbcType); + } + + SSType basicSSType = cryptoMetadata.baseTypeInfo.getSSType(); + if (!jdbcType.convertsTo(basicSSType)) + DataTypes.throwConversionError(jdbcType.toString(), ssType.toString()); + + JDBCType jdbcTypeFromSSType = getJDBCTypeFromBaseSSType(basicSSType, jdbcType); + + if (jdbcTypeFromSSType != jdbcType) { + setJdbcTypeSetByUser(jdbcTypeFromSSType); + jdbcType = jdbcTypeFromSSType; + this.valueLength = Util.getValueLengthBaseOnJavaType(value, javaType, precision, scale, jdbcType); + } + } else { + if (!jdbcType.convertsTo(ssType)) + DataTypes.throwConversionError(jdbcType.toString(), ssType.toString()); + } + } + + // DateTimeOffset is not supported with SQL Server versions earlier than Katmai + if ((JDBCType.DATETIMEOFFSET == jdbcType || JavaType.DATETIMEOFFSET == javaType) && !con.isKatmaiOrLater()) { + throw new SQLServerException(SQLServerException.getErrString("R_notSupported"), + SQLState.DATA_EXCEPTION_NOT_SPECIFIC, DriverError.NOT_SET, null); + } + + // sendStringParametersAsUnicode + // If set to true, this connection property tells the driver to send textual parameters + // to the server as Unicode rather than MBCS. This is accomplished here by re-tagging + // the value with the appropriate corresponding Unicode type. + if ((null != cryptoMetadata) && (con.sendStringParametersAsUnicode()) && (JavaType.STRING == javaType + || JavaType.READER == javaType || JavaType.CLOB == javaType || JavaType.OBJECT == javaType)) { + jdbcType = getSSPAUJDBCType(jdbcType); + } + + // Cheesy checks determine whether updating is allowed, but do not determine HOW to do + // the update (i.e. what JDBC type to use for the update). The JDBC type to use depends + // on the SQL Server type of the column and the JDBC type requested. + // + // In most cases the JDBCType to use is just the requested JDBCType. But in some cases + // a client side type conversion is necessary because SQL Server does not directly support + // conversion from the requested JDBCType to the column SSType, or the driver needs to + // provide special data conversion. + + // Update of Unicode SSType from textual JDBCType: Use Unicode. + if ((SSType.NCHAR == ssType || SSType.NVARCHAR == ssType || SSType.NVARCHARMAX == ssType + || SSType.NTEXT == ssType || SSType.XML == ssType) && + + (JDBCType.CHAR == jdbcType || JDBCType.VARCHAR == jdbcType || JDBCType.LONGVARCHAR == jdbcType + || JDBCType.CLOB == jdbcType)) { + jdbcType = (JDBCType.CLOB == jdbcType) ? JDBCType.NCLOB : JDBCType.NVARCHAR; + } + + // Update of binary SSType from textual JDBCType: Convert hex to binary. + else if ((SSType.BINARY == ssType || SSType.VARBINARY == ssType || SSType.VARBINARYMAX == ssType + || SSType.IMAGE == ssType || SSType.UDT == ssType) && + + (JDBCType.CHAR == jdbcType || JDBCType.VARCHAR == jdbcType || JDBCType.LONGVARCHAR == jdbcType)) { + jdbcType = JDBCType.VARBINARY; + } + + // Update of textual SSType from temporal JDBCType requires + // client-side conversion from temporal to textual. + else if ((JDBCType.TIMESTAMP == jdbcType || JDBCType.DATE == jdbcType || JDBCType.TIME == jdbcType + || JDBCType.DATETIMEOFFSET == jdbcType) && + + (SSType.CHAR == ssType || SSType.VARCHAR == ssType || SSType.VARCHARMAX == ssType + || SSType.TEXT == ssType || SSType.NCHAR == ssType || SSType.NVARCHAR == ssType + || SSType.NVARCHARMAX == ssType || SSType.NTEXT == ssType)) { + jdbcType = JDBCType.NCHAR; + } + + // Lazily create the updater DTV on first update of the column + if (null == updaterDTV) + updaterDTV = new DTV(); + + // Set the column's value + + updaterDTV.setValue(typeInfo.getSQLCollation(), jdbcType, value, javaType, streamSetterArgs, cal, scale, con, + false); + } + + /** + * Used when sendStringParametersAsUnicode=true to derive the appropriate National Character Set JDBC type + * corresponding to the specified JDBC type. + */ + private static JDBCType getSSPAUJDBCType(JDBCType jdbcType) { + switch (jdbcType) { + case CHAR: + return JDBCType.NCHAR; + case VARCHAR: + return JDBCType.NVARCHAR; + case LONGVARCHAR: + return JDBCType.LONGNVARCHAR; + case CLOB: + return JDBCType.NCLOB; + default: + return jdbcType; + } + } + + private static JDBCType getJDBCTypeFromBaseSSType(SSType basicSSType, JDBCType jdbcType) { + switch (jdbcType) { + case TIMESTAMP: + if (SSType.DATETIME == basicSSType) + return JDBCType.DATETIME; + else if (SSType.SMALLDATETIME == basicSSType) + return JDBCType.SMALLDATETIME; + return jdbcType; + + case NUMERIC: + case DECIMAL: + if (SSType.MONEY == basicSSType) + return JDBCType.MONEY; + if (SSType.SMALLMONEY == basicSSType) + return JDBCType.SMALLMONEY; + return jdbcType; + + case CHAR: + if (SSType.GUID == basicSSType) + return JDBCType.GUID; + if (SSType.VARCHARMAX == basicSSType) + return JDBCType.LONGVARCHAR; + return jdbcType; + + default: + return jdbcType; + } + } + + boolean hasUpdates() { + return null != updaterDTV; + } + + void cancelUpdates() { + updaterDTV = null; + } + + void sendByRPC(TDSWriter tdsWriter, SQLServerConnection conn) throws SQLServerException { + // If the column has had no updates then there is nothing to send + if (null == updaterDTV) + return; + try { + // this is for updateRow() stuff + updaterDTV.sendCryptoMetaData(cryptoMetadata, tdsWriter); + updaterDTV.jdbcTypeSetByUser(getJdbcTypeSetByUser(), getValueLength()); + + // Otherwise, send the updated value via RPC + updaterDTV.sendByRPC(baseColumnName, typeInfo, + null != cryptoMetadata ? cryptoMetadata.getBaseTypeInfo().getSQLCollation() + : typeInfo.getSQLCollation(), + null != cryptoMetadata ? cryptoMetadata.getBaseTypeInfo().getPrecision() : typeInfo.getPrecision(), + null != cryptoMetadata ? cryptoMetadata.getBaseTypeInfo().getScale() : typeInfo.getScale(), false, // isOutParameter + // (always + // false + // for + // column + // updates) + tdsWriter, conn); + } finally { + // this is for updateRow() stuff + updaterDTV.sendCryptoMetaData(null, tdsWriter); + } + } + + JDBCType getJdbcTypeSetByUser() { + return jdbcTypeSetByUser; + } + + void setJdbcTypeSetByUser(JDBCType jdbcTypeSetByUser) { + this.jdbcTypeSetByUser = jdbcTypeSetByUser; + } + + int getValueLength() { + return valueLength; + } +} + + +abstract class ColumnFilter { + abstract Object apply(Object value, JDBCType jdbcType) throws SQLServerException; +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/DDC.java b/src/main/java/com/microsoft/sqlserver/jdbc/DDC.java index 2509b5e3c..1fa3e55da 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/DDC.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/DDC.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -29,6 +26,7 @@ import java.util.Locale; import java.util.TimeZone; + /** * Utility class for all Data Dependant Conversions (DDC). */ @@ -39,18 +37,16 @@ final class DDC { * Convert an Integer object to desired target user type. * * @param intvalue - * the value to convert. + * the value to convert. * @param valueLength - * the value to convert. + * the value to convert. * @param jdbcType - * the jdbc type required. + * the jdbc type required. * @param streamType - * the type of stream required. + * the type of stream required. * @return the required object. */ - static final Object convertIntegerToObject(int intValue, - int valueLength, - JDBCType jdbcType, + static final Object convertIntegerToObject(int intValue, int valueLength, JDBCType jdbcType, StreamType streamType) { switch (jdbcType) { case INTEGER: @@ -84,19 +80,16 @@ static final Object convertIntegerToObject(int intValue, * Convert a Long object to desired target user type. * * @param longVal - * the value to convert. + * the value to convert. * @param jdbcType - * the jdbc type required. + * the jdbc type required. * @param baseSSType - * the base SQLServer type. + * the base SQLServer type. * @param streamType - * the stream type. + * the stream type. * @return the required object. */ - static final Object convertLongToObject(long longVal, - JDBCType jdbcType, - SSType baseSSType, - StreamType streamType) { + static final Object convertLongToObject(long longVal, JDBCType jdbcType, SSType baseSSType, StreamType streamType) { switch (jdbcType) { case BIGINT: return longVal; @@ -128,22 +121,26 @@ static final Object convertLongToObject(long longVal, case TINYINT: bytesToReturnLength = 1; bytesToReturn = new byte[bytesToReturnLength]; - System.arraycopy(convertedBytes, convertedBytes.length - bytesToReturnLength, bytesToReturn, 0, bytesToReturnLength); + System.arraycopy(convertedBytes, convertedBytes.length - bytesToReturnLength, bytesToReturn, 0, + bytesToReturnLength); return bytesToReturn; case SMALLINT: bytesToReturnLength = 2; bytesToReturn = new byte[bytesToReturnLength]; - System.arraycopy(convertedBytes, convertedBytes.length - bytesToReturnLength, bytesToReturn, 0, bytesToReturnLength); + System.arraycopy(convertedBytes, convertedBytes.length - bytesToReturnLength, bytesToReturn, 0, + bytesToReturnLength); return bytesToReturn; case INTEGER: bytesToReturnLength = 4; bytesToReturn = new byte[bytesToReturnLength]; - System.arraycopy(convertedBytes, convertedBytes.length - bytesToReturnLength, bytesToReturn, 0, bytesToReturnLength); + System.arraycopy(convertedBytes, convertedBytes.length - bytesToReturnLength, bytesToReturn, 0, + bytesToReturnLength); return bytesToReturn; case BIGINT: bytesToReturnLength = 8; bytesToReturn = new byte[bytesToReturnLength]; - System.arraycopy(convertedBytes, convertedBytes.length - bytesToReturnLength, bytesToReturn, 0, bytesToReturnLength); + System.arraycopy(convertedBytes, convertedBytes.length - bytesToReturnLength, bytesToReturn, 0, + bytesToReturnLength); return bytesToReturn; default: return convertedBytes; @@ -183,13 +180,12 @@ static final Object convertLongToObject(long longVal, * Encodes an integer value to a byte array in big-endian order. * * @param intValue - * the integer value to encode. + * the integer value to encode. * @param valueLength - * the number of bytes to encode. + * the number of bytes to encode. * @return the byte array containing the big-endian encoded value. */ - static final byte[] convertIntToBytes(int intValue, - int valueLength) { + static final byte[] convertIntToBytes(int intValue, int valueLength) { byte bytes[] = new byte[valueLength]; for (int i = valueLength; i-- > 0;) { bytes[i] = (byte) (intValue & 0xFF); @@ -202,16 +198,14 @@ static final byte[] convertIntToBytes(int intValue, * Convert a Float object to desired target user type. * * @param floatVal - * the value to convert. + * the value to convert. * @param jdbcType - * the jdbc type required. + * the jdbc type required. * @param streamType - * the stream type. + * the stream type. * @return the required object. */ - static final Object convertFloatToObject(float floatVal, - JDBCType jdbcType, - StreamType streamType) { + static final Object convertFloatToObject(float floatVal, JDBCType jdbcType, StreamType streamType) { switch (jdbcType) { case REAL: return floatVal; @@ -244,7 +238,7 @@ static final Object convertFloatToObject(float floatVal, * Encodes a long value to a byte array in big-endian order. * * @param longValue - * the long value to encode. + * the long value to encode. * @return the byte array containing the big-endian encoded value. */ static final byte[] convertLongToBytes(long longValue) { @@ -260,16 +254,14 @@ static final byte[] convertLongToBytes(long longValue) { * Convert a Double object to desired target user type. * * @param doubleVal - * the value to convert. + * the value to convert. * @param jdbcType - * the jdbc type required. + * the jdbc type required. * @param streamType - * the stream type. + * the stream type. * @return the required object. */ - static final Object convertDoubleToObject(double doubleVal, - JDBCType jdbcType, - StreamType streamType) { + static final Object convertDoubleToObject(double doubleVal, JDBCType jdbcType, StreamType streamType) { switch (jdbcType) { case FLOAT: case DOUBLE: @@ -298,16 +290,14 @@ static final Object convertDoubleToObject(double doubleVal, } } - static final byte[] convertBigDecimalToBytes(BigDecimal bigDecimalVal, - int scale) { + static final byte[] convertBigDecimalToBytes(BigDecimal bigDecimalVal, int scale) { byte[] valueBytes; if (bigDecimalVal == null) { valueBytes = new byte[2]; valueBytes[0] = (byte) scale; valueBytes[1] = 0; // data length - } - else { + } else { boolean isNegative = (bigDecimalVal.signum() < 0); // NOTE: Handle negative scale as a special case for JDK 1.5 and later VMs. @@ -337,16 +327,14 @@ static final byte[] convertBigDecimalToBytes(BigDecimal bigDecimalVal, * Convert a BigDecimal object to desired target user type. * * @param bigDecimalVal - * the value to convert. + * the value to convert. * @param jdbcType - * the jdbc type required. + * the jdbc type required. * @param streamType - * the stream type. + * the stream type. * @return the required object. */ - static final Object convertBigDecimalToObject(BigDecimal bigDecimalVal, - JDBCType jdbcType, - StreamType streamType) { + static final Object convertBigDecimalToObject(BigDecimal bigDecimalVal, JDBCType jdbcType, StreamType streamType) { switch (jdbcType) { case DECIMAL: case NUMERIC: @@ -379,18 +367,16 @@ static final Object convertBigDecimalToObject(BigDecimal bigDecimalVal, * Convert a Money object to desired target user type. * * @param bigDecimalVal - * the value to convert. + * the value to convert. * @param jdbcType - * the jdbc type required. + * the jdbc type required. * @param streamType - * the stream type. + * the stream type. * @param numberOfBytes - * the number of bytes to convert + * the number of bytes to convert * @return the required object. */ - static final Object convertMoneyToObject(BigDecimal bigDecimalVal, - JDBCType jdbcType, - StreamType streamType, + static final Object convertMoneyToObject(BigDecimal bigDecimalVal, JDBCType jdbcType, StreamType streamType, int numberOfBytes) { switch (jdbcType) { case DECIMAL: @@ -421,9 +407,7 @@ static final Object convertMoneyToObject(BigDecimal bigDecimalVal, } // converts big decimal to money and smallmoney - private static byte[] convertToBytes(BigDecimal value, - int scale, - int numBytes) { + private static byte[] convertToBytes(BigDecimal value, int scale, int numBytes) { boolean isNeg = value.signum() < 0; value = value.setScale(scale); @@ -447,17 +431,16 @@ private static byte[] convertToBytes(BigDecimal value, * Convert a byte array to desired target user type. * * @param bytesValue - * the value to convert. + * the value to convert. * @param jdbcType - * the jdbc type required. + * the jdbc type required. * @param baseTypeInfo - * the type information associated with bytesValue. + * the type information associated with bytesValue. * @return the required object. * @throws SQLServerException - * when an error occurs. + * when an error occurs. */ - static final Object convertBytesToObject(byte[] bytesValue, - JDBCType jdbcType, + static final Object convertBytesToObject(byte[] bytesValue, JDBCType jdbcType, TypeInfo baseTypeInfo) throws SQLServerException { switch (jdbcType) { case CHAR: @@ -487,8 +470,10 @@ static final Object convertBytesToObject(byte[] bytesValue, return bytesValue; default: - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_unsupportedConversionFromTo")); - throw new SQLServerException(form.format(new Object[] {baseTypeInfo.getSSType().name(), jdbcType}), null, 0, null); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_unsupportedConversionFromTo")); + throw new SQLServerException(form.format(new Object[] {baseTypeInfo.getSSType().name(), jdbcType}), + null, 0, null); } } @@ -496,16 +481,14 @@ static final Object convertBytesToObject(byte[] bytesValue, * Convert a String object to desired target user type. * * @param stringVal - * the value to convert. + * the value to convert. * @param charset - * the character set. + * the character set. * @param jdbcType - * the jdbc type required. + * the jdbc type required. * @return the required object. */ - static final Object convertStringToObject(String stringVal, - Charset charset, - JDBCType jdbcType, + static final Object convertStringToObject(String stringVal, Charset charset, JDBCType jdbcType, StreamType streamType) throws UnsupportedEncodingException, IllegalArgumentException { switch (jdbcType) { // Convert String to Numeric types. @@ -527,7 +510,8 @@ static final Object convertStringToObject(String stringVal, case BIT: case BOOLEAN: String trimmedString = stringVal.trim(); - return (1 == trimmedString.length()) ? Boolean.valueOf('1' == trimmedString.charAt(0)) : Boolean.valueOf(trimmedString); + return (1 == trimmedString.length()) ? Boolean.valueOf('1' == trimmedString.charAt(0)) + : Boolean.valueOf(trimmedString); case BIGINT: return Long.valueOf(stringVal.trim()); @@ -545,7 +529,8 @@ static final Object convertStringToObject(String stringVal, // 1) Normalize and parse as a Timestamp // 2) Round fractional seconds up to the nearest millisecond (max resolution of java.sql.Time) // 3) Renormalize (as rounding may have changed the date) to a java.sql.Time - java.sql.Timestamp ts = java.sql.Timestamp.valueOf(TDS.BASE_DATE_1970 + " " + getTimePart(stringVal.trim())); + java.sql.Timestamp ts = java.sql.Timestamp + .valueOf(TDS.BASE_DATE_1970 + " " + getTimePart(stringVal.trim())); GregorianCalendar cal = new GregorianCalendar(Locale.US); cal.clear(); cal.setTimeInMillis(ts.getTime()); @@ -574,9 +559,7 @@ static final Object convertStringToObject(String stringVal, } } - static final Object convertStreamToObject(BaseInputStream stream, - TypeInfo typeInfo, - JDBCType jdbcType, + static final Object convertStreamToObject(BaseInputStream stream, TypeInfo typeInfo, JDBCType jdbcType, InputStreamGetterArgs getterArgs) throws SQLServerException { // Need to handle the simple case of a null value here, as it is not done // outside this function. @@ -601,13 +584,13 @@ static final Object convertStreamToObject(BaseInputStream stream, // Binary streams to character types: // - Direct conversion to ASCII stream // - Convert as hexized value to other character types - if (SSType.BINARY == ssType || SSType.VARBINARY == ssType || SSType.VARBINARYMAX == ssType || SSType.TIMESTAMP == ssType - || SSType.IMAGE == ssType || SSType.UDT == ssType) { + if (SSType.BINARY == ssType || SSType.VARBINARY == ssType || SSType.VARBINARYMAX == ssType + || SSType.TIMESTAMP == ssType || SSType.IMAGE == ssType || SSType.UDT == ssType) { if (StreamType.ASCII == getterArgs.streamType) { return stream; - } - else { - assert StreamType.CHARACTER == getterArgs.streamType || StreamType.NONE == getterArgs.streamType; + } else { + assert StreamType.CHARACTER == getterArgs.streamType + || StreamType.NONE == getterArgs.streamType; byte[] byteValue = stream.getBytes(); if (JDBCType.GUID == jdbcType) { @@ -616,8 +599,7 @@ static final Object convertStreamToObject(BaseInputStream stream, return Geometry.STGeomFromWKB(byteValue); } else if (JDBCType.GEOGRAPHY == jdbcType) { return Geography.STGeomFromWKB(byteValue); - } - else { + } else { String hexString = Util.bytesToHexString(byteValue, byteValue.length); if (StreamType.NONE == getterArgs.streamType) @@ -638,21 +620,22 @@ static final Object convertStreamToObject(BaseInputStream stream, if (getterArgs.isAdaptive) { return AsciiFilteredUnicodeInputStream.MakeAsciiFilteredUnicodeInputStream(stream, new BufferedReader(new InputStreamReader(stream, typeInfo.getCharset()))); + } else { + return new ByteArrayInputStream( + (new String(stream.getBytes(), typeInfo.getCharset())).getBytes(US_ASCII)); } - else { - return new ByteArrayInputStream((new String(stream.getBytes(), typeInfo.getCharset())).getBytes(US_ASCII)); - } - } - else if (StreamType.CHARACTER == getterArgs.streamType || StreamType.NCHARACTER == getterArgs.streamType) { + } else if (StreamType.CHARACTER == getterArgs.streamType + || StreamType.NCHARACTER == getterArgs.streamType) { if (getterArgs.isAdaptive) return new BufferedReader(new InputStreamReader(stream, typeInfo.getCharset())); else return new StringReader(new String(stream.getBytes(), typeInfo.getCharset())); } - // None of the special/fast textual conversion cases applied. Just go the normal route of converting via String. - return convertStringToObject(new String(stream.getBytes(), typeInfo.getCharset()), typeInfo.getCharset(), jdbcType, - getterArgs.streamType); + // None of the special/fast textual conversion cases applied. Just go the normal route of converting + // via String. + return convertStringToObject(new String(stream.getBytes(), typeInfo.getCharset()), + typeInfo.getCharset(), jdbcType, getterArgs.streamType); case CLOB: return new SQLServerClob(stream, typeInfo); @@ -689,8 +672,7 @@ else if (StreamType.CHARACTER == getterArgs.streamType || StreamType.NCHARACTER catch (IllegalArgumentException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_errorConvertingValue")); throw new SQLServerException(form.format(new Object[] {typeInfo.getSSType(), jdbcType}), null, 0, e); - } - catch (UnsupportedEncodingException e) { + } catch (UnsupportedEncodingException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_errorConvertingValue")); throw new SQLServerException(form.format(new Object[] {typeInfo.getSSType(), jdbcType}), null, 0, e); } @@ -716,8 +698,7 @@ private static String getTimePart(String s) { // Formats nanoseconds as a String of the form ".nnnnnnn...." where the number // of digits is equal to the scale. Returns the empty string for scale = 0; - private static String fractionalSecondsString(long subSecondNanos, - int scale) { + private static String fractionalSecondsString(long subSecondNanos, int scale) { assert 0 <= subSecondNanos && subSecondNanos < Nanos.PER_SECOND; assert 0 <= scale && scale <= TDS.MAX_FRACTIONAL_SECONDS_SCALE; @@ -726,7 +707,8 @@ private static String fractionalSecondsString(long subSecondNanos, if (0 == scale) return ""; - return java.math.BigDecimal.valueOf(subSecondNanos % Nanos.PER_SECOND, 9).setScale(scale).toPlainString().substring(1); + return java.math.BigDecimal.valueOf(subSecondNanos % Nanos.PER_SECOND, 9).setScale(scale).toPlainString() + .substring(1); } /** @@ -741,38 +723,36 @@ private static String fractionalSecondsString(long subSecondNanos, * java.sql.Date java.sql.Time java.sql.Timestamp java.lang.String * * @param jdbcType - * the JDBC type indicating the desired conversion + * the JDBC type indicating the desired conversion * * @param ssType - * the SQL Server data type of the value being converted + * the SQL Server data type of the value being converted * * @param timeZoneCalendar - * (optional) a Calendar representing the time zone to associate with the resulting converted value. For DATETIMEOFFSET, this parameter - * represents the time zone associated with the value. Null means to use the default VM time zone. + * (optional) a Calendar representing the time zone to associate with the resulting converted value. For + * DATETIMEOFFSET, this parameter represents the time zone associated with the value. Null means to use the + * default VM time zone. * * @param daysSinceBaseDate - * The date part of the value, expressed as a number of days since the base date for the specified SQL Server data type. For DATETIME - * and SMALLDATETIME, the base date is 1/1/1900. For other types, the base date is 1/1/0001. The number of days assumes Gregorian leap - * year behavior over the entire supported range of values. For TIME values, this parameter must be the number of days between 1/1/0001 - * and 1/1/1900 when converting to java.sql.Timestamp. + * The date part of the value, expressed as a number of days since the base date for the specified SQL Server + * data type. For DATETIME and SMALLDATETIME, the base date is 1/1/1900. For other types, the base date is + * 1/1/0001. The number of days assumes Gregorian leap year behavior over the entire supported range of + * values. For TIME values, this parameter must be the number of days between 1/1/0001 and 1/1/1900 when + * converting to java.sql.Timestamp. * * @param ticksSinceMidnight - * The time part of the value, expressed as a number of time units (ticks) since midnight. For DATETIME and SMALLDATETIME SQL Server - * data types, time units are in milliseconds. For other types, time units are in nanoseconds. For DATE values, this parameter must be - * 0. + * The time part of the value, expressed as a number of time units (ticks) since midnight. For DATETIME and + * SMALLDATETIME SQL Server data types, time units are in milliseconds. For other types, time units are in + * nanoseconds. For DATE values, this parameter must be 0. * * @param fractionalSecondsScale - * the desired fractional seconds scale to use when formatting the value as a String. Ignored for conversions to Java types other than - * String. + * the desired fractional seconds scale to use when formatting the value as a String. Ignored for conversions + * to Java types other than String. * * @return a Java object of the desired type. */ - static final Object convertTemporalToObject(JDBCType jdbcType, - SSType ssType, - Calendar timeZoneCalendar, - int daysSinceBaseDate, - long ticksSinceMidnight, - int fractionalSecondsScale) { + static final Object convertTemporalToObject(JDBCType jdbcType, SSType ssType, Calendar timeZoneCalendar, + int daysSinceBaseDate, long ticksSinceMidnight, int fractionalSecondsScale) { // Determine the local time zone to associate with the value. Use the default VM // time zone if no time zone is otherwise specified. TimeZone localTimeZone = (null != timeZoneCalendar) ? timeZoneCalendar.getTimeZone() : TimeZone.getDefault(); @@ -834,7 +814,8 @@ static final Object convertTemporalToObject(JDBCType jdbcType, // // Ticks are in nanoseconds. - cal.set(1, Calendar.JANUARY, 1 + daysSinceBaseDate + GregorianChange.EXTRA_DAYS_TO_BE_ADDED, 0, 0, 0); + cal.set(1, Calendar.JANUARY, 1 + daysSinceBaseDate + GregorianChange.EXTRA_DAYS_TO_BE_ADDED, 0, 0, + 0); cal.set(Calendar.MILLISECOND, (int) (ticksSinceMidnight / Nanos.PER_MILLISECOND)); } @@ -918,8 +899,7 @@ static final Object convertTemporalToObject(JDBCType jdbcType, _cal.setLenient(true); _cal.clear(); localMillisOffset = tz.getOffset(_cal.getTimeInMillis()); - } - else { + } else { localMillisOffset = timeZoneCalendar.get(Calendar.ZONE_OFFSET); } // Convert the calendar value (in local time) to the desired Java object type. @@ -1056,9 +1036,12 @@ static final Object convertTemporalToObject(JDBCType jdbcType, assert 0 == localMillisOffset % (60 * 1000); int unsignedMinutesOffset = Math.abs(localMillisOffset / (60 * 1000)); - return String.format(Locale.US, "%1$tF %1$tT%2$s %3$c%4$02d:%5$02d", // yyyy-mm-dd hh:mm:ss[.nnnnnnn] [+|-]hh:mm - cal, fractionalSecondsString(subSecondNanos, fractionalSecondsScale), (localMillisOffset >= 0) ? '+' : '-', - unsignedMinutesOffset / 60, unsignedMinutesOffset % 60); + return String.format(Locale.US, "%1$tF %1$tT%2$s %3$c%4$02d:%5$02d", // yyyy-mm-dd + // hh:mm:ss[.nnnnnnn] + // [+|-]hh:mm + cal, fractionalSecondsString(subSecondNanos, fractionalSecondsScale), + (localMillisOffset >= 0) ? '+' : '-', unsignedMinutesOffset / 60, + unsignedMinutesOffset % 60); } case DATETIME: // and SMALLDATETIME @@ -1077,25 +1060,23 @@ cal, fractionalSecondsString(subSecondNanos, fractionalSecondsScale), (localMill } /** - * Returns the number of days elapsed from January 1 of the specified baseYear (Gregorian) to the specified dayOfYear in the specified year, - * assuming pure Gregorian calendar rules (no Julian to Gregorian cutover). + * Returns the number of days elapsed from January 1 of the specified baseYear (Gregorian) to the specified + * dayOfYear in the specified year, assuming pure Gregorian calendar rules (no Julian to Gregorian cutover). */ - static int daysSinceBaseDate(int year, - int dayOfYear, - int baseYear) { + static int daysSinceBaseDate(int year, int dayOfYear, int baseYear) { assert year >= 1; assert baseYear >= 1; assert dayOfYear >= 1; - return (dayOfYear - 1) + // Days into the current year - (year - baseYear) * TDS.DAYS_PER_YEAR + // plus whole years (in days) ... - leapDaysBeforeYear(year) - // ... plus leap days + return (dayOfYear - 1) + // Days into the current year + (year - baseYear) * TDS.DAYS_PER_YEAR + // plus whole years (in days) ... + leapDaysBeforeYear(year) - // ... plus leap days leapDaysBeforeYear(baseYear); } /** - * Returns the number of leap days that have occurred between January 1, 1AD and January 1 of the specified year, assuming a Proleptic Gregorian - * Calendar + * Returns the number of leap days that have occurred between January 1, 1AD and January 1 of the specified year, + * assuming a Proleptic Gregorian Calendar */ private static int leapDaysBeforeYear(int year) { assert year >= 1; @@ -1128,15 +1109,15 @@ static final boolean exceedsMaxRPCDecimalPrecisionOrScale(BigDecimal bigDecimalV // Convert to unscaled integer value, then compare with maxRPCDecimalValue. // NOTE: Handle negative scale as a special case for JDK 1.5 and later VMs. - BigInteger bi = (bigDecimalValue.scale() < 0) ? bigDecimalValue.setScale(0).unscaledValue() : bigDecimalValue.unscaledValue(); + BigInteger bi = (bigDecimalValue.scale() < 0) ? bigDecimalValue.setScale(0).unscaledValue() + : bigDecimalValue.unscaledValue(); if (bigDecimalValue.signum() < 0) bi = bi.negate(); return (bi.compareTo(maxRPCDecimalValue) > 0); } // Converts a Reader to a String. - static String convertReaderToString(Reader reader, - int readerLength) throws SQLServerException { + static String convertReaderToString(Reader reader, int readerLength) throws SQLServerException { assert DataTypes.UNKNOWN_STREAM_LENGTH == readerLength || readerLength >= 0; // Optimize simple cases. @@ -1149,12 +1130,14 @@ static String convertReaderToString(Reader reader, // Set up a StringBuilder big enough to hold the Reader value. If we weren't told the size of // the value then start with a "reasonable" guess StringBuilder size. If necessary, the StringBuilder // will grow automatically to accomodate arbitrary amounts of data. - StringBuilder sb = new StringBuilder((DataTypes.UNKNOWN_STREAM_LENGTH != readerLength) ? readerLength : 4000); + StringBuilder sb = new StringBuilder( + (DataTypes.UNKNOWN_STREAM_LENGTH != readerLength) ? readerLength : 4000); // Set up the buffer into which blocks of characters are read from the Reader. This buffer // should be no larger than the Reader value's size (if known). For known very large values, // limit the buffer's size to reduce this function's memory requirements. - char charArray[] = new char[(DataTypes.UNKNOWN_STREAM_LENGTH != readerLength && readerLength < 4000) ? readerLength : 4000]; + char charArray[] = new char[(DataTypes.UNKNOWN_STREAM_LENGTH != readerLength + && readerLength < 4000) ? readerLength : 4000]; // Loop and read characters, chunk into StringBuilder until EOS. int readChars; @@ -1171,8 +1154,7 @@ static String convertReaderToString(Reader reader, } return sb.toString(); - } - catch (IOException ioEx) { + } catch (IOException ioEx) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_errorReadingStream")); Object[] msgArgs = {ioEx.toString()}; SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), "", true); @@ -1183,11 +1165,12 @@ static String convertReaderToString(Reader reader, } } + /** * InputStream implementation that wraps a contained InputStream, filtering it for 7-bit ASCII characters. * - * The wrapped input stream must supply byte values from a SBCS character set whose first 128 entries match the 7-bit US-ASCII character set. Values - * that lie outside of the 7-bit US-ASCII range are translated to the '?' character. + * The wrapped input stream must supply byte values from a SBCS character set whose first 128 entries match the 7-bit + * US-ASCII character set. Values that lie outside of the 7-bit US-ASCII range are translated to the '?' character. */ final class AsciiFilteredInputStream extends InputStream { private final InputStream containedStream; @@ -1240,9 +1223,7 @@ public int read(byte[] b) throws IOException { return bytesRead; } - public int read(byte b[], - int offset, - int maxBytes) throws IOException { + public int read(byte b[], int offset, int maxBytes) throws IOException { int bytesRead = containedStream.read(b, offset, maxBytes); if (bytesRead > 0) { assert offset + bytesRead <= b.length; @@ -1265,6 +1246,7 @@ public void reset() throws IOException { } } + /** * InputStream implementation that wraps a contained InputStream, filtering it for 7-bit ASCII characters from UNICODE. * @@ -1298,7 +1280,8 @@ public long skip(long n) throws IOException { public int available() throws IOException { // from the JDBC spec - // Note: A stream may return 0 when the method InputStream.available is called whether there is data available or not. + // Note: A stream may return 0 when the method InputStream.available is called whether there is data available + // or not. // Reader does not give us available data. return 0; } @@ -1314,9 +1297,7 @@ public int read(byte[] b) throws IOException { return read(b, 0, b.length); } - public int read(byte b[], - int offset, - int maxBytes) throws IOException { + public int read(byte b[], int offset, int maxBytes) throws IOException { char tempBufferToHoldCharDataForConversion[] = new char[maxBytes]; int charsRead = containedReader.read(tempBufferToHoldCharDataForConversion); @@ -1336,9 +1317,9 @@ public boolean markSupported() { public void mark(int readLimit) { try { containedReader.mark(readLimit); - } - catch (IOException e) { - // unfortunately inputstream mark does not throw an exception so we have to eat any exception from the reader here + } catch (IOException e) { + // unfortunately inputstream mark does not throw an exception so we have to eat any exception from the + // reader here // likely to be a bug in the original InputStream spec. } } @@ -1348,6 +1329,7 @@ public void reset() throws IOException { } } + // Helper class to hold + pass around stream/reader setter arguments. final class StreamSetterArgs { private long length; @@ -1366,13 +1348,13 @@ final void setLength(long newLength) { final StreamType streamType; - StreamSetterArgs(StreamType streamType, - long length) { + StreamSetterArgs(StreamType streamType, long length) { this.streamType = streamType; this.length = length; } } + // Helper class to hold + pass around InputStream getter arguments. final class InputStreamGetterArgs { final StreamType streamType; @@ -1386,10 +1368,7 @@ static final InputStreamGetterArgs getDefaultArgs() { return defaultArgs; } - InputStreamGetterArgs(StreamType streamType, - boolean isAdaptive, - boolean isStreaming, - String logContext) { + InputStreamGetterArgs(StreamType streamType, boolean isAdaptive, boolean isStreaming, String logContext) { this.streamType = streamType; this.isAdaptive = isAdaptive; this.isStreaming = isStreaming; diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/DLLException.java b/src/main/java/com/microsoft/sqlserver/jdbc/DLLException.java index a81252e74..1f78a9697 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/DLLException.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/DLLException.java @@ -1,184 +1,167 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -import java.text.MessageFormat; - -/** - * - * This class is used to handle exceptions that may be recieved from sqljdbc_auth.dll and sqljdbc_xa.dll - * - */ -class DLLException extends Exception { - private static final long serialVersionUID = -4498171382218222079L; - // category status and state are always either -1 or a positive number - // Internal Adal error category used in retry logic and building error message in managed code - private int category = -9; - // Public facing failing status returned from Adal APIs in SNISecADALGetAccessToken - private int status = -9; - // Internal last Adal API called in SNISecADALGetAccessToken for troubleshooting - private int state = -9; - - // Internal error code used to choose which error message to print - private int errCode = -1; // any value that is not assigned to an error - // Parameters used to build error messages from auth dll - private String param1 = ""; - private String param2 = ""; - private String param3 = ""; - - DLLException(String message, - int category, - int status, - int state) { - super(message); - this.category = category; - this.status = status; - this.state = state; - } - - DLLException(String param1, - String param2, - String param3, - int errCode) { - this.errCode = errCode; - this.param1 = param1; - this.param2 = param2; - this.param3 = param3; - } - - int GetCategory() { - return this.category; - } - - int GetStatus() { - return this.status; - } - - int GetState() { - return this.state; - } - - int GetErrCode() { - return this.errCode; - } - - String GetParam1() { - return this.param1; - } - - String GetParam2() { - return this.param2; - } - - String GetParam3() { - return this.param3; - } - - static void buildException(int errCode, - String param1, - String param2, - String param3) throws SQLServerException { - - String errMessage = getErrMessage(errCode); - MessageFormat form = new MessageFormat(SQLServerException.getErrString(errMessage)); - - String[] msgArgs = buildMsgParams(errMessage, param1, param2, param3); - - throw new SQLServerException(null, form.format(msgArgs), null, 0, false); - } - - private static String[] buildMsgParams(String errMessage, - String parameter1, - String parameter2, - String parameter3) { - - String[] msgArgs = new String[3]; - - if ("R_AECertLocBad".equalsIgnoreCase(errMessage)) { - msgArgs[0] = parameter1; - msgArgs[1] = parameter1 + "/" + parameter2 + "/" + parameter3; - } - else if ("R_AECertStoreBad".equalsIgnoreCase(errMessage)) { - msgArgs[0] = parameter2; - msgArgs[1] = parameter1 + "/" + parameter2 + "/" + parameter3; - } - else if ("R_AECertHashEmpty".equalsIgnoreCase(errMessage)) { - msgArgs[0] = parameter1 + "/" + parameter2 + "/" + parameter3; - } - else { - msgArgs[0] = parameter1; - msgArgs[1] = parameter2; - msgArgs[2] = parameter3; - } - - return msgArgs; - } - - private static String getErrMessage(int errCode) { - String message; - switch (errCode) { - case 1: - message = "R_AEKeypathEmpty"; - break; - case 2: - message = "R_EncryptedCEKNull"; - break; - case 3: - message = "R_NullKeyEncryptionAlgorithm"; - break; - case 4: - message = "R_AEWinApiErr"; - break; - case 5: - message = "R_AECertpathBad"; - break; - case 6: - message = "R_AECertLocBad"; - break; - case 7: - message = "R_AECertStoreBad"; - break; - case 8: - message = "R_AECertHashEmpty"; - break; - case 9: - message = "R_AECertNotFound"; - break; - case 10: - message = "R_AEMaloc"; - break; - case 11: - message = "R_EmptyEncryptedCEK"; - break; - case 12: - message = "R_InvalidKeyEncryptionAlgorithm"; - break; - case 13: - message = "R_AEKeypathLong"; - break; - case 14: - message = "R_InvalidEcryptionAlgorithmVersion"; - break; - case 15: - message = "R_AEECEKLenBad"; - break; - case 16: - message = "R_AEECEKSigLenBad"; - break; - case 17: - message = "R_InvalidCertificateSignature"; - break; - default: - message = "R_AEWinApiErr"; - break; - - } - return message; - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +import java.text.MessageFormat; + + +/** + * + * This class is used to handle exceptions that may be recieved from sqljdbc_auth.dll and sqljdbc_xa.dll + * + */ +class DLLException extends Exception { + private static final long serialVersionUID = -4498171382218222079L; + // category status and state are always either -1 or a positive number + // Internal Adal error category used in retry logic and building error message in managed code + private int category = -9; + // Public facing failing status returned from Adal APIs in SNISecADALGetAccessToken + private int status = -9; + // Internal last Adal API called in SNISecADALGetAccessToken for troubleshooting + private int state = -9; + + // Internal error code used to choose which error message to print + private int errCode = -1; // any value that is not assigned to an error + // Parameters used to build error messages from auth dll + private String param1 = ""; + private String param2 = ""; + private String param3 = ""; + + DLLException(String message, int category, int status, int state) { + super(message); + this.category = category; + this.status = status; + this.state = state; + } + + DLLException(String param1, String param2, String param3, int errCode) { + this.errCode = errCode; + this.param1 = param1; + this.param2 = param2; + this.param3 = param3; + } + + int GetCategory() { + return this.category; + } + + int GetStatus() { + return this.status; + } + + int GetState() { + return this.state; + } + + int GetErrCode() { + return this.errCode; + } + + String GetParam1() { + return this.param1; + } + + String GetParam2() { + return this.param2; + } + + String GetParam3() { + return this.param3; + } + + static void buildException(int errCode, String param1, String param2, String param3) throws SQLServerException { + + String errMessage = getErrMessage(errCode); + MessageFormat form = new MessageFormat(SQLServerException.getErrString(errMessage)); + + String[] msgArgs = buildMsgParams(errMessage, param1, param2, param3); + + throw new SQLServerException(null, form.format(msgArgs), null, 0, false); + } + + private static String[] buildMsgParams(String errMessage, String parameter1, String parameter2, String parameter3) { + + String[] msgArgs = new String[3]; + + if ("R_AECertLocBad".equalsIgnoreCase(errMessage)) { + msgArgs[0] = parameter1; + msgArgs[1] = parameter1 + "/" + parameter2 + "/" + parameter3; + } else if ("R_AECertStoreBad".equalsIgnoreCase(errMessage)) { + msgArgs[0] = parameter2; + msgArgs[1] = parameter1 + "/" + parameter2 + "/" + parameter3; + } else if ("R_AECertHashEmpty".equalsIgnoreCase(errMessage)) { + msgArgs[0] = parameter1 + "/" + parameter2 + "/" + parameter3; + } else { + msgArgs[0] = parameter1; + msgArgs[1] = parameter2; + msgArgs[2] = parameter3; + } + + return msgArgs; + } + + private static String getErrMessage(int errCode) { + String message; + switch (errCode) { + case 1: + message = "R_AEKeypathEmpty"; + break; + case 2: + message = "R_EncryptedCEKNull"; + break; + case 3: + message = "R_NullKeyEncryptionAlgorithm"; + break; + case 4: + message = "R_AEWinApiErr"; + break; + case 5: + message = "R_AECertpathBad"; + break; + case 6: + message = "R_AECertLocBad"; + break; + case 7: + message = "R_AECertStoreBad"; + break; + case 8: + message = "R_AECertHashEmpty"; + break; + case 9: + message = "R_AECertNotFound"; + break; + case 10: + message = "R_AEMaloc"; + break; + case 11: + message = "R_EmptyEncryptedCEK"; + break; + case 12: + message = "R_InvalidKeyEncryptionAlgorithm"; + break; + case 13: + message = "R_AEKeypathLong"; + break; + case 14: + message = "R_InvalidEcryptionAlgorithmVersion"; + break; + case 15: + message = "R_AEECEKLenBad"; + break; + case 16: + message = "R_AEECEKSigLenBad"; + break; + case 17: + message = "R_InvalidCertificateSignature"; + break; + default: + message = "R_AEWinApiErr"; + break; + + } + return message; + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/DataTypes.java b/src/main/java/com/microsoft/sqlserver/jdbc/DataTypes.java index 19c6a64a2..66f71bac9 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/DataTypes.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/DataTypes.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -25,49 +22,49 @@ import java.util.EnumMap; import java.util.EnumSet; -enum TDSType -{ + +enum TDSType { // FIXEDLEN types - BIT1 (0x32), // 50 - INT8 (0x7F), // 127 - INT4 (0x38), // 56 - INT2 (0x34), // 52 - INT1 (0x30), // 48 - FLOAT4 (0x3B), // 59 - FLOAT8 (0x3E), // 62 - DATETIME4 (0x3A), // 58 - DATETIME8 (0x3D), // 61 - MONEY4 (0x7A), // 122 - MONEY8 (0x3C), // 60 + BIT1(0x32), // 50 + INT8(0x7F), // 127 + INT4(0x38), // 56 + INT2(0x34), // 52 + INT1(0x30), // 48 + FLOAT4(0x3B), // 59 + FLOAT8(0x3E), // 62 + DATETIME4(0x3A), // 58 + DATETIME8(0x3D), // 61 + MONEY4(0x7A), // 122 + MONEY8(0x3C), // 60 // BYTELEN types - BITN (0x68), // 104 - INTN (0x26), // 38 - DECIMALN (0x6A), // 106 - NUMERICN (0x6C), // 108 - FLOATN (0x6D), // 109 - MONEYN (0x6E), // 110 - DATETIMEN (0x6F), // 111 - GUID (0x24), // 36 - DATEN (0x28), // 40 - TIMEN (0x29), // 41 - DATETIME2N (0x2a), // 42 - DATETIMEOFFSETN (0x2b), // 43 + BITN(0x68), // 104 + INTN(0x26), // 38 + DECIMALN(0x6A), // 106 + NUMERICN(0x6C), // 108 + FLOATN(0x6D), // 109 + MONEYN(0x6E), // 110 + DATETIMEN(0x6F), // 111 + GUID(0x24), // 36 + DATEN(0x28), // 40 + TIMEN(0x29), // 41 + DATETIME2N(0x2a), // 42 + DATETIMEOFFSETN(0x2b), // 43 // USHORTLEN type - BIGCHAR (0xAF), // -81 - BIGVARCHAR (0xA7), // -89 - BIGBINARY (0xAD), // -83 - BIGVARBINARY (0xA5), // -91 - NCHAR (0xEF), // -17 - NVARCHAR (0xE7), // -15 + BIGCHAR(0xAF), // -81 + BIGVARCHAR(0xA7), // -89 + BIGBINARY(0xAD), // -83 + BIGVARBINARY(0xA5), // -91 + NCHAR(0xEF), // -17 + NVARCHAR(0xE7), // -15 // PARTLEN types - IMAGE (0x22), // 34 - TEXT (0x23), // 35 - NTEXT (0x63), // 99 - UDT (0xF0), // -16 - XML (0xF1), // -15 + IMAGE(0x22), // 34 + TEXT(0x23), // 35 + NTEXT(0x63), // 99 + UDT(0xF0), // -16 + XML(0xF1), // -15 // LONGLEN types SQL_VARIANT(0x62); // 98 @@ -103,8 +100,8 @@ static TDSType valueOf(int intValue) throws IllegalArgumentException { } } -enum SSLenType -{ + +enum SSLenType { FIXEDLENTYPE, BYTELENTYPE, USHORTLENTYPE, @@ -112,45 +109,45 @@ enum SSLenType PARTLENTYPE } -enum SSType -{ - UNKNOWN (Category.UNKNOWN, "unknown", JDBCType.UNKNOWN), - TINYINT (Category.NUMERIC, "tinyint", JDBCType.TINYINT), - BIT (Category.NUMERIC, "bit", JDBCType.BIT), - SMALLINT (Category.NUMERIC, "smallint", JDBCType.SMALLINT), - INTEGER (Category.NUMERIC, "int", JDBCType.INTEGER), - BIGINT (Category.NUMERIC, "bigint", JDBCType.BIGINT), - FLOAT (Category.NUMERIC, "float", JDBCType.DOUBLE), - REAL (Category.NUMERIC, "real", JDBCType.REAL), - SMALLDATETIME (Category.DATETIME, "smalldatetime", JDBCType.SMALLDATETIME), - DATETIME (Category.DATETIME, "datetime", JDBCType.DATETIME), - DATE (Category.DATE, "date", JDBCType.DATE), - TIME (Category.TIME, "time", JDBCType.TIME), - DATETIME2 (Category.DATETIME2, "datetime2", JDBCType.TIMESTAMP), - DATETIMEOFFSET (Category.DATETIMEOFFSET, "datetimeoffset", JDBCType.DATETIMEOFFSET), - SMALLMONEY (Category.NUMERIC, "smallmoney", JDBCType.SMALLMONEY), - MONEY (Category.NUMERIC, "money", JDBCType.MONEY), - CHAR (Category.CHARACTER, "char", JDBCType.CHAR), - VARCHAR (Category.CHARACTER, "varchar", JDBCType.VARCHAR), - VARCHARMAX (Category.LONG_CHARACTER, "varchar", JDBCType.LONGVARCHAR), - TEXT (Category.LONG_CHARACTER, "text", JDBCType.LONGVARCHAR), - NCHAR (Category.NCHARACTER, "nchar", JDBCType.NCHAR), - NVARCHAR (Category.NCHARACTER, "nvarchar", JDBCType.NVARCHAR), - NVARCHARMAX (Category.LONG_NCHARACTER, "nvarchar", JDBCType.LONGNVARCHAR), - NTEXT (Category.LONG_NCHARACTER, "ntext", JDBCType.LONGNVARCHAR), - BINARY (Category.BINARY, "binary", JDBCType.BINARY), - VARBINARY (Category.BINARY, "varbinary", JDBCType.VARBINARY), - VARBINARYMAX (Category.LONG_BINARY, "varbinary", JDBCType.LONGVARBINARY), - IMAGE (Category.LONG_BINARY, "image", JDBCType.LONGVARBINARY), - DECIMAL (Category.NUMERIC, "decimal", JDBCType.DECIMAL), - NUMERIC (Category.NUMERIC, "numeric", JDBCType.NUMERIC), - GUID (Category.GUID, "uniqueidentifier", JDBCType.GUID), - SQL_VARIANT (Category.SQL_VARIANT, "sql_variant", JDBCType.SQL_VARIANT), - UDT (Category.UDT, "udt", JDBCType.VARBINARY), - XML (Category.XML, "xml", JDBCType.LONGNVARCHAR), - TIMESTAMP (Category.TIMESTAMP, "timestamp", JDBCType.BINARY), - GEOMETRY (Category.UDT, "geometry", JDBCType.GEOMETRY), - GEOGRAPHY (Category.UDT, "geography", JDBCType.GEOGRAPHY); + +enum SSType { + UNKNOWN(Category.UNKNOWN, "unknown", JDBCType.UNKNOWN), + TINYINT(Category.NUMERIC, "tinyint", JDBCType.TINYINT), + BIT(Category.NUMERIC, "bit", JDBCType.BIT), + SMALLINT(Category.NUMERIC, "smallint", JDBCType.SMALLINT), + INTEGER(Category.NUMERIC, "int", JDBCType.INTEGER), + BIGINT(Category.NUMERIC, "bigint", JDBCType.BIGINT), + FLOAT(Category.NUMERIC, "float", JDBCType.DOUBLE), + REAL(Category.NUMERIC, "real", JDBCType.REAL), + SMALLDATETIME(Category.DATETIME, "smalldatetime", JDBCType.SMALLDATETIME), + DATETIME(Category.DATETIME, "datetime", JDBCType.DATETIME), + DATE(Category.DATE, "date", JDBCType.DATE), + TIME(Category.TIME, "time", JDBCType.TIME), + DATETIME2(Category.DATETIME2, "datetime2", JDBCType.TIMESTAMP), + DATETIMEOFFSET(Category.DATETIMEOFFSET, "datetimeoffset", JDBCType.DATETIMEOFFSET), + SMALLMONEY(Category.NUMERIC, "smallmoney", JDBCType.SMALLMONEY), + MONEY(Category.NUMERIC, "money", JDBCType.MONEY), + CHAR(Category.CHARACTER, "char", JDBCType.CHAR), + VARCHAR(Category.CHARACTER, "varchar", JDBCType.VARCHAR), + VARCHARMAX(Category.LONG_CHARACTER, "varchar", JDBCType.LONGVARCHAR), + TEXT(Category.LONG_CHARACTER, "text", JDBCType.LONGVARCHAR), + NCHAR(Category.NCHARACTER, "nchar", JDBCType.NCHAR), + NVARCHAR(Category.NCHARACTER, "nvarchar", JDBCType.NVARCHAR), + NVARCHARMAX(Category.LONG_NCHARACTER, "nvarchar", JDBCType.LONGNVARCHAR), + NTEXT(Category.LONG_NCHARACTER, "ntext", JDBCType.LONGNVARCHAR), + BINARY(Category.BINARY, "binary", JDBCType.BINARY), + VARBINARY(Category.BINARY, "varbinary", JDBCType.VARBINARY), + VARBINARYMAX(Category.LONG_BINARY, "varbinary", JDBCType.LONGVARBINARY), + IMAGE(Category.LONG_BINARY, "image", JDBCType.LONGVARBINARY), + DECIMAL(Category.NUMERIC, "decimal", JDBCType.DECIMAL), + NUMERIC(Category.NUMERIC, "numeric", JDBCType.NUMERIC), + GUID(Category.GUID, "uniqueidentifier", JDBCType.GUID), + SQL_VARIANT(Category.SQL_VARIANT, "sql_variant", JDBCType.SQL_VARIANT), + UDT(Category.UDT, "udt", JDBCType.VARBINARY), + XML(Category.XML, "xml", JDBCType.LONGNVARCHAR), + TIMESTAMP(Category.TIMESTAMP, "timestamp", JDBCType.BINARY), + GEOMETRY(Category.UDT, "geometry", JDBCType.GEOMETRY), + GEOGRAPHY(Category.UDT, "geography", JDBCType.GEOGRAPHY); final Category category; private final String name; @@ -161,9 +158,7 @@ enum SSType static final BigDecimal MAX_VALUE_SMALLMONEY = new BigDecimal("214748.3647"); static final BigDecimal MIN_VALUE_SMALLMONEY = new BigDecimal("-214748.3648"); - private SSType(Category category, - String name, - JDBCType jdbcType) { + private SSType(Category category, String name, JDBCType jdbcType) { this.category = category; this.name = name; this.jdbcType = jdbcType; @@ -209,179 +204,69 @@ enum Category { XML } - enum GetterConversion - { - NUMERIC ( - SSType.Category.NUMERIC, - EnumSet.of( - JDBCType.Category.NUMERIC, - JDBCType.Category.CHARACTER, + enum GetterConversion { + NUMERIC(SSType.Category.NUMERIC, EnumSet.of(JDBCType.Category.NUMERIC, JDBCType.Category.CHARACTER, JDBCType.Category.BINARY)), - DATETIME ( - SSType.Category.DATETIME, - EnumSet.of( - JDBCType.Category.DATE, - JDBCType.Category.TIME, - JDBCType.Category.TIMESTAMP, - JDBCType.Category.CHARACTER, - JDBCType.Category.BINARY)), + DATETIME(SSType.Category.DATETIME, EnumSet.of(JDBCType.Category.DATE, JDBCType.Category.TIME, + JDBCType.Category.TIMESTAMP, JDBCType.Category.CHARACTER, JDBCType.Category.BINARY)), - DATETIME2 ( - SSType.Category.DATETIME2, - EnumSet.of( - JDBCType.Category.DATE, - JDBCType.Category.TIME, - JDBCType.Category.TIMESTAMP, - JDBCType.Category.CHARACTER)), + DATETIME2(SSType.Category.DATETIME2, EnumSet.of(JDBCType.Category.DATE, JDBCType.Category.TIME, + JDBCType.Category.TIMESTAMP, JDBCType.Category.CHARACTER)), - DATE ( - SSType.Category.DATE, - EnumSet.of( - JDBCType.Category.DATE, - JDBCType.Category.TIMESTAMP, + DATE(SSType.Category.DATE, EnumSet.of(JDBCType.Category.DATE, JDBCType.Category.TIMESTAMP, JDBCType.Category.CHARACTER)), - TIME ( - SSType.Category.TIME, - EnumSet.of( - JDBCType.Category.TIME, - JDBCType.Category.TIMESTAMP, + TIME(SSType.Category.TIME, EnumSet.of(JDBCType.Category.TIME, JDBCType.Category.TIMESTAMP, JDBCType.Category.CHARACTER)), - DATETIMEOFFSET ( - SSType.Category.DATETIMEOFFSET, - EnumSet.of( - JDBCType.Category.DATE, - JDBCType.Category.TIME, - JDBCType.Category.TIMESTAMP, - JDBCType.Category.DATETIMEOFFSET, - JDBCType.Category.CHARACTER)), + DATETIMEOFFSET(SSType.Category.DATETIMEOFFSET, EnumSet.of(JDBCType.Category.DATE, JDBCType.Category.TIME, + JDBCType.Category.TIMESTAMP, JDBCType.Category.DATETIMEOFFSET, JDBCType.Category.CHARACTER)), - CHARACTER ( - SSType.Category.CHARACTER, - EnumSet.of( - JDBCType.Category.NUMERIC, - JDBCType.Category.DATE, - JDBCType.Category.TIME, - JDBCType.Category.TIMESTAMP, - JDBCType.Category.CHARACTER, - JDBCType.Category.LONG_CHARACTER, - JDBCType.Category.BINARY, - JDBCType.Category.GUID)), - - LONG_CHARACTER ( - SSType.Category.LONG_CHARACTER, - EnumSet.of( - JDBCType.Category.NUMERIC, - JDBCType.Category.DATE, - JDBCType.Category.TIME, - JDBCType.Category.TIMESTAMP, - JDBCType.Category.CHARACTER, - JDBCType.Category.LONG_CHARACTER, - JDBCType.Category.BINARY, - JDBCType.Category.CLOB)), - - NCHARACTER ( - SSType.Category.NCHARACTER, - EnumSet.of( - JDBCType.Category.NUMERIC, - JDBCType.Category.CHARACTER, - JDBCType.Category.LONG_CHARACTER, - JDBCType.Category.NCHARACTER, - JDBCType.Category.LONG_NCHARACTER, - JDBCType.Category.BINARY, - JDBCType.Category.DATE, - JDBCType.Category.TIME, - JDBCType.Category.TIMESTAMP)), - - LONG_NCHARACTER ( - SSType.Category.LONG_NCHARACTER, - EnumSet.of( - JDBCType.Category.NUMERIC, - JDBCType.Category.CHARACTER, - JDBCType.Category.LONG_CHARACTER, - JDBCType.Category.NCHARACTER, - JDBCType.Category.LONG_NCHARACTER, - JDBCType.Category.BINARY, - JDBCType.Category.DATE, - JDBCType.Category.TIME, - JDBCType.Category.TIMESTAMP, - JDBCType.Category.CLOB, - JDBCType.Category.NCLOB)), - - BINARY ( - SSType.Category.BINARY, - EnumSet.of( - JDBCType.Category.BINARY, - JDBCType.Category.LONG_BINARY, - JDBCType.Category.CHARACTER, - JDBCType.Category.LONG_CHARACTER, - JDBCType.Category.GUID)), - - LONG_BINARY ( - SSType.Category.LONG_BINARY, - EnumSet.of( - JDBCType.Category.BINARY, - JDBCType.Category.LONG_BINARY, - JDBCType.Category.CHARACTER, - JDBCType.Category.LONG_CHARACTER, - JDBCType.Category.BLOB)), - - TIMESTAMP ( - SSType.Category.TIMESTAMP, - EnumSet.of( - JDBCType.Category.BINARY, - JDBCType.Category.LONG_BINARY, - JDBCType.Category.CHARACTER)), + CHARACTER(SSType.Category.CHARACTER, EnumSet.of(JDBCType.Category.NUMERIC, JDBCType.Category.DATE, + JDBCType.Category.TIME, JDBCType.Category.TIMESTAMP, JDBCType.Category.CHARACTER, + JDBCType.Category.LONG_CHARACTER, JDBCType.Category.BINARY, JDBCType.Category.GUID)), + + LONG_CHARACTER(SSType.Category.LONG_CHARACTER, EnumSet.of(JDBCType.Category.NUMERIC, JDBCType.Category.DATE, + JDBCType.Category.TIME, JDBCType.Category.TIMESTAMP, JDBCType.Category.CHARACTER, + JDBCType.Category.LONG_CHARACTER, JDBCType.Category.BINARY, JDBCType.Category.CLOB)), - XML ( - SSType.Category.XML, - EnumSet.of( - JDBCType.Category.CHARACTER, - JDBCType.Category.LONG_CHARACTER, - JDBCType.Category.CLOB, - JDBCType.Category.NCHARACTER, - JDBCType.Category.LONG_NCHARACTER, - JDBCType.Category.NCLOB, - JDBCType.Category.BINARY, - JDBCType.Category.LONG_BINARY, - JDBCType.Category.BLOB, - JDBCType.Category.SQLXML)), - - UDT ( - SSType.Category.UDT, - EnumSet.of( - JDBCType.Category.BINARY, - JDBCType.Category.LONG_BINARY, - JDBCType.Category.CHARACTER, - JDBCType.Category.GEOMETRY, - JDBCType.Category.GEOGRAPHY)), - - GUID ( - SSType.Category.GUID, - EnumSet.of( - JDBCType.Category.BINARY, + NCHARACTER(SSType.Category.NCHARACTER, EnumSet.of(JDBCType.Category.NUMERIC, JDBCType.Category.CHARACTER, + JDBCType.Category.LONG_CHARACTER, JDBCType.Category.NCHARACTER, JDBCType.Category.LONG_NCHARACTER, + JDBCType.Category.BINARY, JDBCType.Category.DATE, JDBCType.Category.TIME, JDBCType.Category.TIMESTAMP)), + + LONG_NCHARACTER(SSType.Category.LONG_NCHARACTER, EnumSet.of(JDBCType.Category.NUMERIC, + JDBCType.Category.CHARACTER, JDBCType.Category.LONG_CHARACTER, JDBCType.Category.NCHARACTER, + JDBCType.Category.LONG_NCHARACTER, JDBCType.Category.BINARY, JDBCType.Category.DATE, + JDBCType.Category.TIME, JDBCType.Category.TIMESTAMP, JDBCType.Category.CLOB, JDBCType.Category.NCLOB)), + + BINARY(SSType.Category.BINARY, EnumSet.of(JDBCType.Category.BINARY, JDBCType.Category.LONG_BINARY, + JDBCType.Category.CHARACTER, JDBCType.Category.LONG_CHARACTER, JDBCType.Category.GUID)), + + LONG_BINARY(SSType.Category.LONG_BINARY, EnumSet.of(JDBCType.Category.BINARY, JDBCType.Category.LONG_BINARY, + JDBCType.Category.CHARACTER, JDBCType.Category.LONG_CHARACTER, JDBCType.Category.BLOB)), + + TIMESTAMP(SSType.Category.TIMESTAMP, EnumSet.of(JDBCType.Category.BINARY, JDBCType.Category.LONG_BINARY, JDBCType.Category.CHARACTER)), - - SQL_VARIANT ( - SSType.Category.SQL_VARIANT, - EnumSet.of( - JDBCType.Category.CHARACTER, - JDBCType.Category.SQL_VARIANT, - JDBCType.Category.NUMERIC, - JDBCType.Category.DATE, - JDBCType.Category.TIME, - JDBCType.Category.BINARY, - JDBCType.Category.TIMESTAMP, - JDBCType.Category.NCHARACTER, - JDBCType.Category.GUID)); + + XML(SSType.Category.XML, EnumSet.of(JDBCType.Category.CHARACTER, JDBCType.Category.LONG_CHARACTER, + JDBCType.Category.CLOB, JDBCType.Category.NCHARACTER, JDBCType.Category.LONG_NCHARACTER, + JDBCType.Category.NCLOB, JDBCType.Category.BINARY, JDBCType.Category.LONG_BINARY, + JDBCType.Category.BLOB, JDBCType.Category.SQLXML)), + + UDT(SSType.Category.UDT, EnumSet.of(JDBCType.Category.BINARY, JDBCType.Category.LONG_BINARY, + JDBCType.Category.CHARACTER, JDBCType.Category.GEOMETRY, JDBCType.Category.GEOGRAPHY)), + + GUID(SSType.Category.GUID, EnumSet.of(JDBCType.Category.BINARY, JDBCType.Category.CHARACTER)), + + SQL_VARIANT(SSType.Category.SQL_VARIANT, EnumSet.of(JDBCType.Category.CHARACTER, JDBCType.Category.SQL_VARIANT, + JDBCType.Category.NUMERIC, JDBCType.Category.DATE, JDBCType.Category.TIME, JDBCType.Category.BINARY, + JDBCType.Category.TIMESTAMP, JDBCType.Category.NCHARACTER, JDBCType.Category.GUID)); private final SSType.Category from; private final EnumSet to; - private GetterConversion(SSType.Category from, - EnumSet to) { + private GetterConversion(SSType.Category from, EnumSet to) { this.from = from; this.to = to; } @@ -397,8 +282,7 @@ private GetterConversion(SSType.Category from, conversionMap.get(conversion.from).addAll(conversion.to); } - static final boolean converts(SSType fromSSType, - JDBCType toJDBCType) { + static final boolean converts(SSType fromSSType, JDBCType toJDBCType) { return conversionMap.get(fromSSType.category).contains(toJDBCType.category); } } @@ -408,14 +292,14 @@ boolean convertsTo(JDBCType jdbcType) { } } -enum StreamType -{ - NONE (JDBCType.UNKNOWN, "None"), - ASCII (JDBCType.LONGVARCHAR, "AsciiStream"), - BINARY (JDBCType.LONGVARBINARY, "BinaryStream"), - CHARACTER (JDBCType.LONGVARCHAR, "CharacterStream"), - NCHARACTER (JDBCType.LONGNVARCHAR, "NCharacterStream"), - SQLXML (JDBCType.SQLXML, "SQLXML"); + +enum StreamType { + NONE(JDBCType.UNKNOWN, "None"), + ASCII(JDBCType.LONGVARCHAR, "AsciiStream"), + BINARY(JDBCType.LONGVARBINARY, "BinaryStream"), + CHARACTER(JDBCType.LONGVARCHAR, "CharacterStream"), + NCHARACTER(JDBCType.LONGNVARCHAR, "NCharacterStream"), + SQLXML(JDBCType.SQLXML, "SQLXML"); // JDBC type most naturally associated with this type of stream private final JDBCType jdbcType; @@ -427,8 +311,7 @@ JDBCType getJDBCType() { // Display string to use when describing this stream type in traces and error messages private final String name; - private StreamType(JDBCType jdbcType, - String name) { + private StreamType(JDBCType jdbcType, String name) { this.jdbcType = jdbcType; this.name = name; } @@ -468,26 +351,26 @@ boolean convertsTo(TypeInfo typeInfo) { } } + final class UserTypes { /* System defined UDTs */ static final int TIMESTAMP = 0x0050; - private UserTypes() { - } // prevent instantiation + private UserTypes() {} // prevent instantiation } + /** * Java class types that may be used as parameter or column values. * - * Explicit external representation of the Java types eliminates multiple expensive calls to Class.isInstance (from DTV and elsewhere) where the Java - * type of a parameter or column value needs to be known. + * Explicit external representation of the Java types eliminates multiple expensive calls to Class.isInstance (from DTV + * and elsewhere) where the Java type of a parameter or column value needs to be known. * - * !! IMPORTANT !! The tradeoff of using an external representation is that the driver must ensure that the JavaType always reflects the Java type of - * the object instance, so as a general rule, any code that passes Object instances around where the type must be later known, should always pass a - * JavaType as well. + * !! IMPORTANT !! The tradeoff of using an external representation is that the driver must ensure that the JavaType + * always reflects the Java type of the object instance, so as a general rule, any code that passes Object instances + * around where the type must be later known, should always pass a JavaType as well. */ -enum JavaType -{ +enum JavaType { // !! IMPORTANT !! // JavaType enumeration constants are arranged in the order checked // when determining the type of an arbitrary Object instance. @@ -505,38 +388,37 @@ enum JavaType // // 3. The last constant must be for the Object class to ensure that every // type of Object maps to some JavaType. - INTEGER (Integer.class, JDBCType.INTEGER), - STRING (String.class, JDBCType.CHAR), - DATE (java.sql.Date.class, JDBCType.DATE), - TIME (java.sql.Time.class, JDBCType.TIME), - TIMESTAMP (java.sql.Timestamp.class, JDBCType.TIMESTAMP), - UTILDATE (java.util.Date.class, JDBCType.TIMESTAMP), - CALENDAR (java.util.Calendar.class, JDBCType.TIMESTAMP), - LOCALDATE (getJavaClass("LocalDate"), JDBCType.DATE), - LOCALTIME (getJavaClass("LocalTime"), JDBCType.TIME), - LOCALDATETIME (getJavaClass("LocalDateTime"), JDBCType.TIMESTAMP), - OFFSETTIME (getJavaClass("OffsetTime"), JDBCType.TIME_WITH_TIMEZONE), - OFFSETDATETIME (getJavaClass("OffsetDateTime"), JDBCType.TIMESTAMP_WITH_TIMEZONE), - DATETIMEOFFSET (microsoft.sql.DateTimeOffset.class, JDBCType.DATETIMEOFFSET), - BOOLEAN (Boolean.class, JDBCType.BIT), - BIGDECIMAL (BigDecimal.class, JDBCType.DECIMAL), - DOUBLE (Double.class, JDBCType.DOUBLE), - FLOAT (Float.class, JDBCType.REAL), - SHORT (Short.class, JDBCType.SMALLINT), - LONG (Long.class, JDBCType.BIGINT), - BIGINTEGER (BigInteger.class, JDBCType.BIGINT), - BYTE (Byte.class, JDBCType.TINYINT), - BYTEARRAY (byte[].class, JDBCType.BINARY), + INTEGER(Integer.class, JDBCType.INTEGER), + STRING(String.class, JDBCType.CHAR), + DATE(java.sql.Date.class, JDBCType.DATE), + TIME(java.sql.Time.class, JDBCType.TIME), + TIMESTAMP(java.sql.Timestamp.class, JDBCType.TIMESTAMP), + UTILDATE(java.util.Date.class, JDBCType.TIMESTAMP), + CALENDAR(java.util.Calendar.class, JDBCType.TIMESTAMP), + LOCALDATE(getJavaClass("LocalDate"), JDBCType.DATE), + LOCALTIME(getJavaClass("LocalTime"), JDBCType.TIME), + LOCALDATETIME(getJavaClass("LocalDateTime"), JDBCType.TIMESTAMP), + OFFSETTIME(getJavaClass("OffsetTime"), JDBCType.TIME_WITH_TIMEZONE), + OFFSETDATETIME(getJavaClass("OffsetDateTime"), JDBCType.TIMESTAMP_WITH_TIMEZONE), + DATETIMEOFFSET(microsoft.sql.DateTimeOffset.class, JDBCType.DATETIMEOFFSET), + BOOLEAN(Boolean.class, JDBCType.BIT), + BIGDECIMAL(BigDecimal.class, JDBCType.DECIMAL), + DOUBLE(Double.class, JDBCType.DOUBLE), + FLOAT(Float.class, JDBCType.REAL), + SHORT(Short.class, JDBCType.SMALLINT), + LONG(Long.class, JDBCType.BIGINT), + BIGINTEGER(BigInteger.class, JDBCType.BIGINT), + BYTE(Byte.class, JDBCType.TINYINT), + BYTEARRAY(byte[].class, JDBCType.BINARY), // Check for NClob before checking for Clob, since NClob IS A Clob - NCLOB (NClob.class, JDBCType.NCLOB), - CLOB (Clob.class, JDBCType.CLOB), - BLOB (Blob.class, JDBCType.BLOB), - TVP (com.microsoft.sqlserver.jdbc.TVP.class, JDBCType.TVP), - + NCLOB(NClob.class, JDBCType.NCLOB), + CLOB(Clob.class, JDBCType.CLOB), + BLOB(Blob.class, JDBCType.BLOB), + TVP(com.microsoft.sqlserver.jdbc.TVP.class, JDBCType.TVP), + INPUTSTREAM(InputStream.class, JDBCType.UNKNOWN) { // InputStreams are either ASCII or binary - JDBCType getJDBCType(SSType ssType, - JDBCType jdbcTypeFromApp) { + JDBCType getJDBCType(SSType ssType, JDBCType jdbcTypeFromApp) { JDBCType jdbcType; // When the backend type is known, the JDBC type is unknown. @@ -581,17 +463,16 @@ JDBCType getJDBCType(SSType ssType, } }, - READER (Reader.class, JDBCType.LONGVARCHAR), + READER(Reader.class, JDBCType.LONGVARCHAR), // Note: Only SQLServerSQLXML SQLXML instances are accepted by this driver - SQLXML (SQLServerSQLXML.class, JDBCType.SQLXML), - OBJECT (Object.class, JDBCType.UNKNOWN); + SQLXML(SQLServerSQLXML.class, JDBCType.SQLXML), + OBJECT(Object.class, JDBCType.UNKNOWN); private final Class javaClass; private final JDBCType jdbcTypeFromJavaType; private static double jvmVersion = 0.0; - private JavaType(Class javaClass, - JDBCType jdbcTypeFromJavaType) { + private JavaType(Class javaClass, JDBCType jdbcTypeFromJavaType) { this.javaClass = javaClass; this.jdbcTypeFromJavaType = jdbcTypeFromJavaType; } @@ -600,15 +481,15 @@ static Class getJavaClass(String className) { if (0.0 == jvmVersion) { try { /* - * Note: getProperty could throw a SecurityException if there is a security manager that doesn't allow checkPropertyAccess. Unlikely - * to happen & doesn't appear to be a graceful way to handle so will let that exception through. + * Note: getProperty could throw a SecurityException if there is a security manager that doesn't allow + * checkPropertyAccess. Unlikely to happen & doesn't appear to be a graceful way to handle so will let + * that exception through. */ String jvmSpecVersion = System.getProperty("java.specification.version"); if (jvmSpecVersion != null) { jvmVersion = Double.parseDouble(jvmSpecVersion); } - } - catch (NumberFormatException e) { + } catch (NumberFormatException e) { // Setting the version to be less that 1.8 so we don't try to set every time. jvmVersion = 0.1; } @@ -650,132 +531,53 @@ static JavaType of(Object obj) { return JavaType.OBJECT; } - // Retrieve JDBC to use with this Java type. By default we use the static JDBC type - // associated with the Java type, ignoring the JDBC type specified by the application. - // But this behavior is overridden for certain Java types, like InputStream, which - // require the JDBC type to be specified externally to be able to distinguish between - // ASCII and binary streams. - JDBCType getJDBCType(SSType ssType, - JDBCType jdbcTypeFromApp) { + /** + * Returns the JDBC type to use with this Java type. We use the static JDBC type associated with the Java type by + * default, ignoring the JDBC type specified by the application. This behavior is overridden for certain Java types, + * such as InputStream, which requires the JDBC type to be specified externally in order to distinguish between. + */ + JDBCType getJDBCType(SSType ssType, JDBCType jdbcTypeFromApp) { return jdbcTypeFromJavaType; } - - enum SetterConversionAE - { - BIT ( - JavaType.BOOLEAN, - EnumSet.of( - JDBCType.BIT, - JDBCType.TINYINT, - JDBCType.SMALLINT, - JDBCType.INTEGER, - JDBCType.BIGINT - )), - - SHORT ( - JavaType.SHORT, - EnumSet.of( - JDBCType.TINYINT, - JDBCType.SMALLINT, - JDBCType.INTEGER, - JDBCType.BIGINT - )), - - INTEGER ( - JavaType.INTEGER, - EnumSet.of( - JDBCType.INTEGER, - JDBCType.BIGINT - )), - LONG ( - JavaType.LONG, - EnumSet.of( - JDBCType.BIGINT - )), - - BIGDECIMAL ( - JavaType.BIGDECIMAL, - EnumSet.of( - JDBCType.MONEY, - JDBCType.SMALLMONEY, - JDBCType.DECIMAL, - JDBCType.NUMERIC - )), - - BYTE ( - JavaType.BYTE, - EnumSet.of( - JDBCType.BINARY, - JDBCType.VARBINARY, - JDBCType.LONGVARBINARY, - JDBCType.TINYINT - )), - - BYTEARRAY ( - JavaType.BYTEARRAY, - EnumSet.of( - JDBCType.BINARY, - JDBCType.VARBINARY, - JDBCType.LONGVARBINARY - )), - - DATE ( - JavaType.DATE, - EnumSet.of( - JDBCType.DATE - )), - - DATETIMEOFFSET ( - JavaType.DATETIMEOFFSET, - EnumSet.of( - JDBCType.DATETIMEOFFSET - )), - - DOUBLE ( - JavaType.DOUBLE, - EnumSet.of( - JDBCType.DOUBLE - )), - - FLOAT ( - JavaType.FLOAT, - EnumSet.of( - JDBCType.REAL, - JDBCType.DOUBLE - )), - - STRING ( - JavaType.STRING, - EnumSet.of( - JDBCType.CHAR, - JDBCType.VARCHAR, - JDBCType.LONGVARCHAR, - JDBCType.NCHAR, - JDBCType.NVARCHAR, - JDBCType.LONGNVARCHAR, - JDBCType.GUID - )), - - TIME ( - JavaType.TIME, - EnumSet.of( - JDBCType.TIME - )), - - TIMESTAMP ( - JavaType.TIMESTAMP, - EnumSet.of( - JDBCType.TIME,// This is needed to send nanoseconds to the driver as setTime() is only milliseconds - JDBCType.TIMESTAMP, // This is datetime2 - JDBCType.DATETIME, - JDBCType.SMALLDATETIME - )); + + enum SetterConversionAE { + BIT(JavaType.BOOLEAN, EnumSet.of(JDBCType.BIT, JDBCType.TINYINT, JDBCType.SMALLINT, JDBCType.INTEGER, + JDBCType.BIGINT)), + + SHORT(JavaType.SHORT, EnumSet.of(JDBCType.TINYINT, JDBCType.SMALLINT, JDBCType.INTEGER, JDBCType.BIGINT)), + + INTEGER(JavaType.INTEGER, EnumSet.of(JDBCType.INTEGER, JDBCType.BIGINT)), + LONG(JavaType.LONG, EnumSet.of(JDBCType.BIGINT)), + + BIGDECIMAL(JavaType.BIGDECIMAL, EnumSet.of(JDBCType.MONEY, JDBCType.SMALLMONEY, JDBCType.DECIMAL, + JDBCType.NUMERIC)), + + BYTE(JavaType.BYTE, EnumSet.of(JDBCType.BINARY, JDBCType.VARBINARY, JDBCType.LONGVARBINARY, JDBCType.TINYINT)), + + BYTEARRAY(JavaType.BYTEARRAY, EnumSet.of(JDBCType.BINARY, JDBCType.VARBINARY, JDBCType.LONGVARBINARY)), + + DATE(JavaType.DATE, EnumSet.of(JDBCType.DATE)), + + DATETIMEOFFSET(JavaType.DATETIMEOFFSET, EnumSet.of(JDBCType.DATETIMEOFFSET)), + + DOUBLE(JavaType.DOUBLE, EnumSet.of(JDBCType.DOUBLE)), + + FLOAT(JavaType.FLOAT, EnumSet.of(JDBCType.REAL, JDBCType.DOUBLE)), + + STRING(JavaType.STRING, EnumSet.of(JDBCType.CHAR, JDBCType.VARCHAR, JDBCType.LONGVARCHAR, JDBCType.NCHAR, + JDBCType.NVARCHAR, JDBCType.LONGNVARCHAR, JDBCType.GUID)), + + TIME(JavaType.TIME, EnumSet.of(JDBCType.TIME)), + + TIMESTAMP(JavaType.TIMESTAMP, EnumSet.of(JDBCType.TIME, // This is needed to send nanoseconds to the driver as + // setTime() is only milliseconds + JDBCType.TIMESTAMP, // This is datetime2 + JDBCType.DATETIME, JDBCType.SMALLDATETIME)); private final EnumSet to; private final JavaType from; - private SetterConversionAE(JavaType from, - EnumSet to) { + private SetterConversionAE(JavaType from, EnumSet to) { this.from = from; this.to = to; } @@ -790,19 +592,17 @@ private SetterConversionAE(JavaType from, setterConversionAEMap.get(conversion.from).addAll(conversion.to); } - static boolean converts(JavaType fromJavaType, - JDBCType toJDBCType, - Boolean sendStringParametersAsUnicode) { + static boolean converts(JavaType fromJavaType, JDBCType toJDBCType, Boolean sendStringParametersAsUnicode) { if ((null == fromJavaType) || (JavaType.OBJECT == fromJavaType)) return true; else if (!sendStringParametersAsUnicode && fromJavaType == JavaType.BYTEARRAY - && (toJDBCType == JDBCType.VARCHAR || toJDBCType == JDBCType.CHAR || toJDBCType == JDBCType.LONGVARCHAR)) { + && (toJDBCType == JDBCType.VARCHAR || toJDBCType == JDBCType.CHAR + || toJDBCType == JDBCType.LONGVARCHAR)) { // when column is encrypted and sendStringParametersAsUnicode is false, // does not throw exception if the column is char/varchar/varcharmax, // in order to allow send char/varchar/varcharmax as MBCS (BYTEARRAY type) return true; - } - else if (!setterConversionAEMap.containsKey(fromJavaType)) + } else if (!setterConversionAEMap.containsKey(fromJavaType)) return false; return setterConversionAEMap.get(fromJavaType).contains(toJDBCType); } @@ -810,60 +610,57 @@ else if (!setterConversionAEMap.containsKey(fromJavaType)) } -enum JDBCType -{ - UNKNOWN (Category.UNKNOWN, 999, "java.lang.Object"), - ARRAY (Category.UNKNOWN, java.sql.Types.ARRAY, "java.lang.Object"), - BIGINT (Category.NUMERIC, java.sql.Types.BIGINT, "java.lang.Long"), - BINARY (Category.BINARY, java.sql.Types.BINARY, "[B"), - BIT (Category.NUMERIC, java.sql.Types.BIT, "java.lang.Boolean"), - BLOB (Category.BLOB, java.sql.Types.BLOB, "java.sql.Blob"), - BOOLEAN (Category.NUMERIC, java.sql.Types.BOOLEAN, "java.lang.Boolean"), - CHAR (Category.CHARACTER, java.sql.Types.CHAR, "java.lang.String"), - CLOB (Category.CLOB, java.sql.Types.CLOB, "java.sql.Clob"), - DATALINK (Category.UNKNOWN, java.sql.Types.DATALINK, "java.lang.Object"), - DATE (Category.DATE, java.sql.Types.DATE, "java.sql.Date"), - DATETIMEOFFSET(Category.DATETIMEOFFSET, microsoft.sql.Types.DATETIMEOFFSET, "microsoft.sql.DateTimeOffset"), - DECIMAL (Category.NUMERIC, java.sql.Types.DECIMAL, "java.math.BigDecimal"), - DISTINCT (Category.UNKNOWN, java.sql.Types.DISTINCT, "java.lang.Object"), - DOUBLE (Category.NUMERIC, java.sql.Types.DOUBLE, "java.lang.Double"), - FLOAT (Category.NUMERIC, java.sql.Types.FLOAT, "java.lang.Double"), - INTEGER (Category.NUMERIC, java.sql.Types.INTEGER, "java.lang.Integer"), - JAVA_OBJECT (Category.UNKNOWN, java.sql.Types.JAVA_OBJECT, "java.lang.Object"), - LONGNVARCHAR (Category.LONG_NCHARACTER, -16, "java.lang.String"), - LONGVARBINARY (Category.LONG_BINARY, java.sql.Types.LONGVARBINARY, "[B"), - LONGVARCHAR (Category.LONG_CHARACTER, java.sql.Types.LONGVARCHAR, "java.lang.String"), - NCHAR (Category.NCHARACTER, -15, "java.lang.String"), - NCLOB (Category.NCLOB, 2011, "java.sql.NClob"), - NULL (Category.UNKNOWN, java.sql.Types.NULL, "java.lang.Object"), - NUMERIC (Category.NUMERIC, java.sql.Types.NUMERIC, "java.math.BigDecimal"), - NVARCHAR (Category.NCHARACTER, -9, "java.lang.String"), - OTHER (Category.UNKNOWN, java.sql.Types.OTHER, "java.lang.Object"), - REAL (Category.NUMERIC, java.sql.Types.REAL, "java.lang.Float"), - REF (Category.UNKNOWN, java.sql.Types.REF, "java.lang.Object"), - ROWID (Category.UNKNOWN, -8, "java.lang.Object"), - SMALLINT (Category.NUMERIC, java.sql.Types.SMALLINT, "java.lang.Short"), - SQLXML (Category.SQLXML, 2009, "java.lang.Object"), - STRUCT (Category.UNKNOWN, java.sql.Types.STRUCT, "java.lang.Object"), - TIME (Category.TIME, java.sql.Types.TIME, "java.sql.Time"), - TIME_WITH_TIMEZONE - (Category.TIME_WITH_TIMEZONE, 2013, "java.time.OffsetTime"), - TIMESTAMP (Category.TIMESTAMP, java.sql.Types.TIMESTAMP, "java.sql.Timestamp"), - TIMESTAMP_WITH_TIMEZONE - (Category.TIMESTAMP_WITH_TIMEZONE, 2014, "java.time.OffsetDateTime"), - TINYINT (Category.NUMERIC, java.sql.Types.TINYINT, "java.lang.Short"), - VARBINARY (Category.BINARY, java.sql.Types.VARBINARY, "[B"), - VARCHAR (Category.CHARACTER, java.sql.Types.VARCHAR, "java.lang.String"), - MONEY (Category.NUMERIC, microsoft.sql.Types.MONEY, "java.math.BigDecimal"), - SMALLMONEY (Category.NUMERIC, microsoft.sql.Types.SMALLMONEY, "java.math.BigDecimal"), - TVP (Category.TVP, microsoft.sql.Types.STRUCTURED, "java.lang.Object"), - DATETIME (Category.TIMESTAMP, microsoft.sql.Types.DATETIME, "java.sql.Timestamp"), - SMALLDATETIME (Category.TIMESTAMP, microsoft.sql.Types.SMALLDATETIME, "java.sql.Timestamp"), - GUID (Category.CHARACTER, microsoft.sql.Types.GUID, "java.lang.String"), - SQL_VARIANT (Category.SQL_VARIANT, microsoft.sql.Types.SQL_VARIANT, "java.lang.Object"), - GEOMETRY (Category.GEOMETRY, microsoft.sql.Types.GEOMETRY, "java.lang.Object"), - GEOGRAPHY (Category.GEOGRAPHY, microsoft.sql.Types.GEOGRAPHY, "java.lang.Object"); +enum JDBCType { + UNKNOWN(Category.UNKNOWN, 999, "java.lang.Object"), + ARRAY(Category.UNKNOWN, java.sql.Types.ARRAY, "java.lang.Object"), + BIGINT(Category.NUMERIC, java.sql.Types.BIGINT, "java.lang.Long"), + BINARY(Category.BINARY, java.sql.Types.BINARY, "[B"), + BIT(Category.NUMERIC, java.sql.Types.BIT, "java.lang.Boolean"), + BLOB(Category.BLOB, java.sql.Types.BLOB, "java.sql.Blob"), + BOOLEAN(Category.NUMERIC, java.sql.Types.BOOLEAN, "java.lang.Boolean"), + CHAR(Category.CHARACTER, java.sql.Types.CHAR, "java.lang.String"), + CLOB(Category.CLOB, java.sql.Types.CLOB, "java.sql.Clob"), + DATALINK(Category.UNKNOWN, java.sql.Types.DATALINK, "java.lang.Object"), + DATE(Category.DATE, java.sql.Types.DATE, "java.sql.Date"), + DATETIMEOFFSET(Category.DATETIMEOFFSET, microsoft.sql.Types.DATETIMEOFFSET, "microsoft.sql.DateTimeOffset"), + DECIMAL(Category.NUMERIC, java.sql.Types.DECIMAL, "java.math.BigDecimal"), + DISTINCT(Category.UNKNOWN, java.sql.Types.DISTINCT, "java.lang.Object"), + DOUBLE(Category.NUMERIC, java.sql.Types.DOUBLE, "java.lang.Double"), + FLOAT(Category.NUMERIC, java.sql.Types.FLOAT, "java.lang.Double"), + INTEGER(Category.NUMERIC, java.sql.Types.INTEGER, "java.lang.Integer"), + JAVA_OBJECT(Category.UNKNOWN, java.sql.Types.JAVA_OBJECT, "java.lang.Object"), + LONGNVARCHAR(Category.LONG_NCHARACTER, -16, "java.lang.String"), + LONGVARBINARY(Category.LONG_BINARY, java.sql.Types.LONGVARBINARY, "[B"), + LONGVARCHAR(Category.LONG_CHARACTER, java.sql.Types.LONGVARCHAR, "java.lang.String"), + NCHAR(Category.NCHARACTER, -15, "java.lang.String"), + NCLOB(Category.NCLOB, 2011, "java.sql.NClob"), + NULL(Category.UNKNOWN, java.sql.Types.NULL, "java.lang.Object"), + NUMERIC(Category.NUMERIC, java.sql.Types.NUMERIC, "java.math.BigDecimal"), + NVARCHAR(Category.NCHARACTER, -9, "java.lang.String"), + OTHER(Category.UNKNOWN, java.sql.Types.OTHER, "java.lang.Object"), + REAL(Category.NUMERIC, java.sql.Types.REAL, "java.lang.Float"), + REF(Category.UNKNOWN, java.sql.Types.REF, "java.lang.Object"), + ROWID(Category.UNKNOWN, -8, "java.lang.Object"), + SMALLINT(Category.NUMERIC, java.sql.Types.SMALLINT, "java.lang.Short"), + SQLXML(Category.SQLXML, 2009, "java.lang.Object"), + STRUCT(Category.UNKNOWN, java.sql.Types.STRUCT, "java.lang.Object"), + TIME(Category.TIME, java.sql.Types.TIME, "java.sql.Time"), + TIME_WITH_TIMEZONE(Category.TIME_WITH_TIMEZONE, 2013, "java.time.OffsetTime"), + TIMESTAMP(Category.TIMESTAMP, java.sql.Types.TIMESTAMP, "java.sql.Timestamp"), + TIMESTAMP_WITH_TIMEZONE(Category.TIMESTAMP_WITH_TIMEZONE, 2014, "java.time.OffsetDateTime"), + TINYINT(Category.NUMERIC, java.sql.Types.TINYINT, "java.lang.Short"), + VARBINARY(Category.BINARY, java.sql.Types.VARBINARY, "[B"), + VARCHAR(Category.CHARACTER, java.sql.Types.VARCHAR, "java.lang.String"), + MONEY(Category.NUMERIC, microsoft.sql.Types.MONEY, "java.math.BigDecimal"), + SMALLMONEY(Category.NUMERIC, microsoft.sql.Types.SMALLMONEY, "java.math.BigDecimal"), + TVP(Category.TVP, microsoft.sql.Types.STRUCTURED, "java.lang.Object"), + DATETIME(Category.TIMESTAMP, microsoft.sql.Types.DATETIME, "java.sql.Timestamp"), + SMALLDATETIME(Category.TIMESTAMP, microsoft.sql.Types.SMALLDATETIME, "java.sql.Timestamp"), + GUID(Category.CHARACTER, microsoft.sql.Types.GUID, "java.lang.String"), + SQL_VARIANT(Category.SQL_VARIANT, microsoft.sql.Types.SQL_VARIANT, "java.lang.Object"), + GEOMETRY(Category.GEOMETRY, microsoft.sql.Types.GEOMETRY, "java.lang.Object"), + GEOGRAPHY(Category.GEOGRAPHY, microsoft.sql.Types.GEOGRAPHY, "java.lang.Object"); final Category category; private final int intValue; @@ -873,23 +670,21 @@ final String className() { return className; } - private JDBCType(Category category, - int intValue, - String className) { + private JDBCType(Category category, int intValue, String className) { this.category = category; this.intValue = intValue; this.className = className; } /** - * Gets the integer value of JDBCType + * Returns the integer value of JDBCType. * * @return integer representation of JDBCType */ public int getIntValue() { return this.intValue; } - + enum Category { CHARACTER, LONG_CHARACTER, @@ -918,178 +713,74 @@ enum Category { // This SetterConversion enum is based on the Category enum enum SetterConversion { - CHARACTER ( - JDBCType.Category.CHARACTER, - EnumSet.of( - JDBCType.Category.NUMERIC, - JDBCType.Category.DATE, - JDBCType.Category.TIME, - JDBCType.Category.TIMESTAMP, - JDBCType.Category.DATETIMEOFFSET, - JDBCType.Category.CHARACTER, - JDBCType.Category.LONG_CHARACTER, - JDBCType.Category.NCHARACTER, - JDBCType.Category.LONG_NCHARACTER, - JDBCType.Category.BINARY, - JDBCType.Category.LONG_BINARY, - JDBCType.Category.GUID, - JDBCType.Category.SQL_VARIANT)), + CHARACTER(JDBCType.Category.CHARACTER, EnumSet.of(JDBCType.Category.NUMERIC, JDBCType.Category.DATE, + JDBCType.Category.TIME, JDBCType.Category.TIMESTAMP, JDBCType.Category.DATETIMEOFFSET, + JDBCType.Category.CHARACTER, JDBCType.Category.LONG_CHARACTER, JDBCType.Category.NCHARACTER, + JDBCType.Category.LONG_NCHARACTER, JDBCType.Category.BINARY, JDBCType.Category.LONG_BINARY, + JDBCType.Category.GUID, JDBCType.Category.SQL_VARIANT)), + + LONG_CHARACTER(JDBCType.Category.LONG_CHARACTER, EnumSet.of(JDBCType.Category.CHARACTER, + JDBCType.Category.LONG_CHARACTER, JDBCType.Category.NCHARACTER, JDBCType.Category.LONG_NCHARACTER, + JDBCType.Category.BINARY, JDBCType.Category.LONG_BINARY)), - LONG_CHARACTER ( - JDBCType.Category.LONG_CHARACTER, - EnumSet.of( - JDBCType.Category.CHARACTER, - JDBCType.Category.LONG_CHARACTER, - JDBCType.Category.NCHARACTER, - JDBCType.Category.LONG_NCHARACTER, - JDBCType.Category.BINARY, - JDBCType.Category.LONG_BINARY)), - - CLOB ( - JDBCType.Category.CLOB, - EnumSet.of( - JDBCType.Category.CLOB, - JDBCType.Category.LONG_CHARACTER, + CLOB(JDBCType.Category.CLOB, EnumSet.of(JDBCType.Category.CLOB, JDBCType.Category.LONG_CHARACTER, JDBCType.Category.LONG_NCHARACTER)), - NCHARACTER ( - JDBCType.Category.NCHARACTER, - EnumSet.of( - JDBCType.Category.NCHARACTER, - JDBCType.Category.LONG_NCHARACTER, - JDBCType.Category.NCLOB, - JDBCType.Category.SQL_VARIANT)), + NCHARACTER(JDBCType.Category.NCHARACTER, EnumSet.of(JDBCType.Category.NCHARACTER, + JDBCType.Category.LONG_NCHARACTER, JDBCType.Category.NCLOB, JDBCType.Category.SQL_VARIANT)), - LONG_NCHARACTER ( - JDBCType.Category.LONG_NCHARACTER, - EnumSet.of( - JDBCType.Category.NCHARACTER, + LONG_NCHARACTER(JDBCType.Category.LONG_NCHARACTER, EnumSet.of(JDBCType.Category.NCHARACTER, JDBCType.Category.LONG_NCHARACTER)), - NCLOB ( - JDBCType.Category.NCLOB, - EnumSet.of( - JDBCType.Category.LONG_NCHARACTER, - JDBCType.Category.NCLOB)), - - BINARY ( - JDBCType.Category.BINARY, - EnumSet.of( - JDBCType.Category.NUMERIC, - JDBCType.Category.DATE, - JDBCType.Category.TIME, - JDBCType.Category.TIMESTAMP, - JDBCType.Category.CHARACTER, - JDBCType.Category.LONG_CHARACTER, - JDBCType.Category.NCHARACTER, - JDBCType.Category.LONG_NCHARACTER, - JDBCType.Category.BINARY, - JDBCType.Category.LONG_BINARY, - JDBCType.Category.BLOB, - JDBCType.Category.GUID, + NCLOB(JDBCType.Category.NCLOB, EnumSet.of(JDBCType.Category.LONG_NCHARACTER, JDBCType.Category.NCLOB)), + + BINARY(JDBCType.Category.BINARY, EnumSet.of(JDBCType.Category.NUMERIC, JDBCType.Category.DATE, + JDBCType.Category.TIME, JDBCType.Category.TIMESTAMP, JDBCType.Category.CHARACTER, + JDBCType.Category.LONG_CHARACTER, JDBCType.Category.NCHARACTER, JDBCType.Category.LONG_NCHARACTER, + JDBCType.Category.BINARY, JDBCType.Category.LONG_BINARY, JDBCType.Category.BLOB, JDBCType.Category.GUID, + JDBCType.Category.SQL_VARIANT)), + + LONG_BINARY(JDBCType.Category.LONG_BINARY, EnumSet.of(JDBCType.Category.BINARY, JDBCType.Category.LONG_BINARY)), + + BLOB(JDBCType.Category.BLOB, EnumSet.of(JDBCType.Category.LONG_BINARY, JDBCType.Category.BLOB)), + + NUMERIC(JDBCType.Category.NUMERIC, EnumSet.of(JDBCType.Category.NUMERIC, JDBCType.Category.CHARACTER, + JDBCType.Category.LONG_CHARACTER, JDBCType.Category.NCHARACTER, JDBCType.Category.LONG_NCHARACTER, JDBCType.Category.SQL_VARIANT)), - - LONG_BINARY ( - JDBCType.Category.LONG_BINARY, - EnumSet.of( - JDBCType.Category.BINARY, - JDBCType.Category.LONG_BINARY)), - - BLOB ( - JDBCType.Category.BLOB, - EnumSet.of( - JDBCType.Category.LONG_BINARY, - JDBCType.Category.BLOB)), - - NUMERIC ( - JDBCType.Category.NUMERIC, - EnumSet.of( - JDBCType.Category.NUMERIC, - JDBCType.Category.CHARACTER, - JDBCType.Category.LONG_CHARACTER, - JDBCType.Category.NCHARACTER, - JDBCType.Category.LONG_NCHARACTER, - JDBCType.Category.SQL_VARIANT)), - - DATE ( - JDBCType.Category.DATE, - EnumSet.of( - JDBCType.Category.DATE, - JDBCType.Category.TIMESTAMP, - JDBCType.Category.DATETIMEOFFSET, - JDBCType.Category.CHARACTER, - JDBCType.Category.LONG_CHARACTER, - JDBCType.Category.NCHARACTER, - JDBCType.Category.LONG_NCHARACTER, - JDBCType.Category.SQL_VARIANT)), - - TIME ( - JDBCType.Category.TIME, - EnumSet.of( - JDBCType.Category.TIME, - JDBCType.Category.TIMESTAMP, - JDBCType.Category.DATETIMEOFFSET, - JDBCType.Category.CHARACTER, - JDBCType.Category.LONG_CHARACTER, - JDBCType.Category.NCHARACTER, - JDBCType.Category.LONG_NCHARACTER, - JDBCType.Category.SQL_VARIANT)), - - TIMESTAMP ( - JDBCType.Category.TIMESTAMP, - EnumSet.of( - JDBCType.Category.DATE, - JDBCType.Category.TIME, - JDBCType.Category.TIMESTAMP, - JDBCType.Category.DATETIMEOFFSET, - JDBCType.Category.CHARACTER, - JDBCType.Category.LONG_CHARACTER, - JDBCType.Category.NCHARACTER, - JDBCType.Category.LONG_NCHARACTER, - JDBCType.Category.SQL_VARIANT)), - - TIME_WITH_TIMEZONE ( - JDBCType.Category.TIME_WITH_TIMEZONE, - EnumSet.of( - JDBCType.Category.TIME_WITH_TIMEZONE, - JDBCType.Category.CHARACTER, - JDBCType.Category.LONG_CHARACTER, - JDBCType.Category.NCHARACTER, - JDBCType.Category.LONG_NCHARACTER)), - - TIMESTAMP_WITH_TIMEZONE ( - JDBCType.Category.TIMESTAMP_WITH_TIMEZONE, - EnumSet.of( - JDBCType.Category.TIMESTAMP_WITH_TIMEZONE, - JDBCType.Category.TIME_WITH_TIMEZONE, - JDBCType.Category.CHARACTER, - JDBCType.Category.LONG_CHARACTER, - JDBCType.Category.NCHARACTER, - JDBCType.Category.LONG_NCHARACTER)), - - DATETIMEOFFSET ( - JDBCType.Category.DATETIMEOFFSET, - EnumSet.of( - JDBCType.Category.DATE, - JDBCType.Category.TIME, - JDBCType.Category.TIMESTAMP, - JDBCType.Category.DATETIMEOFFSET)), - - SQLXML ( - JDBCType.Category.SQLXML, - EnumSet.of( - JDBCType.Category.SQLXML)), - - TVP ( - JDBCType.Category.TVP, - EnumSet.of( - JDBCType.Category.TVP)); - + + DATE(JDBCType.Category.DATE, EnumSet.of(JDBCType.Category.DATE, JDBCType.Category.TIMESTAMP, + JDBCType.Category.DATETIMEOFFSET, JDBCType.Category.CHARACTER, JDBCType.Category.LONG_CHARACTER, + JDBCType.Category.NCHARACTER, JDBCType.Category.LONG_NCHARACTER, JDBCType.Category.SQL_VARIANT)), + + TIME(JDBCType.Category.TIME, EnumSet.of(JDBCType.Category.TIME, JDBCType.Category.TIMESTAMP, + JDBCType.Category.DATETIMEOFFSET, JDBCType.Category.CHARACTER, JDBCType.Category.LONG_CHARACTER, + JDBCType.Category.NCHARACTER, JDBCType.Category.LONG_NCHARACTER, JDBCType.Category.SQL_VARIANT)), + + TIMESTAMP(JDBCType.Category.TIMESTAMP, EnumSet.of(JDBCType.Category.DATE, JDBCType.Category.TIME, + JDBCType.Category.TIMESTAMP, JDBCType.Category.DATETIMEOFFSET, JDBCType.Category.CHARACTER, + JDBCType.Category.LONG_CHARACTER, JDBCType.Category.NCHARACTER, JDBCType.Category.LONG_NCHARACTER, + JDBCType.Category.SQL_VARIANT)), + + TIME_WITH_TIMEZONE(JDBCType.Category.TIME_WITH_TIMEZONE, EnumSet.of(JDBCType.Category.TIME_WITH_TIMEZONE, + JDBCType.Category.CHARACTER, JDBCType.Category.LONG_CHARACTER, JDBCType.Category.NCHARACTER, + JDBCType.Category.LONG_NCHARACTER)), + + TIMESTAMP_WITH_TIMEZONE(JDBCType.Category.TIMESTAMP_WITH_TIMEZONE, EnumSet.of( + JDBCType.Category.TIMESTAMP_WITH_TIMEZONE, JDBCType.Category.TIME_WITH_TIMEZONE, + JDBCType.Category.CHARACTER, JDBCType.Category.LONG_CHARACTER, JDBCType.Category.NCHARACTER, + JDBCType.Category.LONG_NCHARACTER)), + + DATETIMEOFFSET(JDBCType.Category.DATETIMEOFFSET, EnumSet.of(JDBCType.Category.DATE, JDBCType.Category.TIME, + JDBCType.Category.TIMESTAMP, JDBCType.Category.DATETIMEOFFSET)), + + SQLXML(JDBCType.Category.SQLXML, EnumSet.of(JDBCType.Category.SQLXML)), + + TVP(JDBCType.Category.TVP, EnumSet.of(JDBCType.Category.TVP)); + private final JDBCType.Category from; private final EnumSet to; - private SetterConversion(JDBCType.Category from, - EnumSet to) { + private SetterConversion(JDBCType.Category from, EnumSet to) { this.from = from; this.to = to; } @@ -1105,8 +796,7 @@ private SetterConversion(JDBCType.Category from, conversionMap.get(conversion.from).addAll(conversion.to); } - static boolean converts(JDBCType fromJDBCType, - JDBCType toJDBCType) { + static boolean converts(JDBCType fromJDBCType, JDBCType toJDBCType) { return conversionMap.get(fromJDBCType.category).contains(toJDBCType.category); } }; @@ -1116,199 +806,80 @@ boolean convertsTo(JDBCType jdbcType) { } enum UpdaterConversion { - CHARACTER ( - JDBCType.Category.CHARACTER, - EnumSet.of( - SSType.Category.NUMERIC, - SSType.Category.DATE, - SSType.Category.TIME, - SSType.Category.DATETIME, - SSType.Category.DATETIME2, - SSType.Category.DATETIMEOFFSET, - SSType.Category.CHARACTER, - SSType.Category.LONG_CHARACTER, - SSType.Category.NCHARACTER, - SSType.Category.LONG_NCHARACTER, - SSType.Category.XML, - SSType.Category.BINARY, - SSType.Category.LONG_BINARY, - SSType.Category.UDT, - SSType.Category.GUID, - SSType.Category.TIMESTAMP, - SSType.Category.SQL_VARIANT)), - - LONG_CHARACTER ( - JDBCType.Category.LONG_CHARACTER, - EnumSet.of( - SSType.Category.CHARACTER, - SSType.Category.LONG_CHARACTER, - SSType.Category.NCHARACTER, - SSType.Category.LONG_NCHARACTER, - SSType.Category.XML, - SSType.Category.BINARY, - SSType.Category.LONG_BINARY)), - - CLOB ( - JDBCType.Category.CLOB, - EnumSet.of( - SSType.Category.LONG_CHARACTER, - SSType.Category.LONG_NCHARACTER, + CHARACTER(JDBCType.Category.CHARACTER, EnumSet.of(SSType.Category.NUMERIC, SSType.Category.DATE, + SSType.Category.TIME, SSType.Category.DATETIME, SSType.Category.DATETIME2, + SSType.Category.DATETIMEOFFSET, SSType.Category.CHARACTER, SSType.Category.LONG_CHARACTER, + SSType.Category.NCHARACTER, SSType.Category.LONG_NCHARACTER, SSType.Category.XML, + SSType.Category.BINARY, SSType.Category.LONG_BINARY, SSType.Category.UDT, SSType.Category.GUID, + SSType.Category.TIMESTAMP, SSType.Category.SQL_VARIANT)), + + LONG_CHARACTER(JDBCType.Category.LONG_CHARACTER, EnumSet.of(SSType.Category.CHARACTER, + SSType.Category.LONG_CHARACTER, SSType.Category.NCHARACTER, SSType.Category.LONG_NCHARACTER, + SSType.Category.XML, SSType.Category.BINARY, SSType.Category.LONG_BINARY)), + + CLOB(JDBCType.Category.CLOB, EnumSet.of(SSType.Category.LONG_CHARACTER, SSType.Category.LONG_NCHARACTER, SSType.Category.XML)), - NCHARACTER ( - JDBCType.Category.NCHARACTER, - EnumSet.of( - SSType.Category.NCHARACTER, - SSType.Category.LONG_NCHARACTER, - SSType.Category.XML, - SSType.Category.SQL_VARIANT)), + NCHARACTER(JDBCType.Category.NCHARACTER, EnumSet.of(SSType.Category.NCHARACTER, SSType.Category.LONG_NCHARACTER, + SSType.Category.XML, SSType.Category.SQL_VARIANT)), - LONG_NCHARACTER ( - JDBCType.Category.LONG_NCHARACTER, - EnumSet.of( - SSType.Category.NCHARACTER, - SSType.Category.LONG_NCHARACTER, - SSType.Category.XML)), + LONG_NCHARACTER(JDBCType.Category.LONG_NCHARACTER, EnumSet.of(SSType.Category.NCHARACTER, + SSType.Category.LONG_NCHARACTER, SSType.Category.XML)), - NCLOB ( - JDBCType.Category.NCLOB, - EnumSet.of( - SSType.Category.LONG_NCHARACTER, - SSType.Category.XML)), + NCLOB(JDBCType.Category.NCLOB, EnumSet.of(SSType.Category.LONG_NCHARACTER, SSType.Category.XML)), - BINARY ( - JDBCType.Category.BINARY, - EnumSet.of( - SSType.Category.NUMERIC, - SSType.Category.DATETIME, - SSType.Category.CHARACTER, - SSType.Category.LONG_CHARACTER, - SSType.Category.NCHARACTER, - SSType.Category.LONG_NCHARACTER, - SSType.Category.XML, - SSType.Category.BINARY, - SSType.Category.LONG_BINARY, - SSType.Category.UDT, - SSType.Category.TIMESTAMP, - SSType.Category.GUID, + BINARY(JDBCType.Category.BINARY, EnumSet.of(SSType.Category.NUMERIC, SSType.Category.DATETIME, + SSType.Category.CHARACTER, SSType.Category.LONG_CHARACTER, SSType.Category.NCHARACTER, + SSType.Category.LONG_NCHARACTER, SSType.Category.XML, SSType.Category.BINARY, + SSType.Category.LONG_BINARY, SSType.Category.UDT, SSType.Category.TIMESTAMP, SSType.Category.GUID, SSType.Category.SQL_VARIANT)), - LONG_BINARY ( - JDBCType.Category.LONG_BINARY, - EnumSet.of( - SSType.Category.XML, - SSType.Category.BINARY, - SSType.Category.LONG_BINARY, - SSType.Category.UDT)), - - BLOB ( - JDBCType.Category.BLOB, - EnumSet.of( - SSType.Category.LONG_BINARY, - SSType.Category.XML)), - SQLXML ( - JDBCType.Category.SQLXML, - EnumSet.of( - SSType.Category.XML)), + LONG_BINARY(JDBCType.Category.LONG_BINARY, EnumSet.of(SSType.Category.XML, SSType.Category.BINARY, + SSType.Category.LONG_BINARY, SSType.Category.UDT)), - NUMERIC ( - JDBCType.Category.NUMERIC, - EnumSet.of( - SSType.Category.NUMERIC, - SSType.Category.CHARACTER, - SSType.Category.LONG_CHARACTER, - SSType.Category.NCHARACTER, - SSType.Category.LONG_NCHARACTER, - SSType.Category.SQL_VARIANT)), + BLOB(JDBCType.Category.BLOB, EnumSet.of(SSType.Category.LONG_BINARY, SSType.Category.XML)), + SQLXML(JDBCType.Category.SQLXML, EnumSet.of(SSType.Category.XML)), - DATE ( - JDBCType.Category.DATE, - EnumSet.of( - SSType.Category.DATE, - SSType.Category.DATETIME, - SSType.Category.DATETIME2, - SSType.Category.DATETIMEOFFSET, - SSType.Category.CHARACTER, - SSType.Category.LONG_CHARACTER, - SSType.Category.NCHARACTER, - SSType.Category.LONG_NCHARACTER, + NUMERIC(JDBCType.Category.NUMERIC, EnumSet.of(SSType.Category.NUMERIC, SSType.Category.CHARACTER, + SSType.Category.LONG_CHARACTER, SSType.Category.NCHARACTER, SSType.Category.LONG_NCHARACTER, SSType.Category.SQL_VARIANT)), - TIME ( - JDBCType.Category.TIME, - EnumSet.of( - SSType.Category.TIME, - SSType.Category.DATETIME, - SSType.Category.DATETIME2, - SSType.Category.DATETIMEOFFSET, - SSType.Category.CHARACTER, - SSType.Category.LONG_CHARACTER, - SSType.Category.NCHARACTER, - SSType.Category.LONG_NCHARACTER, + DATE(JDBCType.Category.DATE, EnumSet.of(SSType.Category.DATE, SSType.Category.DATETIME, + SSType.Category.DATETIME2, SSType.Category.DATETIMEOFFSET, SSType.Category.CHARACTER, + SSType.Category.LONG_CHARACTER, SSType.Category.NCHARACTER, SSType.Category.LONG_NCHARACTER, SSType.Category.SQL_VARIANT)), - TIMESTAMP ( - JDBCType.Category.TIMESTAMP, - EnumSet.of( - SSType.Category.DATE, - SSType.Category.TIME, - SSType.Category.DATETIME, - SSType.Category.DATETIME2, - SSType.Category.DATETIMEOFFSET, - SSType.Category.CHARACTER, - SSType.Category.LONG_CHARACTER, - SSType.Category.NCHARACTER, - SSType.Category.LONG_NCHARACTER, + TIME(JDBCType.Category.TIME, EnumSet.of(SSType.Category.TIME, SSType.Category.DATETIME, + SSType.Category.DATETIME2, SSType.Category.DATETIMEOFFSET, SSType.Category.CHARACTER, + SSType.Category.LONG_CHARACTER, SSType.Category.NCHARACTER, SSType.Category.LONG_NCHARACTER, SSType.Category.SQL_VARIANT)), - DATETIMEOFFSET ( - JDBCType.Category.DATETIMEOFFSET, - EnumSet.of( - SSType.Category.DATE, - SSType.Category.TIME, - SSType.Category.DATETIME, - SSType.Category.DATETIME2, - SSType.Category.DATETIMEOFFSET, - SSType.Category.CHARACTER, - SSType.Category.LONG_CHARACTER, - SSType.Category.NCHARACTER, + TIMESTAMP(JDBCType.Category.TIMESTAMP, EnumSet.of(SSType.Category.DATE, SSType.Category.TIME, + SSType.Category.DATETIME, SSType.Category.DATETIME2, SSType.Category.DATETIMEOFFSET, + SSType.Category.CHARACTER, SSType.Category.LONG_CHARACTER, SSType.Category.NCHARACTER, + SSType.Category.LONG_NCHARACTER, SSType.Category.SQL_VARIANT)), + + DATETIMEOFFSET(JDBCType.Category.DATETIMEOFFSET, EnumSet.of(SSType.Category.DATE, SSType.Category.TIME, + SSType.Category.DATETIME, SSType.Category.DATETIME2, SSType.Category.DATETIMEOFFSET, + SSType.Category.CHARACTER, SSType.Category.LONG_CHARACTER, SSType.Category.NCHARACTER, SSType.Category.LONG_NCHARACTER)), - - TIME_WITH_TIMEZONE ( - JDBCType.Category.TIME_WITH_TIMEZONE, - EnumSet.of( - SSType.Category.TIME, - SSType.Category.DATETIME, - SSType.Category.DATETIME2, - SSType.Category.DATETIMEOFFSET, - SSType.Category.CHARACTER, - SSType.Category.LONG_CHARACTER, - SSType.Category.NCHARACTER, - SSType.Category.LONG_NCHARACTER)), - - TIMESTAMP_WITH_TIMEZONE ( - JDBCType.Category.TIMESTAMP_WITH_TIMEZONE, - EnumSet.of( - SSType.Category.DATE, - SSType.Category.TIME, - SSType.Category.DATETIME, - SSType.Category.DATETIME2, - SSType.Category.DATETIMEOFFSET, - SSType.Category.CHARACTER, - SSType.Category.LONG_CHARACTER, - SSType.Category.NCHARACTER, - SSType.Category.LONG_NCHARACTER)), - - SQL_VARIANT ( - JDBCType.Category.SQL_VARIANT, - EnumSet.of( - SSType.Category.SQL_VARIANT)); - + + TIME_WITH_TIMEZONE(JDBCType.Category.TIME_WITH_TIMEZONE, EnumSet.of(SSType.Category.TIME, + SSType.Category.DATETIME, SSType.Category.DATETIME2, SSType.Category.DATETIMEOFFSET, + SSType.Category.CHARACTER, SSType.Category.LONG_CHARACTER, SSType.Category.NCHARACTER, + SSType.Category.LONG_NCHARACTER)), + + TIMESTAMP_WITH_TIMEZONE(JDBCType.Category.TIMESTAMP_WITH_TIMEZONE, EnumSet.of(SSType.Category.DATE, + SSType.Category.TIME, SSType.Category.DATETIME, SSType.Category.DATETIME2, + SSType.Category.DATETIMEOFFSET, SSType.Category.CHARACTER, SSType.Category.LONG_CHARACTER, + SSType.Category.NCHARACTER, SSType.Category.LONG_NCHARACTER)), + + SQL_VARIANT(JDBCType.Category.SQL_VARIANT, EnumSet.of(SSType.Category.SQL_VARIANT)); + private final JDBCType.Category from; private final EnumSet to; - private UpdaterConversion(JDBCType.Category from, - EnumSet to) { + private UpdaterConversion(JDBCType.Category from, EnumSet to) { this.from = from; this.to = to; } @@ -1324,8 +895,7 @@ private UpdaterConversion(JDBCType.Category from, conversionMap.get(conversion.from).addAll(conversion.to); } - static boolean converts(JDBCType fromJDBCType, - SSType toSSType) { + static boolean converts(JDBCType fromJDBCType, SSType toSSType) { return conversionMap.get(fromJDBCType.category).contains(toSSType.category); } }; @@ -1346,70 +916,49 @@ static JDBCType of(int intValue) throws SQLServerException { } /** - * Identify numerically signed data types. + * Identifies numerically signed data types. * * @return true if the type can be signed */ - private final static EnumSet signedTypes = - EnumSet.of( - SMALLINT, - INTEGER, - BIGINT, - REAL, - FLOAT, - DOUBLE, - DECIMAL, - NUMERIC, - MONEY, - SMALLMONEY); - - boolean isSigned() - { + private final static EnumSet signedTypes = EnumSet.of(SMALLINT, INTEGER, BIGINT, REAL, FLOAT, DOUBLE, + DECIMAL, NUMERIC, MONEY, SMALLMONEY); + + boolean isSigned() { return signedTypes.contains(this); } /** - * Identify binary JDBC data types. + * Identifies binary JDBC data types. * * @return true if the JDBC type is binary */ - private final static EnumSet binaryTypes = EnumSet.of( - BINARY, - VARBINARY, - LONGVARBINARY, - BLOB); + private final static EnumSet binaryTypes = EnumSet.of(BINARY, VARBINARY, LONGVARBINARY, BLOB); boolean isBinary() { return binaryTypes.contains(this); } /** - * Identify textual JDBC data types -- those types for which conversion from another type is simply a matter of representing that type as a - * string. + * Identifies textual JDBC data types -- those types for which conversion from another type is simply a matter of + * representing that type as a string. * - * Note: SQLXML does not qualify as a "textual" type in this context. That is, calling, for example, timestamp.toString() does not result in an - * XML representation of a timestamp. + * Note: SQLXML does not qualify as a "textual" type in this context. That is, calling, for example, + * timestamp.toString() does not result in an XML representation of a timestamp. * * @return true if the JDBC type is textual */ - private final static EnumSet textualCategories = - EnumSet.of( - Category.CHARACTER, - Category.LONG_CHARACTER, - Category.CLOB, - Category.NCHARACTER, - Category.LONG_NCHARACTER, - Category.NCLOB); + private final static EnumSet textualCategories = EnumSet.of(Category.CHARACTER, Category.LONG_CHARACTER, + Category.CLOB, Category.NCHARACTER, Category.LONG_NCHARACTER, Category.NCLOB); boolean isTextual() { return textualCategories.contains(category); } /** - * Identify unsupported JDBC data types. + * Returns if datat types are supported by JDBC. * * @param jdbcType - * the JDBC type to check + * the JDBC type to check * @return true if the type is unsupported */ boolean isUnsupported() { @@ -1438,188 +987,78 @@ int asJavaSqlType() { default: return intValue; } - } - else { + } else { return intValue; } } /* - * Used for verifying if a data type can be normalized for AE + * Used for verifying if a data type can be normalized for AE. */ enum NormalizationAE { - CHARACTER_NORMALIZED_TO ( - JDBCType.CHAR, - EnumSet.of( - SSType.CHAR, - SSType.VARCHAR, - SSType.VARCHARMAX)), - - VARCHARACTER_NORMALIZED_TO ( - JDBCType.VARCHAR, - EnumSet.of( - SSType.CHAR, - SSType.VARCHAR, - SSType.VARCHARMAX)), - - LONGVARCHARACTER_NORMALIZED_TO ( - JDBCType.LONGVARCHAR, - EnumSet.of( - SSType.CHAR, - SSType.VARCHAR, - SSType.VARCHARMAX)), - - NCHAR_NORMALIZED_TO ( - JDBCType.NCHAR, - EnumSet.of( - SSType.NCHAR, - SSType.NVARCHAR, - SSType.NVARCHARMAX)), - - NVARCHAR_NORMALIZED_TO ( - JDBCType.NVARCHAR, - EnumSet.of( - SSType.NCHAR, - SSType.NVARCHAR, - SSType.NVARCHARMAX)), - - LONGNVARCHAR_NORMALIZED_TO ( - JDBCType.LONGNVARCHAR, - EnumSet.of( - SSType.NCHAR, - SSType.NVARCHAR, - SSType.NVARCHARMAX)), - - BIT_NORMALIZED_TO ( - JDBCType.BIT, - EnumSet.of( - SSType.BIT, - SSType.TINYINT, - SSType.SMALLINT, - SSType.INTEGER, - SSType.BIGINT)), - - TINYINT_NORMALIZED_TO ( - JDBCType.TINYINT, - EnumSet.of( - SSType.TINYINT, - SSType.SMALLINT, - SSType.INTEGER, - SSType.BIGINT)), - - SMALLINT_NORMALIZED_TO ( - JDBCType.SMALLINT, - EnumSet.of( - SSType.SMALLINT, - SSType.INTEGER, - SSType.BIGINT)), - - INTEGER_NORMALIZED_TO ( - JDBCType.INTEGER, - EnumSet.of( - SSType.INTEGER, - SSType.BIGINT)), - - BIGINT_NORMALIZED_TO ( - JDBCType.BIGINT, - EnumSet.of( - SSType.BIGINT)), - - BINARY_NORMALIZED_TO ( - JDBCType.BINARY, - EnumSet.of( - SSType.BINARY, - SSType.VARBINARY, - SSType.VARBINARYMAX)), - - VARBINARY_NORMALIZED_TO ( - JDBCType.VARBINARY, - EnumSet.of( - SSType.BINARY, - SSType.VARBINARY, - SSType.VARBINARYMAX)), - - LONGVARBINARY_NORMALIZED_TO ( - JDBCType.LONGVARBINARY, - EnumSet.of( - SSType.BINARY, - SSType.VARBINARY, - SSType.VARBINARYMAX)), - - FLOAT_NORMALIZED_TO ( - JDBCType.DOUBLE, - EnumSet.of( - SSType.FLOAT)), - - REAL_NORMALIZED_TO ( - JDBCType.REAL, - EnumSet.of( - SSType.REAL)), - - DECIMAL_NORMALIZED_TO ( - JDBCType.DECIMAL, - EnumSet.of( - SSType.DECIMAL, - SSType.NUMERIC)), - - SMALLMONEY_NORMALIZED_TO ( - JDBCType.SMALLMONEY, - EnumSet.of( - SSType.SMALLMONEY, - SSType.MONEY)), - - MONEY_NORMALIZED_TO ( - JDBCType.MONEY, - EnumSet.of( - SSType.MONEY)), - - NUMERIC_NORMALIZED_TO ( - JDBCType.NUMERIC, - EnumSet.of( - SSType.DECIMAL, - SSType.NUMERIC)), - - DATE_NORMALIZED_TO ( - JDBCType.DATE, - EnumSet.of( - SSType.DATE)), - - TIME_NORMALIZED_TO ( - JDBCType.TIME, - EnumSet.of( - SSType.TIME)), - - DATETIME2_NORMALIZED_TO ( - JDBCType.TIMESTAMP, - EnumSet.of( - SSType.DATETIME2)), - - DATETIMEOFFSET_NORMALIZED_TO ( - JDBCType.DATETIMEOFFSET, - EnumSet.of( - SSType.DATETIMEOFFSET)), - - DATETIME_NORMALIZED_TO ( - JDBCType.DATETIME, - EnumSet.of( - SSType.DATETIME)), - - SMALLDATETIME_NORMALIZED_TO ( - JDBCType.SMALLDATETIME, - EnumSet.of( - SSType.SMALLDATETIME)), - - GUID_NORMALIZED_TO ( - JDBCType.GUID, - EnumSet.of( - SSType.GUID)), - ; + CHARACTER_NORMALIZED_TO(JDBCType.CHAR, EnumSet.of(SSType.CHAR, SSType.VARCHAR, SSType.VARCHARMAX)), + + VARCHARACTER_NORMALIZED_TO(JDBCType.VARCHAR, EnumSet.of(SSType.CHAR, SSType.VARCHAR, SSType.VARCHARMAX)), + + LONGVARCHARACTER_NORMALIZED_TO(JDBCType.LONGVARCHAR, EnumSet.of(SSType.CHAR, SSType.VARCHAR, + SSType.VARCHARMAX)), + + NCHAR_NORMALIZED_TO(JDBCType.NCHAR, EnumSet.of(SSType.NCHAR, SSType.NVARCHAR, SSType.NVARCHARMAX)), + + NVARCHAR_NORMALIZED_TO(JDBCType.NVARCHAR, EnumSet.of(SSType.NCHAR, SSType.NVARCHAR, SSType.NVARCHARMAX)), + + LONGNVARCHAR_NORMALIZED_TO(JDBCType.LONGNVARCHAR, EnumSet.of(SSType.NCHAR, SSType.NVARCHAR, + SSType.NVARCHARMAX)), + + BIT_NORMALIZED_TO(JDBCType.BIT, EnumSet.of(SSType.BIT, SSType.TINYINT, SSType.SMALLINT, SSType.INTEGER, + SSType.BIGINT)), + + TINYINT_NORMALIZED_TO(JDBCType.TINYINT, EnumSet.of(SSType.TINYINT, SSType.SMALLINT, SSType.INTEGER, + SSType.BIGINT)), + + SMALLINT_NORMALIZED_TO(JDBCType.SMALLINT, EnumSet.of(SSType.SMALLINT, SSType.INTEGER, SSType.BIGINT)), + + INTEGER_NORMALIZED_TO(JDBCType.INTEGER, EnumSet.of(SSType.INTEGER, SSType.BIGINT)), + + BIGINT_NORMALIZED_TO(JDBCType.BIGINT, EnumSet.of(SSType.BIGINT)), + + BINARY_NORMALIZED_TO(JDBCType.BINARY, EnumSet.of(SSType.BINARY, SSType.VARBINARY, SSType.VARBINARYMAX)), + + VARBINARY_NORMALIZED_TO(JDBCType.VARBINARY, EnumSet.of(SSType.BINARY, SSType.VARBINARY, SSType.VARBINARYMAX)), + + LONGVARBINARY_NORMALIZED_TO(JDBCType.LONGVARBINARY, EnumSet.of(SSType.BINARY, SSType.VARBINARY, + SSType.VARBINARYMAX)), + + FLOAT_NORMALIZED_TO(JDBCType.DOUBLE, EnumSet.of(SSType.FLOAT)), + + REAL_NORMALIZED_TO(JDBCType.REAL, EnumSet.of(SSType.REAL)), + + DECIMAL_NORMALIZED_TO(JDBCType.DECIMAL, EnumSet.of(SSType.DECIMAL, SSType.NUMERIC)), + + SMALLMONEY_NORMALIZED_TO(JDBCType.SMALLMONEY, EnumSet.of(SSType.SMALLMONEY, SSType.MONEY)), + + MONEY_NORMALIZED_TO(JDBCType.MONEY, EnumSet.of(SSType.MONEY)), + + NUMERIC_NORMALIZED_TO(JDBCType.NUMERIC, EnumSet.of(SSType.DECIMAL, SSType.NUMERIC)), + + DATE_NORMALIZED_TO(JDBCType.DATE, EnumSet.of(SSType.DATE)), + + TIME_NORMALIZED_TO(JDBCType.TIME, EnumSet.of(SSType.TIME)), + + DATETIME2_NORMALIZED_TO(JDBCType.TIMESTAMP, EnumSet.of(SSType.DATETIME2)), + + DATETIMEOFFSET_NORMALIZED_TO(JDBCType.DATETIMEOFFSET, EnumSet.of(SSType.DATETIMEOFFSET)), + + DATETIME_NORMALIZED_TO(JDBCType.DATETIME, EnumSet.of(SSType.DATETIME)), + + SMALLDATETIME_NORMALIZED_TO(JDBCType.SMALLDATETIME, EnumSet.of(SSType.SMALLDATETIME)), + + GUID_NORMALIZED_TO(JDBCType.GUID, EnumSet.of(SSType.GUID)),; private final JDBCType from; private final EnumSet to; - private NormalizationAE(JDBCType from, - EnumSet to) { + private NormalizationAE(JDBCType from, EnumSet to) { this.from = from; this.to = to; } @@ -1634,8 +1073,7 @@ private NormalizationAE(JDBCType from, normalizationMapAE.get(conversion.from).addAll(conversion.to); } - static boolean converts(JDBCType fromJDBCType, - SSType toSSType) { + static boolean converts(JDBCType fromJDBCType, SSType toSSType) { return normalizationMapAE.get(fromJDBCType).contains(toSSType); } }; @@ -1646,60 +1084,62 @@ boolean normalizationCheck(SSType ssType) { } + final class DataTypes { // ResultSet & CallableStatement getXXX conversions (SSType --> JDBCType) - static final void throwConversionError(String fromType, - String toType) throws SQLServerException { + static final void throwConversionError(String fromType, String toType) throws SQLServerException { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_unsupportedConversionFromTo")); Object[] msgArgs = {fromType, toType}; SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), null, true); } - // Max length in Unicode characters allowed by the "short" NVARCHAR type. - // Values longer than this must use NVARCHAR(max) (Yukon or later) or NTEXT (Shiloh) + /** + * Max length in Unicode characters allowed by the "short" NVARCHAR type. Values longer than this must use + * NVARCHAR(max) (Yukon or later) or NTEXT (Shiloh) + */ final static int SHORT_VARTYPE_MAX_CHARS = 4000; - // Max length in bytes allowed by the "short" VARBINARY/VARCHAR types. - // Values longer than this must use VARBINARY(max)/VARCHAR(max) (Yukon or later) or IMAGE/TEXT (Shiloh) + /** + * Max length in bytes allowed by the "short" VARBINARY/VARCHAR types. Values longer than this must use + * VARBINARY(max)/VARCHAR(max) (Yukon or later) or IMAGE/TEXT (Shiloh) + */ final static int SHORT_VARTYPE_MAX_BYTES = 8000; - // A type with unlimited max size, known as varchar(max), varbinary(max) and nvarchar(max), - // which has a max size of 0xFFFF, defined by PARTLENTYPE. + /** + * A type with unlimited max size, known as varchar(max), varbinary(max) and nvarchar(max), which has a max size of + * 0xFFFF, defined by PARTLENTYPE. + */ final static int SQL_USHORTVARMAXLEN = 65535; // 0xFFFF - // From SQL Server 2005 Books Online : ntext, text, and image (Transact-SQL) - // http://msdn.microsoft.com/en-us/library/ms187993.aspx - // - // image - // "... through 2^31 - 1 (2,147,483,687) bytes." - // - // text - // "... maximum length of 2^31 - 1 (2,147,483,687) characters." - // - // ntext - // "... maximum length of 2^30 - 1 (1,073,741,823) characters." + /** + * From SQL Server 2005 Books Online : ntext, text, and image (Transact-SQL) + * http://msdn.microsoft.com/en-us/library/ms187993.aspx + * + * image "... through 2^31 - 1 (2,147,483,687) bytes." + * + * text "... maximum length of 2^31 - 1 (2,147,483,687) characters." + * + * ntext "... maximum length of 2^30 - 1 (1,073,741,823) characters." + */ final static int NTEXT_MAX_CHARS = 0x3FFFFFFF; final static int IMAGE_TEXT_MAX_BYTES = 0x7FFFFFFF; - // From SQL Server 2005 Books Online : Transact-SQL Data Types - // http://msdn.microsoft.com/en-us/library/ms179910.aspx - // - // varbinary(max) - // "max indicates that the maximum storage size is 2^31 - 1 bytes. The storage size is the actual - // length of the data entered + 2 bytes." - // - // varchar(max) - // "max indicates that the maximum storage size is 2^31 - 1 bytes. The storage size is the actual - // length of the data entered + 2 bytes." - // - // nvarchar(max) - // "max indicates that the maximum storage size is 2^31 - 1 bytes. The storage size, in bytes, - // is two times the number of characters entered + 2 bytes." - // - // Normally, that would mean that the maximum length of nvarchar(max) data is 0x3FFFFFFE characters - // and that the maximum length of varchar(max) or varbinary(max) data is 0x3FFFFFFD bytes. However... - // Despite the documentation, SQL Server returns 2^30 - 1 and 2^31 - 1 respectively as the PRECISION - // of these types, so use that instead. + /** + * Transact-SQL Data Types: http://msdn.microsoft.com/en-us/library/ms179910.aspx + * + * varbinary(max) "max indicates that the maximum storage size is 2^31 - 1 bytes. The storage size is the actual + * length of the data entered + 2 bytes." + * + * varchar(max) "max indicates that the maximum storage size is 2^31 - 1 bytes. The storage size is the actual + * length of the data entered + 2 bytes." + * + * nvarchar(max) "max indicates that the maximum storage size is 2^31 - 1 bytes. The storage size, in bytes, is two + * times the number of characters entered + 2 bytes." + * + * Normally, that would mean that the maximum length of nvarchar(max) data is 0x3FFFFFFE characters and that the + * maximum length of varchar(max) or varbinary(max) data is 0x3FFFFFFD bytes. However... Despite the documentation, + * SQL Server returns 2^30 - 1 and 2^31 - 1 respectively as the PRECISION of these types, so use that instead. + */ final static int MAX_VARTYPE_MAX_CHARS = 0x3FFFFFFF; final static int MAX_VARTYPE_MAX_BYTES = 0x7FFFFFFF; @@ -1711,9 +1151,7 @@ static final void throwConversionError(String fromType, static final int UNKNOWN_STREAM_LENGTH = -1; // Utility methods to check a reported length against the maximums allowed - static final long getCheckedLength(SQLServerConnection con, - JDBCType jdbcType, - long length, + static final long getCheckedLength(SQLServerConnection con, JDBCType jdbcType, long length, boolean allowUnknown) throws SQLServerException { long maxLength; diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/FailOverInfo.java b/src/main/java/com/microsoft/sqlserver/jdbc/FailOverInfo.java index cdfe4fb83..14f394ab3 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/FailOverInfo.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/FailOverInfo.java @@ -1,157 +1,150 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -import java.text.MessageFormat; -import java.util.logging.Level; - -/** - * This class keeps the failover server info and if the mirror has become the primary. For synchronizing better and not to keep a lock in the class - * through a connection open a placeholder class is used to get the failover info in one shot. This class should never directly expose its members. - */ - -final class FailoverInfo { - private String failoverPartner; - private int portNumber; - private String failoverInstance; - private boolean setUpInfocalled; - - // This member is exposed outside for reading, we need to know in advance if the - // failover partner is the currently active server before making a DNS resolution and a connect attempt. - private boolean useFailoverPartner; - - boolean getUseFailoverPartner() { - return useFailoverPartner; - } - - FailoverInfo(String failover, - SQLServerConnection con, - boolean actualFailoverPartner) { - failoverPartner = failover; - useFailoverPartner = actualFailoverPartner; - portNumber = -1; // init to -1 to make sure that the user of this class calls the failover check before getting the port number. - } - - // the members of this class are not exposed so inorder to log we call this function. - void log(SQLServerConnection con) { - if (con.getConnectionLogger().isLoggable(Level.FINE)) - con.getConnectionLogger() - .fine(con.toString() + " Failover server :" + failoverPartner + " Failover partner is primary : " + useFailoverPartner); - } - - // this function gets the failover server port and sets up the security manager - // note calls to these should be synchronized or guaranteed to happen from only one thread. - private void setupInfo(SQLServerConnection con) throws SQLServerException { - if (setUpInfocalled) - return; - - if (0 == failoverPartner.length()) { - portNumber = SQLServerConnection.DEFAULTPORT; - } - else { - // 3.3006 get the instance name - int px = failoverPartner.indexOf('\\'); - String instancePort; - String instanceValue; - - // found the instance name with the severname - if (px >= 0) { - if (con.getConnectionLogger().isLoggable(Level.FINE)) - con.getConnectionLogger().fine(con.toString() + " Failover server :" + failoverPartner); - instanceValue = failoverPartner.substring(px + 1, failoverPartner.length()); - failoverPartner = failoverPartner.substring(0, px); - con.ValidateMaxSQLLoginName(SQLServerDriverStringProperty.INSTANCE_NAME.toString(), instanceValue); - failoverInstance = instanceValue; - instancePort = con.getInstancePort(failoverPartner, instanceValue); - - try { - portNumber = Integer.parseInt(instancePort); - } - catch (NumberFormatException e) { - // Should not get here as the server should give a proper port number anyway. - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidPortNumber")); - Object[] msgArgs = {instancePort}; - SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, false); - } - } - else - portNumber = SQLServerConnection.DEFAULTPORT; - } - setUpInfocalled = true; - } - - synchronized ServerPortPlaceHolder failoverPermissionCheck(SQLServerConnection con, - boolean link) throws SQLServerException { - setupInfo(con); - return new ServerPortPlaceHolder(failoverPartner, portNumber, failoverInstance, link); - } - - // Add/replace the failover server, - synchronized void failoverAdd(SQLServerConnection connection, - boolean actualUseFailoverPartner, - String actualFailoverPartner) throws SQLServerException { - if (useFailoverPartner != actualUseFailoverPartner) { - if (connection.getConnectionLogger().isLoggable(Level.FINE)) - connection.getConnectionLogger().fine(connection.toString() + " Failover detected. failover partner=" + actualFailoverPartner); - useFailoverPartner = actualUseFailoverPartner; - } - // The checking for actualUseFailoverPartner may look weird but this is required - // We only change the failoverpartner info when we connect to the primary - // if we connect to the secondary and it sends a failover partner - // we wont store that information. - if (!actualUseFailoverPartner && !failoverPartner.equals(actualFailoverPartner)) { - failoverPartner = actualFailoverPartner; - // new FO partner need to setup again. - setUpInfocalled = false; - } - } -} - -// A simple readonly placeholder class to store the current server info. -// We need this class so during a connection open we can keep a copy of the current failover info stable -// This is also used to keep the standalone primary server connection information. -// -final class ServerPortPlaceHolder { - private final String serverName; - private final int port; - private final String instanceName; - private final boolean checkLink; - private final SQLServerConnectionSecurityManager securityManager; - - ServerPortPlaceHolder(String name, - int conPort, - String instance, - boolean fLink) { - serverName = name; - port = conPort; - instanceName = instance; - checkLink = fLink; - securityManager = new SQLServerConnectionSecurityManager(serverName, port); - doSecurityCheck(); - } - - // accessors - int getPortNumber() { - return port; - } - - String getServerName() { - return serverName; - } - - String getInstanceName() { - return instanceName; - } - - void doSecurityCheck() { - securityManager.checkConnect(); - if (checkLink) - securityManager.checkLink(); - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +import java.text.MessageFormat; +import java.util.logging.Level; + + +/** + * This class keeps the failover server info and if the mirror has become the primary. For synchronizing better and not + * to keep a lock in the class through a connection open a placeholder class is used to get the failover info in one + * shot. This class should never directly expose its members. + */ + +final class FailoverInfo { + private String failoverPartner; + private int portNumber; + private String failoverInstance; + private boolean setUpInfocalled; + + // This member is exposed outside for reading, we need to know in advance if the + // failover partner is the currently active server before making a DNS resolution and a connect attempt. + private boolean useFailoverPartner; + + boolean getUseFailoverPartner() { + return useFailoverPartner; + } + + FailoverInfo(String failover, SQLServerConnection con, boolean actualFailoverPartner) { + failoverPartner = failover; + useFailoverPartner = actualFailoverPartner; + portNumber = -1; // init to -1 to make sure that the user of this class calls the failover check before getting + // the port number. + } + + // the members of this class are not exposed so inorder to log we call this function. + void log(SQLServerConnection con) { + if (con.getConnectionLogger().isLoggable(Level.FINE)) + con.getConnectionLogger().fine(con.toString() + " Failover server :" + failoverPartner + + " Failover partner is primary : " + useFailoverPartner); + } + + // this function gets the failover server port and sets up the security manager + // note calls to these should be synchronized or guaranteed to happen from only one thread. + private void setupInfo(SQLServerConnection con) throws SQLServerException { + if (setUpInfocalled) + return; + + if (0 == failoverPartner.length()) { + portNumber = SQLServerConnection.DEFAULTPORT; + } else { + // 3.3006 get the instance name + int px = failoverPartner.indexOf('\\'); + String instancePort; + String instanceValue; + + // found the instance name with the severname + if (px >= 0) { + if (con.getConnectionLogger().isLoggable(Level.FINE)) + con.getConnectionLogger().fine(con.toString() + " Failover server :" + failoverPartner); + instanceValue = failoverPartner.substring(px + 1, failoverPartner.length()); + failoverPartner = failoverPartner.substring(0, px); + con.ValidateMaxSQLLoginName(SQLServerDriverStringProperty.INSTANCE_NAME.toString(), instanceValue); + failoverInstance = instanceValue; + instancePort = con.getInstancePort(failoverPartner, instanceValue); + + try { + portNumber = Integer.parseInt(instancePort); + } catch (NumberFormatException e) { + // Should not get here as the server should give a proper port number anyway. + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidPortNumber")); + Object[] msgArgs = {instancePort}; + SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, false); + } + } else + portNumber = SQLServerConnection.DEFAULTPORT; + } + setUpInfocalled = true; + } + + synchronized ServerPortPlaceHolder failoverPermissionCheck(SQLServerConnection con, + boolean link) throws SQLServerException { + setupInfo(con); + return new ServerPortPlaceHolder(failoverPartner, portNumber, failoverInstance, link); + } + + // Add/replace the failover server, + synchronized void failoverAdd(SQLServerConnection connection, boolean actualUseFailoverPartner, + String actualFailoverPartner) throws SQLServerException { + if (useFailoverPartner != actualUseFailoverPartner) { + if (connection.getConnectionLogger().isLoggable(Level.FINE)) + connection.getConnectionLogger() + .fine(connection.toString() + " Failover detected. failover partner=" + actualFailoverPartner); + useFailoverPartner = actualUseFailoverPartner; + } + // The checking for actualUseFailoverPartner may look weird but this is required + // We only change the failoverpartner info when we connect to the primary + // if we connect to the secondary and it sends a failover partner + // we wont store that information. + if (!actualUseFailoverPartner && !failoverPartner.equals(actualFailoverPartner)) { + failoverPartner = actualFailoverPartner; + // new FO partner need to setup again. + setUpInfocalled = false; + } + } +} + + +// A simple readonly placeholder class to store the current server info. +// We need this class so during a connection open we can keep a copy of the current failover info stable +// This is also used to keep the standalone primary server connection information. +// +final class ServerPortPlaceHolder { + private final String serverName; + private final int port; + private final String instanceName; + private final boolean checkLink; + private final SQLServerConnectionSecurityManager securityManager; + + ServerPortPlaceHolder(String name, int conPort, String instance, boolean fLink) { + serverName = name; + port = conPort; + instanceName = instance; + checkLink = fLink; + securityManager = new SQLServerConnectionSecurityManager(serverName, port); + doSecurityCheck(); + } + + // accessors + int getPortNumber() { + return port; + } + + String getServerName() { + return serverName; + } + + String getInstanceName() { + return instanceName; + } + + void doSecurityCheck() { + securityManager.checkConnect(); + if (checkLink) + securityManager.checkLink(); + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/FailOverMapSingleton.java b/src/main/java/com/microsoft/sqlserver/jdbc/FailOverMapSingleton.java index 8bebf1f0e..c0936b09c 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/FailOverMapSingleton.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/FailOverMapSingleton.java @@ -1,79 +1,69 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -import java.util.HashMap; -import java.util.logging.Level; - -final class FailoverMapSingleton { - private static int INITIALHASHMAPSIZE = 5; - private static HashMap failoverMap = new HashMap<>(INITIALHASHMAPSIZE); - - private FailoverMapSingleton() { - /* hide the constructor to stop the instantiation of this class. */} - - private static String concatPrimaryDatabase(String primary, - String instance, - String database) { - StringBuilder buf = new StringBuilder(); - buf.append(primary); - if (null != instance) { - buf.append("\\"); - buf.append(instance); - } - buf.append(";"); - buf.append(database); - return buf.toString(); - } - - static FailoverInfo getFailoverInfo(SQLServerConnection connection, - String primaryServer, - String instance, - String database) { - synchronized (FailoverMapSingleton.class) { - if (true == failoverMap.isEmpty()) { - return null; - } - else { - String mapKey = concatPrimaryDatabase(primaryServer, instance, database); - if (connection.getConnectionLogger().isLoggable(Level.FINER)) - connection.getConnectionLogger().finer(connection.toString() + " Looking up info in the map using key: " + mapKey); - FailoverInfo fo = failoverMap.get(mapKey); - if (null != fo) - fo.log(connection); - return fo; - } - } - } - - // The map is populated with primary server, instance name and db as the key (always user info) value is the failover server name provided - // by the server. The map is only populated if the server sends failover info. - static void putFailoverInfo(SQLServerConnection connection, - String primaryServer, - String instance, - String database, - FailoverInfo actualFailoverInfo, - boolean actualuseFailover, - String failoverPartner) throws SQLServerException { - FailoverInfo fo; - - synchronized (FailoverMapSingleton.class) { - // one more check to make sure someone already did not do this - if (null == (fo = getFailoverInfo(connection, primaryServer, instance, database))) { - if (connection.getConnectionLogger().isLoggable(Level.FINE)) - connection.getConnectionLogger().fine(connection.toString() + " Failover map add server: " + primaryServer + "; database:" - + database + "; Mirror:" + failoverPartner); - failoverMap.put(concatPrimaryDatabase(primaryServer, instance, database), actualFailoverInfo); - } - else - // if the class exists make sure the latest info is updated - fo.failoverAdd(connection, actualuseFailover, failoverPartner); - } - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +import java.util.HashMap; +import java.util.logging.Level; + + +final class FailoverMapSingleton { + private static int INITIALHASHMAPSIZE = 5; + private static HashMap failoverMap = new HashMap<>(INITIALHASHMAPSIZE); + + private FailoverMapSingleton() { + /* hide the constructor to stop the instantiation of this class. */} + + private static String concatPrimaryDatabase(String primary, String instance, String database) { + StringBuilder buf = new StringBuilder(); + buf.append(primary); + if (null != instance) { + buf.append("\\"); + buf.append(instance); + } + buf.append(";"); + buf.append(database); + return buf.toString(); + } + + static FailoverInfo getFailoverInfo(SQLServerConnection connection, String primaryServer, String instance, + String database) { + synchronized (FailoverMapSingleton.class) { + if (true == failoverMap.isEmpty()) { + return null; + } else { + String mapKey = concatPrimaryDatabase(primaryServer, instance, database); + if (connection.getConnectionLogger().isLoggable(Level.FINER)) + connection.getConnectionLogger() + .finer(connection.toString() + " Looking up info in the map using key: " + mapKey); + FailoverInfo fo = failoverMap.get(mapKey); + if (null != fo) + fo.log(connection); + return fo; + } + } + } + + // The map is populated with primary server, instance name and db as the key (always user info) value is the + // failover server name provided + // by the server. The map is only populated if the server sends failover info. + static void putFailoverInfo(SQLServerConnection connection, String primaryServer, String instance, String database, + FailoverInfo actualFailoverInfo, boolean actualuseFailover, + String failoverPartner) throws SQLServerException { + FailoverInfo fo; + + synchronized (FailoverMapSingleton.class) { + // one more check to make sure someone already did not do this + if (null == (fo = getFailoverInfo(connection, primaryServer, instance, database))) { + if (connection.getConnectionLogger().isLoggable(Level.FINE)) + connection.getConnectionLogger().fine(connection.toString() + " Failover map add server: " + + primaryServer + "; database:" + database + "; Mirror:" + failoverPartner); + failoverMap.put(concatPrimaryDatabase(primaryServer, instance, database), actualFailoverInfo); + } else + // if the class exists make sure the latest info is updated + fo.failoverAdd(connection, actualuseFailover, failoverPartner); + } + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/Geography.java b/src/main/java/com/microsoft/sqlserver/jdbc/Geography.java index 8726cb001..d8dd00929 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/Geography.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/Geography.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -11,154 +8,156 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; + +/** + * Geography datatype represents data in a round-earth coordinate system. + */ + public class Geography extends SQLServerSpatialDatatype { - + /** - * Private constructor used for creating a Geography object from WKT and srid. + * Private constructor used for creating a Geography object from WKT and Spatial Reference Identifier. * - * @param WellKnownText - * Well-Known Text (WKT) provided by the user. - * @param srid - * Spatial Reference Identifier (SRID) provided by the user. - * @throws SQLServerException - * if an exception occurs + * @param wkt + * Well-Known Text (WKT) provided by the user. + * @param srid + * Spatial Reference Identifier (SRID) provided by the user. + * @throws SQLServerException + * if an exception occurs */ - private Geography(String WellKnownText, int srid) throws SQLServerException { - this.wkt = WellKnownText; - this.srid = srid; - - try { - parseWKTForSerialization(this, currentWktPos, -1, false); - } - catch (StringIndexOutOfBoundsException e) { - String strError = SQLServerException.getErrString("R_illegalWKT"); - throw new SQLServerException(strError, null, 0, null); + private Geography(String wkt, int srid) throws SQLServerException { + if (null == wkt || wkt.length() <= 0) { + throwIllegalWKT(); } - - serializeToWkb(false); + + this.wkt = wkt; + this.srid = srid; + + parseWKTForSerialization(this, currentWktPos, -1, false); + + serializeToWkb(false, this); isNull = false; } /** * Private constructor used for creating a Geography object from WKB. * - * @param wkb - * Well-Known Binary (WKB) provided by the user. - * @throws SQLServerException - * if an exception occurs + * @param wkb + * Well-Known Binary (WKB) provided by the user. + * @throws SQLServerException + * if an exception occurs */ private Geography(byte[] wkb) throws SQLServerException { + if (null == wkb || wkb.length <= 0) { + throwIllegalWKB(); + } + this.wkb = wkb; buffer = ByteBuffer.wrap(wkb); buffer.order(ByteOrder.LITTLE_ENDIAN); - - parseWkb(); - + + parseWkb(this); + WKTsb = new StringBuffer(); WKTsbNoZM = new StringBuffer(); - + constructWKT(this, internalType, numberOfPoints, numberOfFigures, numberOfSegments, numberOfShapes); - + wkt = WKTsb.toString(); wktNoZM = WKTsbNoZM.toString(); isNull = false; } - + /** - * Returns a Geography instance from an Open Geospatial Consortium (OGC) Well-Known Text (WKT) - * representation augmented with any Z (elevation) and M (measure) values carried by the instance. - * + * Constructor for a Geography instance from an Open Geospatial Consortium (OGC) Well-Known Text (WKT) + * representation augmented with any Z (elevation) and M (measure) values carried by the instance. + * * @param wkt - * Well-Known Text (WKT) provided by the user. + * Well-Known Text (WKT) provided by the user. * @param srid - * Spatial Reference Identifier (SRID) provided by the user. - * @return Geography - * Geography instance created from WKT and SRID - * @throws SQLServerException - * if an exception occurs + * Spatial Reference Identifier (SRID) provided by the user. + * @return Geography Geography instance created from WKT and SRID + * @throws SQLServerException + * if an exception occurs */ public static Geography STGeomFromText(String wkt, int srid) throws SQLServerException { return new Geography(wkt, srid); } - + /** - * Returns a Geography instance from an Open Geospatial Consortium (OGC) - * Well-Known Binary (WKB) representation. + * Constructor for a Geography instance from an Open Geospatial Consortium (OGC) Well-Known Binary (WKB) + * representation. * * @param wkb - * Well-Known Binary (WKB) provided by the user. - * @return Geography - * Geography instance created from WKB - * @throws SQLServerException - * if an exception occurs + * Well-Known Binary (WKB) provided by the user. + * @return Geography Geography instance created from WKB + * @throws SQLServerException + * if an exception occurs */ public static Geography STGeomFromWKB(byte[] wkb) throws SQLServerException { return new Geography(wkb); } - + /** - * Returns a constructed Geography from an internal SQL Server format for spatial data. + * Constructor for a Geography instance from an internal SQL Server format for spatial data. * * @param wkb - * Well-Known Binary (WKB) provided by the user. - * @return Geography - * Geography instance created from WKB - * @throws SQLServerException - * if an exception occurs + * Well-Known Binary (WKB) provided by the user. + * @return Geography Geography instance created from WKB + * @throws SQLServerException + * if an exception occurs */ public static Geography deserialize(byte[] wkb) throws SQLServerException { return new Geography(wkb); } /** - * Returns a Geography instance from an Open Geospatial Consortium (OGC) Well-Known Text (WKT) representation. - * SRID is defaulted to 4326. + * Constructor for a Geography instance from an Open Geospatial Consortium (OGC) Well-Known Text (WKT) + * representation. Spatial Reference Identifier is defaulted to 4326. * * @param wkt - * Well-Known Text (WKT) provided by the user. - * @return Geography - * Geography instance created from WKT - * @throws SQLServerException - * if an exception occurs + * Well-Known Text (WKT) provided by the user. + * @return Geography Geography instance created from WKT + * @throws SQLServerException + * if an exception occurs */ public static Geography parse(String wkt) throws SQLServerException { return new Geography(wkt, 4326); } - + /** - * Constructs a Geography instance that represents a Point instance from its X and Y values and an SRID. + * Constructor for a Geography instance that represents a Point instance from its latitude and longitude values and + * a Spatial Reference Identifier. * - * @param x - * x coordinate - * @param y - * y coordinate + * @param lat + * latitude + * @param lon + * longitude * @param srid - * SRID - * @return Geography - * Geography instance - * @throws SQLServerException - * if an exception occurs + * Spatial Reference Identifier value + * @return Geography Geography instance + * @throws SQLServerException + * if an exception occurs */ - public static Geography point(double x, double y, int srid) throws SQLServerException { - return new Geography("POINT (" + x + " " + y + ")", srid); + public static Geography point(double lat, double lon, int srid) throws SQLServerException { + return new Geography("POINT (" + lat + " " + lon + ")", srid); } /** - * Returns the Open Geospatial Consortium (OGC) Well-Known Text (WKT) representation of a - * Geography instance. This text will not contain any Z (elevation) or M (measure) values carried by the instance. + * Returns the Open Geospatial Consortium (OGC) Well-Known Text (WKT) representation of a Geography instance. This + * text will not contain any Z (elevation) or M (measure) values carried by the instance. * - * @return - * the WKT representation without the Z and M values. - * @throws SQLServerException - * if an exception occurs + * @return the WKT representation without the Z and M values. + * @throws SQLServerException + * if an exception occurs */ public String STAsText() throws SQLServerException { if (null == wktNoZM) { buffer = ByteBuffer.wrap(wkb); buffer.order(ByteOrder.LITTLE_ENDIAN); - - parseWkb(); - + + parseWkb(this); + WKTsb = new StringBuffer(); WKTsbNoZM = new StringBuffer(); constructWKT(this, internalType, numberOfPoints, numberOfFigures, numberOfSegments, numberOfShapes); @@ -166,29 +165,29 @@ public String STAsText() throws SQLServerException { } return wktNoZM; } - + /** - * Returns the Open Geospatial Consortium (OGC) Well-Known Binary (WKB) representation of a - * Geography instance. This value will not contain any Z or M values carried by the instance. - * + * Returns the Open Geospatial Consortium (OGC) Well-Known Binary (WKB) representation of a Geography instance. This + * value will not contain any Z or M values carried by the instance. + * * @return byte array representation of the Geography object. */ public byte[] STAsBinary() { if (null == wkbNoZM) { - serializeToWkb(true); + serializeToWkb(true, this); } return wkbNoZM; } - + /** - * Returns the bytes that represent an internal SQL Server format of Geography type. + * Returns the bytes that represent an internal SQL Server format of Geography type. * * @return byte array representation of the Geography object. */ public byte[] serialize() { return wkb; } - + /** * Returns if the object contains a M (measure) value. * @@ -197,7 +196,7 @@ public byte[] serialize() { public boolean hasM() { return hasMvalues; } - + /** * Returns if the object contains a Z (elevation) value. * @@ -206,31 +205,31 @@ public boolean hasM() { public boolean hasZ() { return hasZvalues; } - + /** - * Returns the X coordinate value. + * Returns the latitude value. * - * @return double value that represents the X coordinate. + * @return double value that represents the latitude. */ - public Double getX() { - if (null != internalType && internalType == InternalSpatialDatatype.POINT && points.length == 2) { - return points[0]; + public Double getLatitude() { + if (null != internalType && internalType == InternalSpatialDatatype.POINT && xValues.length == 1) { + return xValues[0]; } return null; } - + /** - * Returns the Y coordinate value. + * Returns the longitude value. * - * @return double value that represents the Y coordinate. + * @return double value that represents the longitude. */ - public Double getY() { - if (null != internalType && internalType == InternalSpatialDatatype.POINT && points.length == 2) { - return points[1]; + public Double getLongitude() { + if (null != internalType && internalType == InternalSpatialDatatype.POINT && yValues.length == 1) { + return yValues[0]; } return null; } - + /** * Returns the M (measure) value of the object. * @@ -242,7 +241,7 @@ public Double getM() { } return null; } - + /** * Returns the Z (elevation) value of the object. * @@ -263,7 +262,7 @@ public Double getZ() { public int getSrid() { return srid; } - + /** * Returns if the Geography object is null. * @@ -272,7 +271,7 @@ public int getSrid() { public boolean isNull() { return isNull; } - + /** * Returns the number of points in the Geography object. * @@ -293,16 +292,16 @@ public String STGeographyType() { } return null; } - + /** - * Returns the Well-Known Text (WKT) representation of the Geography object. + * Returns the Well-Known Text (WKT) representation of the Geography object. * * @return String that contains the WKT representation of the Geography object. */ public String asTextZM() { return wkt; } - + /** * Returns the String representation of the Geography object. * @@ -312,111 +311,4 @@ public String asTextZM() { public String toString() { return wkt; } - - protected void serializeToWkb(boolean noZM) { - ByteBuffer buf = ByteBuffer.allocate(determineWkbCapacity()); - createSerializationProperties(); - - buf.order(ByteOrder.LITTLE_ENDIAN); - buf.putInt(srid); - buf.put(version); - buf.put(serializationProperties); - - if (!isSinglePoint && !isSingleLineSegment) { - buf.putInt(numberOfPoints); - } - - for (int i = 0; i < numberOfPoints; i++) { - buf.putDouble(points[2 * i + 1]); - buf.putDouble(points[2 * i]); - } - - if (!noZM) { - if (hasZvalues) { - for (int i = 0; i < numberOfPoints; i++) { - buf.putDouble(zValues[i]); - } - } - if (hasMvalues) { - for (int i = 0; i < numberOfPoints; i++) { - buf.putDouble(mValues[i]); - } - } - } - - if (isSinglePoint || isSingleLineSegment) { - wkb = buf.array(); - return; - } - - buf.putInt(numberOfFigures); - for (int i = 0; i < numberOfFigures; i++) { - buf.put(figures[i].getFiguresAttribute()); - buf.putInt(figures[i].getPointOffset()); - } - - buf.putInt(numberOfShapes); - for (int i = 0; i < numberOfShapes; i++) { - buf.putInt(shapes[i].getParentOffset()); - buf.putInt(shapes[i].getFigureOffset()); - buf.put(shapes[i].getOpenGISType()); - } - - if (version == 2 && null != segments) { - buf.putInt(numberOfSegments); - for (int i = 0; i < numberOfSegments; i++) { - buf.put(segments[i].getSegmentType()); - } - } - - if (noZM) { - wkbNoZM = buf.array(); - } else { - wkb = buf.array(); - - } - return; - } - - protected void parseWkb() { - srid = buffer.getInt(); - version = buffer.get(); - serializationProperties = buffer.get(); - - interpretSerializationPropBytes(); - readNumberOfPoints(); - readPoints(); - - if (hasZvalues) { - readZvalues(); - } - - if (hasMvalues) { - readMvalues(); - } - - if (!(isSinglePoint || isSingleLineSegment)) { - readNumberOfFigures(); - readFigures(); - readNumberOfShapes(); - readShapes(); - } - - determineInternalType(); - - if (buffer.hasRemaining()) { - if (version == 2 && internalType.getTypeCode() != 8 && internalType.getTypeCode() != 11) { - readNumberOfSegments(); - readSegments(); - } - } - } - - private void readPoints() { - points = new double[2 * numberOfPoints]; - for (int i = 0; i < numberOfPoints; i++) { - points[2 * i + 1] = buffer.getDouble(); - points[2 * i] = buffer.getDouble(); - } - } -} \ No newline at end of file +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/Geometry.java b/src/main/java/com/microsoft/sqlserver/jdbc/Geometry.java index 45a0960f1..64d78e0e8 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/Geometry.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/Geometry.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -11,49 +8,55 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; + +/** + * Geometry datatype represents data in a Euclidean (flat) coordinate system. + */ + public class Geometry extends SQLServerSpatialDatatype { /** - * Private constructor used for creating a Geometry object from WKT and srid. + * Private constructor used for creating a Geometry object from WKT and Spatial Reference Identifier. * - * @param WellKnownText - * Well-Known Text (WKT) provided by the user. - * @param srid - * Spatial Reference Identifier (SRID) provided by the user. + * @param wkt + * Well-Known Text (WKT) provided by the user. + * @param srid + * Spatial Reference Identifier (SRID) provided by the user. * @throws SQLServerException - * if an exception occurs + * if an exception occurs */ - private Geometry(String WellKnownText, - int srid) throws SQLServerException { - this.wkt = WellKnownText; + private Geometry(String wkt, int srid) throws SQLServerException { + if (null == wkt || wkt.length() <= 0) { + throwIllegalWKT(); + } + + this.wkt = wkt; this.srid = srid; - try { - parseWKTForSerialization(this, currentWktPos, -1, false); - } - catch (StringIndexOutOfBoundsException e) { - String strError = SQLServerException.getErrString("R_illegalWKT"); - throw new SQLServerException(strError, null, 0, null); - } + parseWKTForSerialization(this, currentWktPos, -1, false); - serializeToWkb(false); + serializeToWkb(false, this); isNull = false; } /** * Private constructor used for creating a Geometry object from WKB. * - * @param wkb - * Well-Known Binary (WKB) provided by the user. + * @param wkb + * Well-Known Binary (WKB) provided by the user. * @throws SQLServerException - * if an exception occurs + * if an exception occurs */ private Geometry(byte[] wkb) throws SQLServerException { + if (null == wkb || wkb.length <= 0) { + throwIllegalWKB(); + } + this.wkb = wkb; buffer = ByteBuffer.wrap(wkb); buffer.order(ByteOrder.LITTLE_ENDIAN); - parseWkb(); + parseWkb(this); WKTsb = new StringBuffer(); WKTsbNoZM = new StringBuffer(); @@ -66,100 +69,94 @@ private Geometry(byte[] wkb) throws SQLServerException { } /** - * Returns a Geometry instance from an Open Geospatial Consortium (OGC) Well-Known Text (WKT) representation augmented with any Z (elevation) and - * M (measure) values carried by the instance. + * Constructor for a Geometry instance from an Open Geospatial Consortium (OGC) Well-Known Text (WKT) representation + * augmented with any Z (elevation) and M (measure) values carried by the instance. * * @param wkt - * Well-Known Text (WKT) provided by the user. + * Well-Known Text (WKT) provided by the user. * @param srid - * Spatial Reference Identifier (SRID) provided by the user. - * @return Geometry - * Geometry instance created from WKT and SRID + * Spatial Reference Identifier (SRID) provided by the user. + * @return Geometry Geometry instance created from WKT and SRID * @throws SQLServerException - * if an exception occurs + * if an exception occurs */ - public static Geometry STGeomFromText(String wkt, - int srid) throws SQLServerException { + public static Geometry STGeomFromText(String wkt, int srid) throws SQLServerException { return new Geometry(wkt, srid); } /** - * Returns a Geometry instance from an Open Geospatial Consortium (OGC) Well-Known Binary (WKB) representation. + * Constructor for a Geometry instance from an Open Geospatial Consortium (OGC) Well-Known Binary (WKB) + * representation. * * @param wkb - * Well-Known Binary (WKB) provided by the user. - * @return Geometry - * Geometry instance created from WKB + * Well-Known Binary (WKB) provided by the user. + * @return Geometry Geometry instance created from WKB * @throws SQLServerException - * if an exception occurs + * if an exception occurs */ public static Geometry STGeomFromWKB(byte[] wkb) throws SQLServerException { return new Geometry(wkb); } /** - * Returns a constructed Geometry from an internal SQL Server format for spatial data. + * Constructor for a Geometry instance from an internal SQL Server format for spatial data. * * @param wkb - * Well-Known Binary (WKB) provided by the user. - * @return Geometry - * Geometry instance created from WKB + * Well-Known Binary (WKB) provided by the user. + * @return Geometry Geometry instance created from WKB * @throws SQLServerException - * if an exception occurs + * if an exception occurs */ public static Geometry deserialize(byte[] wkb) throws SQLServerException { return new Geometry(wkb); } /** - * Returns a Geometry instance from an Open Geospatial Consortium (OGC) Well-Known Text (WKT) representation. SRID is defaulted to 0. + * Constructor for a Geometry instance from an Open Geospatial Consortium (OGC) Well-Known Text (WKT) + * representation. Spatial Reference Identifier is defaulted to 0. * * @param wkt - * Well-Known Text (WKT) provided by the user. - * @return Geometry - * Geometry instance created from WKT + * Well-Known Text (WKT) provided by the user. + * @return Geometry Geometry instance created from WKT * @throws SQLServerException - * if an exception occurs + * if an exception occurs */ public static Geometry parse(String wkt) throws SQLServerException { return new Geometry(wkt, 0); } /** - * Constructs a Geometry instance that represents a Point instance from its X and Y values and an SRID. + * Constructor for a Geometry instance that represents a Point instance from its X and Y values and an Spatial + * Reference Identifier. * * @param x - * x coordinate + * x coordinate * @param y - * y coordinate + * y coordinate * @param srid - * SRID - * @return Geometry - * Geography instance + * Spatial Reference Identifier value + * @return Geometry Geography instance * @throws SQLServerException - * if an exception occurs + * if an exception occurs */ - public static Geometry point(double x, - double y, - int srid) throws SQLServerException { + public static Geometry point(double x, double y, int srid) throws SQLServerException { return new Geometry("POINT (" + x + " " + y + ")", srid); } /** - * Returns the Open Geospatial Consortium (OGC) Well-Known Text (WKT) representation of a Geometry instance. This text will not contain any Z - * (elevation) or M (measure) values carried by the instance. + * Returns the Open Geospatial Consortium (OGC) Well-Known Text (WKT) representation of a Geometry instance. This + * text will not contain any Z (elevation) or M (measure) values carried by the instance. * - * @return - * the WKT representation without the Z and M values. + * @return the WKT representation without the Z and M values. * @throws SQLServerException - * if an exception occurs + * if an exception occurs */ public String STAsText() throws SQLServerException { if (null == wktNoZM) { buffer = ByteBuffer.wrap(wkb); buffer.order(ByteOrder.LITTLE_ENDIAN); - parseWkb(); + parseWkb(this); WKTsb = new StringBuffer(); WKTsbNoZM = new StringBuffer(); @@ -170,14 +167,14 @@ public String STAsText() throws SQLServerException { } /** - * Returns the Open Geospatial Consortium (OGC) Well-Known Binary (WKB) representation of a Geometry instance. This value will not contain any Z - * or M values carried by the instance. + * Returns the Open Geospatial Consortium (OGC) Well-Known Binary (WKB) representation of a Geometry instance. This + * value will not contain any Z or M values carried by the instance. * * @return byte array representation of the Geometry object. */ public byte[] STAsBinary() { if (null == wkbNoZM) { - serializeToWkb(true); + serializeToWkb(true, this); } return wkbNoZM; } @@ -215,8 +212,8 @@ public boolean hasZ() { * @return double value that represents the X coordinate. */ public Double getX() { - if (null != internalType && internalType == InternalSpatialDatatype.POINT && points.length == 2) { - return points[0]; + if (null != internalType && internalType == InternalSpatialDatatype.POINT && xValues.length == 1) { + return xValues[0]; } return null; } @@ -227,8 +224,8 @@ public Double getX() { * @return double value that represents the Y coordinate. */ public Double getY() { - if (null != internalType && internalType == InternalSpatialDatatype.POINT && points.length == 2) { - return points[1]; + if (null != internalType && internalType == InternalSpatialDatatype.POINT && yValues.length == 1) { + return yValues[0]; } return null; } @@ -314,113 +311,4 @@ public String asTextZM() { public String toString() { return wkt; } - - protected void serializeToWkb(boolean noZM) { - ByteBuffer buf = ByteBuffer.allocate(determineWkbCapacity()); - createSerializationProperties(); - - buf.order(ByteOrder.LITTLE_ENDIAN); - buf.putInt(srid); - buf.put(version); - buf.put(serializationProperties); - - if (!isSinglePoint && !isSingleLineSegment) { - buf.putInt(numberOfPoints); - } - - for (int i = 0; i < numberOfPoints; i++) { - buf.putDouble(points[2 * i]); - buf.putDouble(points[2 * i + 1]); - } - - if (!noZM) { - if (hasZvalues) { - for (int i = 0; i < numberOfPoints; i++) { - buf.putDouble(zValues[i]); - } - } - - if (hasMvalues) { - for (int i = 0; i < numberOfPoints; i++) { - buf.putDouble(mValues[i]); - } - } - } - - if (isSinglePoint || isSingleLineSegment) { - wkb = buf.array(); - return; - } - - buf.putInt(numberOfFigures); - for (int i = 0; i < numberOfFigures; i++) { - buf.put(figures[i].getFiguresAttribute()); - buf.putInt(figures[i].getPointOffset()); - } - - buf.putInt(numberOfShapes); - for (int i = 0; i < numberOfShapes; i++) { - buf.putInt(shapes[i].getParentOffset()); - buf.putInt(shapes[i].getFigureOffset()); - buf.put(shapes[i].getOpenGISType()); - } - - if (version == 2 && null != segments) { - buf.putInt(numberOfSegments); - for (int i = 0; i < numberOfSegments; i++) { - buf.put(segments[i].getSegmentType()); - } - } - - if (noZM) { - wkbNoZM = buf.array(); - } - else { - wkb = buf.array(); - - } - return; - } - - protected void parseWkb() { - srid = buffer.getInt(); - version = buffer.get(); - serializationProperties = buffer.get(); - - interpretSerializationPropBytes(); - readNumberOfPoints(); - readPoints(); - - if (hasZvalues) { - readZvalues(); - } - - if (hasMvalues) { - readMvalues(); - } - - if (!(isSinglePoint || isSingleLineSegment)) { - readNumberOfFigures(); - readFigures(); - readNumberOfShapes(); - readShapes(); - } - - determineInternalType(); - - if (buffer.hasRemaining()) { - if (version == 2 && internalType.getTypeCode() != 8 && internalType.getTypeCode() != 11) { - readNumberOfSegments(); - readSegments(); - } - } - } - - private void readPoints() { - points = new double[2 * numberOfPoints]; - for (int i = 0; i < numberOfPoints; i++) { - points[2 * i] = buffer.getDouble(); - points[2 * i + 1] = buffer.getDouble(); - } - } } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java b/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java index 94e62341a..f08262347 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -20,14 +17,13 @@ import java.math.BigDecimal; import java.math.BigInteger; import java.math.RoundingMode; -import java.net.Inet4Address; -import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketAddress; import java.net.SocketException; import java.net.SocketTimeoutException; +import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.SelectionKey; @@ -76,7 +72,6 @@ import com.microsoft.sqlserver.jdbc.dataclassification.SensitivityClassification; -import java.nio.Buffer; final class TDS { // TDS protocol versions @@ -113,7 +108,8 @@ final class TDS { static final int TDS_FEDAUTH_LIBRARY_RESERVED = 0x7F; static final byte ADALWORKFLOW_ACTIVEDIRECTORYPASSWORD = 0x01; static final byte ADALWORKFLOW_ACTIVEDIRECTORYINTEGRATED = 0x02; - static final byte FEDAUTH_INFO_ID_STSURL = 0x01; // FedAuthInfoData is token endpoint URL from which to acquire fed auth token + static final byte FEDAUTH_INFO_ID_STSURL = 0x01; // FedAuthInfoData is token endpoint URL from which to acquire fed + // auth token static final byte FEDAUTH_INFO_ID_SPN = 0x02; // FedAuthInfoData is the SPN to use for acquiring fed auth token // AE constants @@ -121,17 +117,17 @@ final class TDS { static final byte TDS_FEATURE_EXT_AE = 0x04; static final byte MAX_SUPPORTED_TCE_VERSION = 0x01; // max version static final int CUSTOM_CIPHER_ALGORITHM_ID = 0; // max version - // 0x06 is for x_eFeatureExtensionId_LoginToken - // 0x07 is for x_eFeatureExtensionId_ClientSideTelemetry + // 0x06 is for x_eFeatureExtensionId_LoginToken + // 0x07 is for x_eFeatureExtensionId_ClientSideTelemetry // Data Classification constants static final byte TDS_FEATURE_EXT_DATACLASSIFICATION = 0x09; static final byte DATA_CLASSIFICATION_NOT_ENABLED = 0x00; static final byte MAX_SUPPORTED_DATA_CLASSIFICATION_VERSION = 0x01; - + static final int AES_256_CBC = 1; static final int AEAD_AES_256_CBC_HMAC_SHA256 = 2; static final int AE_METADATA = 0x08; - + static final byte TDS_FEATURE_EXT_UTF8SUPPORT = 0x0A; static final int TDS_TVP = 0xF3; @@ -150,7 +146,7 @@ final class TDS { static final int FLAG_TVP_DEFAULT_COLUMN = 0x200; static final int FEATURE_EXT_TERMINATOR = -1; - + // Sql_variant length static final int SQL_VARIANT_LENGTH = 8009; @@ -258,7 +254,7 @@ static final String getTokenName(int tdsTokenType) { static final byte PKT_LOGON70 = 16; // 0x10 static final byte PKT_SSPI = 17; static final byte PKT_PRELOGIN = 18; // 0x12 - static final byte PKT_FEDAUTH_TOKEN_MESSAGE = 8; // Authentication token for federated authentication + static final byte PKT_FEDAUTH_TOKEN_MESSAGE = 8; // Authentication token for federated authentication static final byte STATUS_NORMAL = 0x00; static final byte STATUS_BIT_EOM = 0x01; @@ -287,9 +283,10 @@ static final String getTokenName(int tdsTokenType) { // 8 byte transaction descriptor // 4 byte outstanding request count static final int MARS_HEADER_LENGTH = 18; // 2 byte header type, 8 byte transaction descriptor, - static final int TRACE_HEADER_LENGTH = 26; // header length (4) + header type (2) + guid (16) + Sequence number size (4) + static final int TRACE_HEADER_LENGTH = 26; // header length (4) + header type (2) + guid (16) + Sequence number size + // (4) - static final short HEADERTYPE_TRACE = 3; // trace header type + static final short HEADERTYPE_TRACE = 3; // trace header type // Message header length static final int MESSAGE_HEADER_LENGTH = MARS_HEADER_LENGTH + 4; // length includes message header itself @@ -457,20 +454,20 @@ static int datetimeoffsetValueLength(int scale) { } // TDS is just a namespace - it can't be instantiated. - private TDS() { - } + private TDS() {} } + class Nanos { static final int PER_SECOND = 1000000000; static final int PER_MAX_SCALE_INTERVAL = PER_SECOND / (int) Math.pow(10, TDS.MAX_FRACTIONAL_SECONDS_SCALE); static final int PER_MILLISECOND = PER_SECOND / 1000; static final long PER_DAY = 24 * 60 * 60 * (long) PER_SECOND; - private Nanos() { - } + private Nanos() {} } + // Constants relating to the historically accepted Julian-Gregorian calendar cutover date (October 15, 1582). // // Used in processing SQL Server temporal data types whose date component may precede that date. @@ -518,7 +515,8 @@ class GregorianChange { GregorianCalendar cal = new GregorianCalendar(Locale.US); cal.clear(); - cal.set(1, Calendar.FEBRUARY, 577738, 0, 0, 0);// 577738 = 1+577737(no of days since epoch that brings us to oct 15th 1582) + cal.set(1, Calendar.FEBRUARY, 577738, 0, 0, 0);// 577738 = 1+577737(no of days since epoch that brings us to oct + // 15th 1582) if (cal.get(Calendar.DAY_OF_MONTH) == 15) { // If the date calculation is correct(the above bug is fixed), // post the default gregorian cut over date, the pure gregorian date @@ -531,24 +529,23 @@ class GregorianChange { // In both the above approaches, the code is about 6-8 times slower, // resulting in an overall perf regression of about (10-30)% for perf test cases EXTRA_DAYS_TO_BE_ADDED = 2; - } - else + } else EXTRA_DAYS_TO_BE_ADDED = 0; } - private GregorianChange() { - } + private GregorianChange() {} } + final class UTC { // UTC/GMT time zone singleton. static final TimeZone timeZone = new SimpleTimeZone(0, "UTC"); - private UTC() { - } + private UTC() {} } + final class TDSChannel { private static final Logger logger = Logger.getLogger("com.microsoft.sqlserver.jdbc.internals.TDS.Channel"); @@ -646,19 +643,14 @@ void resetPooledConnection() { /** * Opens the physical communications channel (TCP/IP socket and I/O streams) to the SQL Server. */ - final void open(String host, - int port, - int timeoutMillis, - boolean useParallel, - boolean useTnir, - boolean isTnirFirstAttempt, - int timeoutMillisForFullTimeout) throws SQLServerException { + final void open(String host, int port, int timeoutMillis, boolean useParallel, boolean useTnir, + boolean isTnirFirstAttempt, int timeoutMillisForFullTimeout) throws SQLServerException { if (logger.isLoggable(Level.FINER)) logger.finer(this.toString() + ": Opening TCP socket..."); SocketFinder socketFinder = new SocketFinder(traceID, con); - channelSocket = tcpSocket = socketFinder.findSocket(host, port, timeoutMillis, useParallel, useTnir, isTnirFirstAttempt, - timeoutMillisForFullTimeout); + channelSocket = tcpSocket = socketFinder.findSocket(host, port, timeoutMillis, useParallel, useTnir, + isTnirFirstAttempt, timeoutMillisForFullTimeout); try { @@ -672,8 +664,7 @@ final void open(String host, inputStream = tcpInputStream = tcpSocket.getInputStream(); outputStream = tcpOutputStream = tcpSocket.getOutputStream(); - } - catch (IOException ex) { + } catch (IOException ex) { SQLServerException.ConvertConnectExceptionToSQLServerException(host, port, con, ex); } } @@ -686,21 +677,19 @@ void disableSSL() { logger.finer(toString() + " Disabling SSL..."); /* - * The mission: To close the SSLSocket and release everything that it is holding onto other than the TCP/IP socket and streams. - * - * The challenge: Simply closing the SSLSocket tries to do additional, unnecessary shutdown I/O over the TCP/IP streams that are bound to the - * socket proxy, resulting in a not responding and confusing SQL Server. - * - * Solution: Rewire the ProxySocket's input and output streams (one more time) to closed streams. SSLSocket sees that the streams are already - * closed and does not attempt to do any further I/O on them before closing itself. + * The mission: To close the SSLSocket and release everything that it is holding onto other than the TCP/IP + * socket and streams. The challenge: Simply closing the SSLSocket tries to do additional, unnecessary shutdown + * I/O over the TCP/IP streams that are bound to the socket proxy, resulting in a not responding and confusing + * SQL Server. Solution: Rewire the ProxySocket's input and output streams (one more time) to closed streams. + * SSLSocket sees that the streams are already closed and does not attempt to do any further I/O on them before + * closing itself. */ // Create a couple of cheap closed streams InputStream is = new ByteArrayInputStream(new byte[0]); try { is.close(); - } - catch (IOException e) { + } catch (IOException e) { // No reason to expect a brand new ByteArrayInputStream not to close, // but just in case... logger.fine("Ignored error closing InputStream: " + e.getMessage()); @@ -709,8 +698,7 @@ void disableSSL() { OutputStream os = new ByteArrayOutputStream(); try { os.close(); - } - catch (IOException e) { + } catch (IOException e) { // No reason to expect a brand new ByteArrayOutputStream not to close, // but just in case... logger.fine("Ignored error closing OutputStream: " + e.getMessage()); @@ -728,8 +716,7 @@ void disableSSL() { logger.finer(toString() + " Closing SSL socket"); sslSocket.close(); - } - catch (IOException e) { + } catch (IOException e) { // Don't care if we can't close the SSL socket. We're done with it anyway. logger.fine("Ignored error closing SSLSocket: " + e.getMessage()); } @@ -751,8 +738,8 @@ void disableSSL() { } /** - * Used during SSL handshake, this class implements an InputStream that reads SSL handshake response data (framed in TDS messages) from the TDS - * channel. + * Used during SSL handshake, this class implements an InputStream that reads SSL handshake response data (framed in + * TDS messages) from the TDS channel. */ private class SSLHandshakeInputStream extends InputStream { private final TDSReader tdsReader; @@ -761,8 +748,7 @@ private class SSLHandshakeInputStream extends InputStream { private final Logger logger; private final String logContext; - SSLHandshakeInputStream(TDSChannel tdsChannel, - SSLHandshakeOutputStream sslHandshakeOutputStream) { + SSLHandshakeInputStream(TDSChannel tdsChannel, SSLHandshakeOutputStream sslHandshakeOutputStream) { this.tdsReader = tdsChannel.getReader(null); this.sslHandshakeOutputStream = sslHandshakeOutputStream; this.logger = tdsChannel.getLogger(); @@ -770,20 +756,22 @@ private class SSLHandshakeInputStream extends InputStream { } /** - * If there is no handshake response data available to be read from existing packets then this method ensures that the SSL handshake output - * stream has been flushed to the server, and reads another packet (starting the next TDS response message). + * If there is no handshake response data available to be read from existing packets then this method ensures + * that the SSL handshake output stream has been flushed to the server, and reads another packet (starting the + * next TDS response message). * - * Note that simply using TDSReader.ensurePayload isn't sufficient as it does not automatically start the new response message. + * Note that simply using TDSReader.ensurePayload isn't sufficient as it does not automatically start the new + * response message. */ private void ensureSSLPayload() throws IOException { if (0 == tdsReader.available()) { if (logger.isLoggable(Level.FINEST)) - logger.finest(logContext + " No handshake response bytes available. Flushing SSL handshake output stream."); + logger.finest(logContext + + " No handshake response bytes available. Flushing SSL handshake output stream."); try { sslHandshakeOutputStream.endMessage(); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { logger.finer(logContext + " Ending TDS message threw exception:" + e.getMessage()); throw new IOException(e.getMessage()); } @@ -793,8 +781,7 @@ private void ensureSSLPayload() throws IOException { try { tdsReader.readPacket(); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { logger.finer(logContext + " Reading response packet threw exception:" + e.getMessage()); throw new IOException(e.getMessage()); } @@ -815,8 +802,7 @@ public long skip(long n) throws IOException { try { tdsReader.skip((int) n); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { logger.finer(logContext + " Skipping bytes threw exception:" + e.getMessage()); throw new IOException(e.getMessage()); } @@ -829,8 +815,7 @@ public long skip(long n) throws IOException { public int read() throws IOException { int bytesRead; - while (0 == (bytesRead = readInternal(oneByte, 0, oneByte.length))) - ; + while (0 == (bytesRead = readInternal(oneByte, 0, oneByte.length))); assert 1 == bytesRead || -1 == bytesRead; return 1 == bytesRead ? oneByte[0] : -1; @@ -840,15 +825,11 @@ public int read(byte[] b) throws IOException { return readInternal(b, 0, b.length); } - public int read(byte b[], - int offset, - int maxBytes) throws IOException { + public int read(byte b[], int offset, int maxBytes) throws IOException { return readInternal(b, offset, maxBytes); } - private int readInternal(byte b[], - int offset, - int maxBytes) throws IOException { + private int readInternal(byte b[], int offset, int maxBytes) throws IOException { if (logger.isLoggable(Level.FINEST)) logger.finest(logContext + " Reading " + maxBytes + " bytes..."); @@ -856,8 +837,7 @@ private int readInternal(byte b[], try { tdsReader.readBytes(b, offset, maxBytes); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { logger.finer(logContext + " Reading bytes threw exception:" + e.getMessage()); throw new IOException(e.getMessage()); } @@ -867,8 +847,8 @@ private int readInternal(byte b[], } /** - * Used during SSL handshake, this class implements an OutputStream that writes SSL handshake request data (framed in TDS messages) to the TDS - * channel. + * Used during SSL handshake, this class implements an OutputStream that writes SSL handshake request data (framed + * in TDS messages) to the TDS channel. */ private class SSLHandshakeOutputStream extends OutputStream { private final TDSWriter tdsWriter; @@ -923,15 +903,11 @@ public void write(byte[] b) throws IOException { writeInternal(b, 0, b.length); } - public void write(byte[] b, - int off, - int len) throws IOException { + public void write(byte[] b, int off, int len) throws IOException { writeInternal(b, off, len); } - private void writeInternal(byte[] b, - int off, - int len) throws IOException { + private void writeInternal(byte[] b, int off, int len) throws IOException { try { // Start out the handshake request in a new prelogin message. Subsequent // writes just add handshake data to the request until flushed. @@ -947,8 +923,7 @@ private void writeInternal(byte[] b, logger.finest(logContext + " Writing " + len + " bytes..."); tdsWriter.writeBytes(b, off, len); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { logger.finer(logContext + " Writing bytes threw exception:" + e.getMessage()); throw new IOException(e.getMessage()); } @@ -958,7 +933,8 @@ private void writeInternal(byte[] b, /** * This class implements an InputStream that just forwards all of its methods to an underlying InputStream. * - * It is more predictable than FilteredInputStream which forwards some of its read methods directly to the underlying stream, but not others. + * It is more predictable than FilteredInputStream which forwards some of its read methods directly to the + * underlying stream, but not others. */ private final class ProxyInputStream extends InputStream { private InputStream filteredStream; @@ -999,8 +975,7 @@ public int available() throws IOException { public int read() throws IOException { int bytesRead; - while (0 == (bytesRead = readInternal(oneByte, 0, oneByte.length))) - ; + while (0 == (bytesRead = readInternal(oneByte, 0, oneByte.length))); assert 1 == bytesRead || -1 == bytesRead; return 1 == bytesRead ? oneByte[0] : -1; @@ -1010,15 +985,11 @@ public int read(byte[] b) throws IOException { return readInternal(b, 0, b.length); } - public int read(byte b[], - int offset, - int maxBytes) throws IOException { + public int read(byte b[], int offset, int maxBytes) throws IOException { return readInternal(b, offset, maxBytes); } - private int readInternal(byte b[], - int offset, - int maxBytes) throws IOException { + private int readInternal(byte b[], int offset, int maxBytes) throws IOException { int bytesRead; if (logger.isLoggable(Level.FINEST)) @@ -1026,8 +997,7 @@ private int readInternal(byte b[], try { bytesRead = filteredStream.read(b, offset, maxBytes); - } - catch (IOException e) { + } catch (IOException e) { if (logger.isLoggable(Level.FINER)) logger.finer(toString() + " " + e.getMessage()); @@ -1075,8 +1045,8 @@ public void close() throws IOException { /** * This class implements an OutputStream that just forwards all of its methods to an underlying OutputStream. * - * This class essentially does what FilteredOutputStream does, but is more efficient for our usage. FilteredOutputStream transforms block writes - * to sequences of single-byte writes. + * This class essentially does what FilteredOutputStream does, but is more efficient for our usage. + * FilteredOutputStream transforms block writes to sequences of single-byte writes. */ final class ProxyOutputStream extends OutputStream { private OutputStream filteredStream; @@ -1114,15 +1084,11 @@ public void write(byte[] b) throws IOException { writeInternal(b, 0, b.length); } - public void write(byte[] b, - int off, - int len) throws IOException { + public void write(byte[] b, int off, int len) throws IOException { writeInternal(b, off, len); } - private void writeInternal(byte[] b, - int off, - int len) throws IOException { + private void writeInternal(byte[] b, int off, int len) throws IOException { if (logger.isLoggable(Level.FINEST)) logger.finest(toString() + " Writing " + len + " bytes"); @@ -1131,14 +1097,15 @@ private void writeInternal(byte[] b, } /** - * This class implements a Socket whose I/O streams can be switched from using a TDSChannel for I/O to using its underlying TCP/IP socket. + * This class implements a Socket whose I/O streams can be switched from using a TDSChannel for I/O to using its + * underlying TCP/IP socket. * - * The SSL socket binds to a ProxySocket. The initial SSL handshake is done over TDSChannel I/O streams so that the handshake payload is framed in - * TDS packets. The I/O streams are then switched to TCP/IP I/O streams using setStreams, and SSL communications continue directly over the TCP/IP - * I/O streams. + * The SSL socket binds to a ProxySocket. The initial SSL handshake is done over TDSChannel I/O streams so that the + * handshake payload is framed in TDS packets. The I/O streams are then switched to TCP/IP I/O streams using + * setStreams, and SSL communications continue directly over the TCP/IP I/O streams. * - * Most methods other than those for getting the I/O streams are simply forwarded to the TDSChannel's underlying TCP/IP socket. Methods that - * change the socket binding or provide direct channel access are disallowed. + * Most methods other than those for getting the I/O streams are simply forwarded to the TDSChannel's underlying + * TCP/IP socket. Methods that change the socket binding or provide direct channel access are disallowed. */ private class ProxySocket extends Socket { private final TDSChannel tdsChannel; @@ -1154,13 +1121,13 @@ private class ProxySocket extends Socket { // Create the I/O streams SSLHandshakeOutputStream sslHandshakeOutputStream = new SSLHandshakeOutputStream(tdsChannel); - SSLHandshakeInputStream sslHandshakeInputStream = new SSLHandshakeInputStream(tdsChannel, sslHandshakeOutputStream); + SSLHandshakeInputStream sslHandshakeInputStream = new SSLHandshakeInputStream(tdsChannel, + sslHandshakeOutputStream); this.proxyOutputStream = new ProxyOutputStream(sslHandshakeOutputStream); this.proxyInputStream = new ProxyInputStream(sslHandshakeInputStream); } - void setStreams(InputStream is, - OutputStream os) { + void setStreams(InputStream is, OutputStream os) { proxyInputStream.setFilteredStream(is); proxyOutputStream.setFilteredStream(os); } @@ -1279,8 +1246,7 @@ public void connect(SocketAddress endpoint) throws IOException { throw new IOException(); } - public void connect(SocketAddress endpoint, - int timeout) throws IOException { + public void connect(SocketAddress endpoint, int timeout) throws IOException { logger.finer(logContext + " Disallowed call to connect (with timeout). Throwing IOException."); throw new IOException(); } @@ -1307,8 +1273,7 @@ public void setReuseAddress(boolean on) throws SocketException { logger.finer(toString() + " Ignoring setReuseAddress"); } - public void setSoLinger(boolean on, - int linger) throws SocketException { + public void setSoLinger(boolean on, int linger) throws SocketException { if (logger.isLoggable(Level.FINER)) logger.finer(toString() + " Ignoring setSoLinger"); } @@ -1357,8 +1322,8 @@ public void setOOBInline(boolean on) throws SocketException { /** * This class implements an X509TrustManager that always accepts the X509Certificate chain offered to it. * - * A PermissiveX509TrustManager is used to "verify" the authenticity of the server when the trustServerCertificate connection property is set to - * true. + * A PermissiveX509TrustManager is used to "verify" the authenticity of the server when the trustServerCertificate + * connection property is set to true. */ private final class PermissiveX509TrustManager implements X509TrustManager { private final TDSChannel tdsChannel; @@ -1371,14 +1336,12 @@ private final class PermissiveX509TrustManager implements X509TrustManager { this.logContext = tdsChannel.toString() + " (PermissiveX509TrustManager):"; } - public void checkClientTrusted(X509Certificate[] chain, - String authType) throws CertificateException { + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { if (logger.isLoggable(Level.FINER)) logger.finer(logContext + " Trusting client certificate (!)"); } - public void checkServerTrusted(X509Certificate[] chain, - String authType) throws CertificateException { + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { if (logger.isLoggable(Level.FINER)) logger.finer(logContext + " Trusting server certificate"); } @@ -1399,15 +1362,12 @@ private final class HostNameOverrideX509TrustManager implements X509TrustManager private final X509TrustManager defaultTrustManager; private String hostName; - HostNameOverrideX509TrustManager(TDSChannel tdsChannel, - X509TrustManager tm, - String hostName) { + HostNameOverrideX509TrustManager(TDSChannel tdsChannel, X509TrustManager tm, String hostName) { this.logger = tdsChannel.getLogger(); this.logContext = tdsChannel.toString() + " (HostNameOverrideX509TrustManager):"; defaultTrustManager = tm; // canonical name is in lower case so convert this to lowercase too. - this.hostName = hostName.toLowerCase(Locale.ENGLISH); - ; + this.hostName = hostName.toLowerCase(Locale.ENGLISH);; } // Parse name in RFC 2253 format @@ -1422,8 +1382,10 @@ private String parseCommonName(String distinguishedName) { } distinguishedName = distinguishedName.substring(index + 3); // Parse until a comma or end is reached - // Note the parser will handle gracefully (essentially will return empty string) , inside the quotes (e.g cn="Foo, bar") however - // RFC 952 says that the hostName cant have commas however the parser should not (and will not) crash if it sees a , within quotes. + // Note the parser will handle gracefully (essentially will return empty string) , inside the quotes (e.g + // cn="Foo, bar") however + // RFC 952 says that the hostName cant have commas however the parser should not (and will not) crash if it + // sees a , within quotes. for (index = 0; index < distinguishedName.length(); index++) { if (distinguishedName.charAt(index) == ',') { break; @@ -1453,25 +1415,25 @@ private boolean validateServerName(String nameInCert) throws CertificateExceptio // Verify that the name in certificate matches exactly with the host name if (!nameInCert.equals(hostName)) { if (logger.isLoggable(Level.FINER)) - logger.finer(logContext + " The name in certificate " + nameInCert + " does not match with the server name " + hostName + "."); + logger.finer(logContext + " The name in certificate " + nameInCert + + " does not match with the server name " + hostName + "."); return false; } if (logger.isLoggable(Level.FINER)) - logger.finer(logContext + " The name in certificate:" + nameInCert + " validated against server name " + hostName + "."); + logger.finer(logContext + " The name in certificate:" + nameInCert + " validated against server name " + + hostName + "."); return true; } - public void checkClientTrusted(X509Certificate[] chain, - String authType) throws CertificateException { + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { if (logger.isLoggable(Level.FINEST)) logger.finest(logContext + " Forwarding ClientTrusted."); defaultTrustManager.checkClientTrusted(chain, authType); } - public void checkServerTrusted(X509Certificate[] chain, - String authType) throws CertificateException { + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { if (logger.isLoggable(Level.FINEST)) logger.finest(logContext + " Forwarding Trusting server certificate"); defaultTrustManager.checkServerTrusted(chain, authType); @@ -1508,12 +1470,14 @@ private void validateServerNameInCertificate(X509Certificate cert) throws Certif Object value = sanEntry.get(1); if (logger.isLoggable(Level.FINER)) { - logger.finer(logContext + "Key: " + key + "; KeyClass:" + (key != null ? key.getClass() : null) + ";value: " + value - + "; valueClass:" + (value != null ? value.getClass() : null)); + logger.finer(logContext + "Key: " + key + "; KeyClass:" + + (key != null ? key.getClass() : null) + ";value: " + value + "; valueClass:" + + (value != null ? value.getClass() : null)); } - // From Documentation(http://download.oracle.com/javase/6/docs/api/java/security/cert/X509Certificate.html): + // From + // Documentation(http://download.oracle.com/javase/6/docs/api/java/security/cert/X509Certificate.html): // "Note that the Collection returned may contain // more than one name of the same type." // So, more than one entry of dnsNameType can be present. @@ -1539,19 +1503,21 @@ private void validateServerNameInCertificate(X509Certificate cert) throws Certif if (isServerNameValidated) { if (logger.isLoggable(Level.FINER)) { - logger.finer(logContext + " found a valid name in certificate: " + dnsNameInSANCert); + logger.finer(logContext + " found a valid name in certificate: " + + dnsNameInSANCert); } break; } } if (logger.isLoggable(Level.FINER)) { - logger.finer(logContext + " the following name in certificate does not match the serverName: " + value); + logger.finer(logContext + + " the following name in certificate does not match the serverName: " + + value); } } - } - else { + } else { if (logger.isLoggable(Level.FINER)) { logger.finer(logContext + " found an invalid san entry: " + sanEntry); } @@ -1582,19 +1548,18 @@ enum SSLHandhsakeState { * Enables SSL Handshake. * * @param host - * Server Host Name for SSL Handshake + * Server Host Name for SSL Handshake * @param port - * Server Port for SSL Handshake + * Server Port for SSL Handshake * @throws SQLServerException */ - void enableSSL(String host, - int port) throws SQLServerException { + void enableSSL(String host, int port) throws SQLServerException { // If enabling SSL fails, which it can for a number of reasons, the following items // are used in logging information to the TDS channel logger to help diagnose the problem. - Provider tmfProvider = null; // TrustManagerFactory provider + Provider tmfProvider = null; // TrustManagerFactory provider Provider sslContextProvider = null; // SSLContext provider - Provider ksProvider = null; // KeyStore provider - String tmfDefaultAlgorithm = null; // Default algorithm (typically X.509) used by the TrustManagerFactory + Provider ksProvider = null; // KeyStore provider + String tmfDefaultAlgorithm = null; // Default algorithm (typically X.509) used by the TrustManagerFactory SSLHandhsakeState handshakeState = SSLHandhsakeState.SSL_HANDHSAKE_NOT_STARTED; boolean isFips = false; @@ -1606,30 +1571,35 @@ void enableSSL(String host, if (logger.isLoggable(Level.FINER)) logger.finer(toString() + " Enabling SSL..."); - String trustStoreFileName = con.activeConnectionProperties.getProperty(SQLServerDriverStringProperty.TRUST_STORE.toString()); - String trustStorePassword = con.activeConnectionProperties.getProperty(SQLServerDriverStringProperty.TRUST_STORE_PASSWORD.toString()); + String trustStoreFileName = con.activeConnectionProperties + .getProperty(SQLServerDriverStringProperty.TRUST_STORE.toString()); + String trustStorePassword = con.activeConnectionProperties + .getProperty(SQLServerDriverStringProperty.TRUST_STORE_PASSWORD.toString()); String hostNameInCertificate = con.activeConnectionProperties .getProperty(SQLServerDriverStringProperty.HOSTNAME_IN_CERTIFICATE.toString()); - trustStoreType = con.activeConnectionProperties.getProperty(SQLServerDriverStringProperty.TRUST_STORE_TYPE.toString()); - - if(StringUtils.isEmpty(trustStoreType)) { + trustStoreType = con.activeConnectionProperties + .getProperty(SQLServerDriverStringProperty.TRUST_STORE_TYPE.toString()); + + if (StringUtils.isEmpty(trustStoreType)) { trustStoreType = SQLServerDriverStringProperty.TRUST_STORE_TYPE.getDefaultValue(); } - - isFips = Boolean.valueOf(con.activeConnectionProperties.getProperty(SQLServerDriverBooleanProperty.FIPS.toString())); - sslProtocol = con.activeConnectionProperties.getProperty(SQLServerDriverStringProperty.SSL_PROTOCOL.toString()); - + + isFips = Boolean.valueOf( + con.activeConnectionProperties.getProperty(SQLServerDriverBooleanProperty.FIPS.toString())); + sslProtocol = con.activeConnectionProperties + .getProperty(SQLServerDriverStringProperty.SSL_PROTOCOL.toString()); + if (isFips) { validateFips(trustStoreType, trustStoreFileName); } assert TDS.ENCRYPT_OFF == con.getRequestedEncryptionLevel() || // Login only SSL - TDS.ENCRYPT_ON == con.getRequestedEncryptionLevel(); // Full SSL + TDS.ENCRYPT_ON == con.getRequestedEncryptionLevel(); // Full SSL assert TDS.ENCRYPT_OFF == con.getNegotiatedEncryptionLevel() || // Login only SSL TDS.ENCRYPT_ON == con.getNegotiatedEncryptionLevel() || // Full SSL - TDS.ENCRYPT_REQ == con.getNegotiatedEncryptionLevel(); // Full SSL + TDS.ENCRYPT_REQ == con.getNegotiatedEncryptionLevel(); // Full SSL // If we requested login only SSL or full SSL without server certificate validation, // then we'll "validate" the server certificate using a naive TrustManager that trusts @@ -1653,9 +1623,9 @@ else if (con.getTrustManagerClass() != null) { String constructorArg = con.getTrustManagerConstructorArg(); if (constructorArg == null) { tm = new TrustManager[] {(TrustManager) tmClass.getDeclaredConstructor().newInstance()}; - } - else { - tm = new TrustManager[] {(TrustManager) tmClass.getDeclaredConstructor(String.class).newInstance(constructorArg)}; + } else { + tm = new TrustManager[] { + (TrustManager) tmClass.getDeclaredConstructor(String.class).newInstance(constructorArg)}; } } // Otherwise, we'll validate the certificate using a real TrustManager obtained @@ -1682,7 +1652,6 @@ else if (con.getTrustManagerClass() != null) { if (logger.isLoggable(Level.FINEST)) logger.finest(toString() + " Finding key store interface"); - ks = KeyStore.getInstance(trustStoreType); ksProvider = ks.getProvider(); @@ -1699,17 +1668,16 @@ else if (con.getTrustManagerClass() != null) { try { ks.load(is, (null == trustStorePassword) ? null : trustStorePassword.toCharArray()); - } - finally { + } finally { // We are done with the trustStorePassword (if set). Clear it for better security. - con.activeConnectionProperties.remove(SQLServerDriverStringProperty.TRUST_STORE_PASSWORD.toString()); + con.activeConnectionProperties + .remove(SQLServerDriverStringProperty.TRUST_STORE_PASSWORD.toString()); // We are also done with the trust store input stream. if (null != is) { try { is.close(); - } - catch (IOException e) { + } catch (IOException e) { if (logger.isLoggable(Level.FINE)) logger.fine(toString() + " Ignoring error closing trust material InputStream..."); } @@ -1744,10 +1712,11 @@ else if (con.getTrustManagerClass() != null) { // if the host name in cert provided use it or use the host name Only if it is not FIPS if (!isFips) { if (null != hostNameInCertificate) { - tm = new TrustManager[] {new HostNameOverrideX509TrustManager(this, (X509TrustManager) tm[0], hostNameInCertificate)}; - } - else { - tm = new TrustManager[] {new HostNameOverrideX509TrustManager(this, (X509TrustManager) tm[0], host)}; + tm = new TrustManager[] {new HostNameOverrideX509TrustManager(this, (X509TrustManager) tm[0], + hostNameInCertificate)}; + } else { + tm = new TrustManager[] { + new HostNameOverrideX509TrustManager(this, (X509TrustManager) tm[0], host)}; } } } // end if (!con.trustServerCertificate()) @@ -1775,8 +1744,9 @@ else if (con.getTrustManagerClass() != null) { if (logger.isLoggable(Level.FINEST)) logger.finest(toString() + " Creating SSL socket"); - sslSocket = (SSLSocket) sslContext.getSocketFactory().createSocket(proxySocket, host, port, false); // don't close proxy when SSL socket - // is closed + // don't close proxy when SSL socket is closed + sslSocket = (SSLSocket) sslContext.getSocketFactory().createSocket(proxySocket, host, port, false); + // At long last, start the SSL handshake ... if (logger.isLoggable(Level.FINER)) logger.finer(toString() + " Starting SSL handshake"); @@ -1808,8 +1778,7 @@ else if (con.getTrustManagerClass() != null) { if (logger.isLoggable(Level.FINER)) logger.finer(toString() + " SSL enabled"); - } - catch (Exception e) { + } catch (Exception e) { // Log the original exception and its source at FINER level if (logger.isLoggable(Level.FINER)) logger.log(Level.FINER, e.getMessage(), e); @@ -1819,21 +1788,26 @@ else if (con.getTrustManagerClass() != null) { // This is because due to an intermittent TLS 1.2 connection issue, we will be retrying the connection and // do not want to print this message in console. if (logger.isLoggable(Level.FINER)) - logger.log(Level.FINER, - "java.security path: " + JAVA_SECURITY + "\n" + "Security providers: " + Arrays.asList(Security.getProviders()) + "\n" - + ((null != sslContextProvider) ? ("SSLContext provider info: " + sslContextProvider.getInfo() + "\n" - + "SSLContext provider services:\n" + sslContextProvider.getServices() + "\n") : "") - + ((null != tmfProvider) ? ("TrustManagerFactory provider info: " + tmfProvider.getInfo() + "\n") : "") - + ((null != tmfDefaultAlgorithm) ? ("TrustManagerFactory default algorithm: " + tmfDefaultAlgorithm + "\n") : "") - + ((null != ksProvider) ? ("KeyStore provider info: " + ksProvider.getInfo() + "\n") : "") + "java.ext.dirs: " - + System.getProperty("java.ext.dirs")); + logger.log(Level.FINER, "java.security path: " + JAVA_SECURITY + "\n" + "Security providers: " + + Arrays.asList(Security.getProviders()) + "\n" + + ((null != sslContextProvider) ? ("SSLContext provider info: " + sslContextProvider.getInfo() + + "\n" + "SSLContext provider services:\n" + sslContextProvider.getServices() + "\n") + : "") + + ((null != tmfProvider) ? ("TrustManagerFactory provider info: " + tmfProvider.getInfo() + + "\n") : "") + + ((null != tmfDefaultAlgorithm) ? ("TrustManagerFactory default algorithm: " + + tmfDefaultAlgorithm + "\n") : "") + + ((null != ksProvider) ? ("KeyStore provider info: " + ksProvider.getInfo() + "\n") : "") + + "java.ext.dirs: " + System.getProperty("java.ext.dirs")); MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_sslFailed")); Object[] msgArgs = {e.getMessage()}; - // It is important to get the localized message here, otherwise error messages won't match for different locales. + // It is important to get the localized message here, otherwise error messages won't match for different + // locales. String errMsg = e.getLocalizedMessage(); - // If the message is null replace it with the non-localized message or a dummy string. This can happen if a custom + // If the message is null replace it with the non-localized message or a dummy string. This can happen if a + // custom // TrustManager implementation is specified that does not provide localized messages. if (errMsg == null) { errMsg = e.getMessage(); @@ -1851,8 +1825,7 @@ else if (con.getTrustManagerClass() != null) { if (e instanceof IOException && (SSLHandhsakeState.SSL_HANDHSAKE_STARTED == handshakeState) && (errMsg.equals(SQLServerException.getErrString("R_truncatedServerResponse")))) { con.terminate(SQLServerException.DRIVER_ERROR_INTERMITTENT_TLS_FAILED, form.format(msgArgs), e); - } - else { + } else { con.terminate(SQLServerException.DRIVER_ERROR_SSL_FAILED, form.format(msgArgs), e); } } @@ -1871,8 +1844,7 @@ else if (con.getTrustManagerClass() != null) { * @throws SQLServerException * @since 6.1.4 */ - private void validateFips(final String trustStoreType, - final String trustStoreFileName) throws SQLServerException { + private void validateFips(final String trustStoreType, final String trustStoreFileName) throws SQLServerException { boolean isValid = false; boolean isEncryptOn; boolean isValidTrustStoreType; @@ -1887,11 +1859,11 @@ private void validateFips(final String trustStoreType, isValidTrustStore = !StringUtils.isEmpty(trustStoreFileName); isTrustServerCertificate = con.trustServerCertificate(); - if (isEncryptOn && !isTrustServerCertificate) { + if (isEncryptOn && !isTrustServerCertificate) { isValid = true; if (isValidTrustStore && !isValidTrustStoreType) { - // In case of valid trust store we need to check TrustStoreType. - isValid = false; + // In case of valid trust store we need to check TrustStoreType. + isValid = false; if (logger.isLoggable(Level.FINER)) logger.finer(toString() + "TrustStoreType is required alongside with TrustStore."); } @@ -1912,15 +1884,17 @@ private void validateFips(final String trustStoreType, /** * Loads the contents of a trust store into an InputStream. * - * When a location to a trust store is specified, this method attempts to load that store. Otherwise, it looks for and attempts to load the - * default trust store using essentially the same logic (outlined in the JSSE Reference Guide) as the default X.509 TrustManagerFactory. + * When a location to a trust store is specified, this method attempts to load that store. Otherwise, it looks for + * and attempts to load the default trust store using essentially the same logic (outlined in the JSSE Reference + * Guide) as the default X.509 TrustManagerFactory. * * @return an InputStream containing the contents of the loaded trust store * @return null if the trust store cannot be loaded. * - * Note: It is by design that this function returns null when the trust store cannot be loaded rather than throwing an exception. The - * reason is that KeyStore.load, which uses the returned InputStream, interprets a null InputStream to mean that there are no trusted - * certificates, which mirrors the behavior of the default (no trust store, no password specified) path. + * Note: It is by design that this function returns null when the trust store cannot be loaded rather than + * throwing an exception. The reason is that KeyStore.load, which uses the returned InputStream, interprets + * a null InputStream to mean that there are no trusted certificates, which mirrors the behavior of the + * default (no trust store, no password specified) path. */ final InputStream loadTrustStore(String trustStoreFileName) { FileInputStream is = null; @@ -1932,8 +1906,7 @@ final InputStream loadTrustStore(String trustStoreFileName) { logger.finest(toString() + " Opening specified trust store: " + trustStoreFileName); is = new FileInputStream(trustStoreFileName); - } - catch (FileNotFoundException e) { + } catch (FileNotFoundException e) { if (logger.isLoggable(Level.FINE)) logger.fine(toString() + " Trust store not found: " + e.getMessage()); @@ -1947,11 +1920,11 @@ final InputStream loadTrustStore(String trustStoreFileName) { else if (null != (trustStoreFileName = System.getProperty("javax.net.ssl.trustStore"))) { try { if (logger.isLoggable(Level.FINEST)) - logger.finest(toString() + " Opening default trust store (from javax.net.ssl.trustStore): " + trustStoreFileName); + logger.finest(toString() + " Opening default trust store (from javax.net.ssl.trustStore): " + + trustStoreFileName); is = new FileInputStream(trustStoreFileName); - } - catch (FileNotFoundException e) { + } catch (FileNotFoundException e) { if (logger.isLoggable(Level.FINE)) logger.fine(toString() + " Trust store not found: " + e.getMessage()); @@ -1968,8 +1941,7 @@ else if (null != (trustStoreFileName = System.getProperty("javax.net.ssl.trustSt logger.finest(toString() + " Opening default trust store: " + JSSECACERTS); is = new FileInputStream(JSSECACERTS); - } - catch (FileNotFoundException e) { + } catch (FileNotFoundException e) { if (logger.isLoggable(Level.FINE)) logger.fine(toString() + " Trust store not found: " + e.getMessage()); } @@ -1981,8 +1953,7 @@ else if (null != (trustStoreFileName = System.getProperty("javax.net.ssl.trustSt logger.finest(toString() + " Opening default trust store: " + CACERTS); is = new FileInputStream(CACERTS); - } - catch (FileNotFoundException e) { + } catch (FileNotFoundException e) { if (logger.isLoggable(Level.FINE)) logger.fine(toString() + " Trust store not found: " + e.getMessage()); @@ -1995,20 +1966,16 @@ else if (null != (trustStoreFileName = System.getProperty("javax.net.ssl.trustSt return is; } - final int read(byte[] data, - int offset, - int length) throws SQLServerException { + final int read(byte[] data, int offset, int length) throws SQLServerException { try { return inputStream.read(data, offset, length); - } - catch (IOException e) { + } catch (IOException e) { if (logger.isLoggable(Level.FINE)) logger.fine(toString() + " read failed:" + e.getMessage()); if (e instanceof SocketTimeoutException) { con.terminate(SQLServerException.ERROR_SOCKET_TIMEOUT, e.getMessage(), e); - } - else { + } else { con.terminate(SQLServerException.DRIVER_ERROR_IO_FAILED, e.getMessage(), e); } @@ -2016,13 +1983,10 @@ final int read(byte[] data, } } - final void write(byte[] data, - int offset, - int length) throws SQLServerException { + final void write(byte[] data, int offset, int length) throws SQLServerException { try { outputStream.write(data, offset, length); - } - catch (IOException e) { + } catch (IOException e) { if (logger.isLoggable(Level.FINER)) logger.finer(toString() + " write failed:" + e.getMessage()); @@ -2033,8 +1997,7 @@ final void write(byte[] data, final void flush() throws SQLServerException { try { outputStream.flush(); - } - catch (IOException e) { + } catch (IOException e) { if (logger.isLoggable(Level.FINER)) logger.finer(toString() + " flush failed:" + e.getMessage()); @@ -2052,8 +2015,7 @@ final void close() { try { inputStream.close(); - } - catch (IOException e) { + } catch (IOException e) { if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, this.toString() + ": Ignored error closing inputStream", e); } @@ -2065,8 +2027,7 @@ final void close() { try { outputStream.close(); - } - catch (IOException e) { + } catch (IOException e) { if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, this.toString() + ": Ignored error closing outputStream", e); } @@ -2078,8 +2039,7 @@ final void close() { try { tcpSocket.close(); - } - catch (IOException e) { + } catch (IOException e) { if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, this.toString() + ": Ignored error closing socket", e); } @@ -2090,33 +2050,33 @@ final void close() { * Logs TDS packet data to the com.microsoft.sqlserver.jdbc.TDS.DATA logger * * @param data - * the buffer containing the TDS packet payload data to log + * the buffer containing the TDS packet payload data to log * @param nStartOffset - * offset into the above buffer from where to start logging + * offset into the above buffer from where to start logging * @param nLength - * length (in bytes) of payload + * length (in bytes) of payload * @param messageDetail - * other loggable details about the payload + * other loggable details about the payload */ - /* L0 */ void logPacket(byte data[], - int nStartOffset, - int nLength, - String messageDetail) { + /* L0 */ void logPacket(byte data[], int nStartOffset, int nLength, String messageDetail) { assert 0 <= nLength && nLength <= data.length; assert 0 <= nStartOffset && nStartOffset <= data.length; final char hexChars[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; - final char printableChars[] = {'.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', - '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', ' ', '!', '\"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', - 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', - 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', '.', - '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', - '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', - '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', - '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', - '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.'}; + final char printableChars[] = {'.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', + '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', ' ', '!', '\"', '#', + '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', + 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', '`', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', + 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', + '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', + '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', + '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', + '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', + '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', + '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.', '.'}; // Log message body lines have this form: // @@ -2124,8 +2084,9 @@ final void close() { // 012345678911111111112222222222333333333344444444445555555555666666 // 01234567890123456789012345678901234567890123456789012345 // - final char lineTemplate[] = {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', - ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', + final char lineTemplate[] = {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', + ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', + ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', @@ -2138,16 +2099,17 @@ final void close() { // before writing it out. So use an initial size large enough // that the buffer doesn't have to resize itself. StringBuilder logMsg = new StringBuilder(messageDetail.length() + // Message detail - 4 * nLength + // 2-digit hex + space + ASCII, per byte - 4 * (1 + nLength / 16) + // 2 extra spaces + CR/LF, per line (16 bytes per line) - 80); // Extra fluff: IP:Port, Connection #, SPID, ... + 4 * nLength + // 2-digit hex + space + ASCII, per byte + 4 * (1 + nLength / 16) + // 2 extra spaces + CR/LF, per line (16 bytes per line) + 80); // Extra fluff: IP:Port, Connection #, SPID, ... // Format the headline like so: // /157.55.121.182:2983 Connection 1, SPID 53, Message info here ... // // Note: the log formatter itself timestamps what we write so we don't have // to do it again here. - logMsg.append(tcpSocket.getLocalAddress().toString() + ":" + tcpSocket.getLocalPort() + " SPID:" + spid + " " + messageDetail + "\r\n"); + logMsg.append(tcpSocket.getLocalAddress().toString() + ":" + tcpSocket.getLocalPort() + " SPID:" + spid + " " + + messageDetail + "\r\n"); // Fill in the body of the log message, line by line, 16 bytes per line. int nBytesLogged = 0; @@ -2183,7 +2145,8 @@ final void close() { * Get the current socket SO_TIMEOUT value. * * @return the current socket timeout value - * @throws IOException thrown if the socket timeout cannot be read + * @throws IOException + * thrown if the socket timeout cannot be read */ final int getNetworkTimeout() throws IOException { return tcpSocket.getSoTimeout(); @@ -2192,39 +2155,44 @@ final int getNetworkTimeout() throws IOException { /** * Set the socket SO_TIMEOUT value. * - * @param timeout the socket timeout in milliseconds - * @throws IOException thrown if the socket timeout cannot be set + * @param timeout + * the socket timeout in milliseconds + * @throws IOException + * thrown if the socket timeout cannot be set */ final void setNetworkTimeout(int timeout) throws IOException { tcpSocket.setSoTimeout(timeout); } } + /** - * SocketFinder is used to find a server socket to which a connection can be made. This class abstracts the logic of finding a socket from TDSChannel - * class. + * SocketFinder is used to find a server socket to which a connection can be made. This class abstracts the logic of + * finding a socket from TDSChannel class. * - * In the case when useParallel is set to true, this is achieved by trying to make parallel connections to multiple IP addresses. This class is - * responsible for spawning multiple threads and keeping track of the search result and the connected socket or exception to be thrown. + * In the case when useParallel is set to true, this is achieved by trying to make parallel connections to multiple IP + * addresses. This class is responsible for spawning multiple threads and keeping track of the search result and the + * connected socket or exception to be thrown. * * In the case where multiSubnetFailover is false, we try our old logic of trying to connect to the first ip address * - * Typical usage of this class is SocketFinder sf = new SocketFinder(traceId, conn); Socket = sf.getSocket(hostName, port, timeout); + * Typical usage of this class is SocketFinder sf = new SocketFinder(traceId, conn); Socket = sf.getSocket(hostName, + * port, timeout); */ final class SocketFinder { /** * Indicates the result of a search */ enum Result { - UNKNOWN,// search is still in progress - SUCCESS,// found a socket + UNKNOWN, // search is still in progress + SUCCESS, // found a socket FAILURE// failed in finding a socket } // Thread pool - the values in the constructor are chosen based on the // explanation given in design_connection_director_multisubnet.doc - private static final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 5, TimeUnit.SECONDS, - new SynchronousQueue()); + private static final ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 5, + TimeUnit.SECONDS, new SynchronousQueue()); // When parallel connections are to be used, use minimum timeout slice of 1500 milliseconds. private static final int minTimeoutForParallelConnections = 1500; @@ -2271,12 +2239,11 @@ enum Result { * Constructs a new SocketFinder object with appropriate traceId * * @param callerTraceID - * traceID of the caller + * traceID of the caller * @param sqlServerConnection - * the SQLServer connection + * the SQLServer connection */ - SocketFinder(String callerTraceID, - SQLServerConnection sqlServerConnection) { + SocketFinder(String callerTraceID, SQLServerConnection sqlServerConnection) { traceID = "SocketFinder(" + callerTraceID + ")"; conn = sqlServerConnection; } @@ -2290,19 +2257,15 @@ enum Result { * @return connected socket * @throws IOException */ - Socket findSocket(String hostName, - int portNumber, - int timeoutInMilliSeconds, - boolean useParallel, - boolean useTnir, - boolean isTnirFirstAttempt, - int timeoutInMilliSecondsForFullTimeout) throws SQLServerException { + Socket findSocket(String hostName, int portNumber, int timeoutInMilliSeconds, boolean useParallel, boolean useTnir, + boolean isTnirFirstAttempt, int timeoutInMilliSecondsForFullTimeout) throws SQLServerException { assert timeoutInMilliSeconds != 0 : "The driver does not allow a time out of 0"; try { InetAddress[] inetAddrs = null; - // inetAddrs is only used if useParallel is true or TNIR is true. Skip resolving address if that's not the case. + // inetAddrs is only used if useParallel is true or TNIR is true. Skip resolving address if that's not the + // case. if (useParallel || useTnir) { // Ignore TNIR if host resolves to more than 64 IPs. Make sure we are using original timeout for this. inetAddrs = InetAddress.getAllByName(hostName); @@ -2318,8 +2281,7 @@ Socket findSocket(String hostName, // For TNIR first attempt, we should do existing behavior including how host name is resolved. if (useTnir && isTnirFirstAttempt) { return getDefaultSocket(hostName, portNumber, SQLServerConnection.TnirFirstAttemptTimeoutMs); - } - else if (!useTnir) { + } else if (!useTnir) { return getDefaultSocket(hostName, portNumber, timeoutInMilliSeconds); } } @@ -2331,7 +2293,7 @@ else if (!useTnir) { loggingString.append(" Total no of InetAddresses: "); loggingString.append(inetAddrs.length); loggingString.append(". They are: "); - + for (InetAddress inetAddr : inetAddrs) { loggingString.append(inetAddr.toString() + ";"); } @@ -2340,7 +2302,8 @@ else if (!useTnir) { } if (inetAddrs.length > ipAddressLimit) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_ipAddressLimitWithMultiSubnetFailover")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_ipAddressLimitWithMultiSubnetFailover")); Object[] msgArgs = {Integer.toString(ipAddressLimit)}; String errorStr = form.format(msgArgs); // we do not want any retry to happen here. So, terminate the connection @@ -2352,14 +2315,13 @@ else if (!useTnir) { // Single address so do not start any threads return getConnectedSocket(inetAddrs[0], portNumber, timeoutInMilliSeconds); } - timeoutInMilliSeconds = Math.max(timeoutInMilliSeconds, minTimeoutForParallelConnections); + timeoutInMilliSeconds = Math.max(timeoutInMilliSeconds, minTimeoutForParallelConnections); if (Util.isIBM()) { if (logger.isLoggable(Level.FINER)) { logger.finer(this.toString() + "Using Java NIO with timeout:" + timeoutInMilliSeconds); } findSocketUsingJavaNIO(inetAddrs, portNumber, timeoutInMilliSeconds); - } - else { + } else { if (logger.isLoggable(Level.FINER)) { logger.finer(this.toString() + "Using Threading with timeout:" + timeoutInMilliSeconds); } @@ -2397,15 +2359,13 @@ else if (!useTnir) { throw selectedException; } - } - catch (InterruptedException ex) { + } catch (InterruptedException ex) { // re-interrupt the current thread, in order to restore the thread's interrupt status. Thread.currentThread().interrupt(); - + close(selectedSocket); SQLServerException.ConvertConnectExceptionToSQLServerException(hostName, portNumber, conn, ex); - } - catch (IOException ex) { + } catch (IOException ex) { close(selectedSocket); // The code below has been moved from connectHelper. // If we do not move it, the functions open(caller of findSocket) @@ -2427,18 +2387,17 @@ else if (!useTnir) { } /** - * This function uses java NIO to connect to all the addresses in inetAddrs with in a specified timeout. If it succeeds in connecting, it closes - * all the other open sockets and updates the result to success. + * This function uses java NIO to connect to all the addresses in inetAddrs with in a specified timeout. If it + * succeeds in connecting, it closes all the other open sockets and updates the result to success. * * @param inetAddrs - * the array of inetAddress to which connection should be made + * the array of inetAddress to which connection should be made * @param portNumber - * the port number at which connection should be made + * the port number at which connection should be made * @param timeoutInMilliSeconds * @throws IOException */ - private void findSocketUsingJavaNIO(InetAddress[] inetAddrs, - int portNumber, + private void findSocketUsingJavaNIO(InetAddress[] inetAddrs, int portNumber, int timeoutInMilliSeconds) throws IOException { // The driver does not allow a time out of zero. // Also, the unit of time the user can specify in the driver is seconds. @@ -2468,7 +2427,8 @@ private void findSocketUsingJavaNIO(InetAddress[] inetAddrs, sChannel.connect(new InetSocketAddress(inetAddr, portNumber)); if (logger.isLoggable(Level.FINER)) - logger.finer(this.toString() + " initiated connection to address: " + inetAddr + ", portNumber: " + portNumber); + logger.finer(this.toString() + " initiated connection to address: " + inetAddr + ", portNumber: " + + portNumber); } long timerNow = System.currentTimeMillis(); @@ -2504,7 +2464,8 @@ private void findSocketUsingJavaNIO(InetAddress[] inetAddrs, SocketChannel ch = (SocketChannel) key.channel(); if (logger.isLoggable(Level.FINER)) - logger.finer(this.toString() + " processing the channel :" + ch);// this traces the IP by default + logger.finer(this.toString() + " processing the channel :" + ch);// this traces the IP by + // default boolean connected = false; try { @@ -2520,11 +2481,10 @@ private void findSocketUsingJavaNIO(InetAddress[] inetAddrs, logger.finer(this.toString() + " selected the channel :" + selectedChannel); break; - } - catch (IOException ex) { + } catch (IOException ex) { if (logger.isLoggable(Level.FINER)) - logger.finer(this.toString() + " the exception: " + ex.getClass() + " with message: " + ex.getMessage() - + " occured while processing the channel: " + ch); + logger.finer(this.toString() + " the exception: " + ex.getClass() + " with message: " + + ex.getMessage() + " occured while processing the channel: " + ch); updateSelectedException(ex, this.toString()); // close the channel pro-actively so that we do not // rely to network resources @@ -2540,15 +2500,13 @@ private void findSocketUsingJavaNIO(InetAddress[] inetAddrs, timerNow = System.currentTimeMillis(); } - } - catch (IOException ex) { + } catch (IOException ex) { // in case of an exception, close the selected channel. // All other channels will be closed in the finally block, // as they need to be closed irrespective of a success/failure close(selectedChannel); throw ex; - } - finally { + } finally { // close the selector // As per java docs, on selector.close(), any uncancelled keys still // associated with this @@ -2586,9 +2544,7 @@ private void findSocketUsingJavaNIO(InetAddress[] inetAddrs, // In the old code below, the logic around 0 timeout has been removed as // 0 timeout is not allowed. The code has been re-factored so that the logic // is common for hostName or InetAddress. - private Socket getDefaultSocket(String hostName, - int portNumber, - int timeoutInMilliSeconds) throws IOException { + private Socket getDefaultSocket(String hostName, int portNumber, int timeoutInMilliSeconds) throws IOException { // Open the socket, with or without a timeout, throwing an UnknownHostException // if there is a failure to resolve the host name to an InetSocketAddress. // @@ -2599,15 +2555,13 @@ private Socket getDefaultSocket(String hostName, return getConnectedSocket(addr, timeoutInMilliSeconds); } - private Socket getConnectedSocket(InetAddress inetAddr, - int portNumber, + private Socket getConnectedSocket(InetAddress inetAddr, int portNumber, int timeoutInMilliSeconds) throws IOException { InetSocketAddress addr = new InetSocketAddress(inetAddr, portNumber); return getConnectedSocket(addr, timeoutInMilliSeconds); } - private Socket getConnectedSocket(InetSocketAddress addr, - int timeoutInMilliSeconds) throws IOException { + private Socket getConnectedSocket(InetSocketAddress addr, int timeoutInMilliSeconds) throws IOException { assert timeoutInMilliSeconds != 0 : "timeout cannot be zero"; if (addr.isUnresolved()) throw new java.net.UnknownHostException(); @@ -2616,11 +2570,10 @@ private Socket getConnectedSocket(InetSocketAddress addr, return selectedSocket; } - private void findSocketUsingThreading(InetAddress[] inetAddrs, - int portNumber, + private void findSocketUsingThreading(InetAddress[] inetAddrs, int portNumber, int timeoutInMilliSeconds) throws IOException, InterruptedException { assert timeoutInMilliSeconds != 0 : "The timeout cannot be zero"; - + assert inetAddrs.length != 0 : "Number of inetAddresses should not be zero in this function"; LinkedList sockets = new LinkedList<>(); @@ -2636,7 +2589,8 @@ private void findSocketUsingThreading(InetAddress[] inetAddrs, InetSocketAddress inetSocketAddress = new InetSocketAddress(inetAddress, portNumber); - SocketConnector socketConnector = new SocketConnector(s, inetSocketAddress, timeoutInMilliSeconds, this); + SocketConnector socketConnector = new SocketConnector(s, inetSocketAddress, timeoutInMilliSeconds, + this); socketConnectors.add(socketConnector); } @@ -2654,8 +2608,9 @@ private void findSocketUsingThreading(InetAddress[] inetAddrs, long timeRemaining = timerExpire - timerNow; if (logger.isLoggable(Level.FINER)) { - logger.finer(this.toString() + " TimeRemaining:" + timeRemaining + "; Result:" + result + "; Max. open thread count: " - + threadPoolExecutor.getLargestPoolSize() + "; Current open thread count:" + threadPoolExecutor.getActiveCount()); + logger.finer(this.toString() + " TimeRemaining:" + timeRemaining + "; Result:" + result + + "; Max. open thread count: " + threadPoolExecutor.getLargestPoolSize() + + "; Current open thread count:" + threadPoolExecutor.getActiveCount()); } // if there is no time left or if the result is determined, break. @@ -2683,8 +2638,7 @@ private void findSocketUsingThreading(InetAddress[] inetAddrs, } - } - finally { + } finally { // Close all sockets except the selected one. // As we close sockets pro-actively in the child threads, // its possible that we close a socket twice. @@ -2700,8 +2654,8 @@ private void findSocketUsingThreading(InetAddress[] inetAddrs, } } } - - if (selectedSocket != null) { + + if (selectedSocket != null) { result = Result.SUCCESS; } } @@ -2720,8 +2674,7 @@ void close(Selector selector) { try { selector.close(); - } - catch (IOException e) { + } catch (IOException e) { if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, this.toString() + ": Ignored the following error while closing Selector", e); } @@ -2735,8 +2688,7 @@ void close(Socket socket) { try { socket.close(); - } - catch (IOException e) { + } catch (IOException e) { if (logger.isLoggable(Level.FINE)) logger.log(Level.FINE, this.toString() + ": Ignored the following error while closing socket", e); } @@ -2750,29 +2702,28 @@ void close(SocketChannel socketChannel) { try { socketChannel.close(); - } - catch (IOException e) { + } catch (IOException e) { if (logger.isLoggable(Level.FINE)) - logger.log(Level.FINE, this.toString() + "Ignored the following error while closing socketChannel", e); + logger.log(Level.FINE, this.toString() + "Ignored the following error while closing socketChannel", + e); } } } /** - * Used by socketConnector threads to notify the socketFinder of their connection attempt result(a connected socket or exception). It updates the - * result, socket and exception variables of socketFinder object. This method notifies the parent thread if a socket is found or if all the - * spawned threads have notified. It also closes a socket if it is not selected for use by socketFinder. + * Used by socketConnector threads to notify the socketFinder of their connection attempt result(a connected socket + * or exception). It updates the result, socket and exception variables of socketFinder object. This method notifies + * the parent thread if a socket is found or if all the spawned threads have notified. It also closes a socket if it + * is not selected for use by socketFinder. * * @param socket - * the SocketConnector's socket + * the SocketConnector's socket * @param exception - * Exception that occurred in socket connector thread + * Exception that occurred in socket connector thread * @param threadId - * Id of the calling Thread for diagnosis + * Id of the calling Thread for diagnosis */ - void updateResult(Socket socket, - IOException exception, - String threadId) { + void updateResult(Socket socket, IOException exception, String threadId) { if (result.equals(Result.UNKNOWN)) { if (logger.isLoggable(Level.FINER)) { logger.finer("The following child thread is waiting for socketFinderLock:" + threadId); @@ -2844,7 +2795,9 @@ void updateResult(Socket socket, } if (logger.isLoggable(Level.FINER)) { - logger.finer("The following child thread released parentThreadLock and notified the parent thread:" + threadId); + logger.finer( + "The following child thread released parentThreadLock and notified the parent thread:" + + threadId); } } } @@ -2863,27 +2816,27 @@ void updateResult(Socket socket, *

* b) ex is a non-socketTimeoutException and selectedException is a socketTimeoutException *

- * If there are multiple exceptions, that are not related to socketTimeout the first non-socketTimeout exception is picked. If all exceptions are - * related to socketTimeout, the first exception is picked. Note: This method is not thread safe. The caller should ensure thread safety. + * If there are multiple exceptions, that are not related to socketTimeout the first non-socketTimeout exception is + * picked. If all exceptions are related to socketTimeout, the first exception is picked. Note: This method is not + * thread safe. The caller should ensure thread safety. * * @param ex - * the IOException + * the IOException * @param traceId - * the traceId of the thread + * the traceId of the thread */ - public void updateSelectedException(IOException ex, - String traceId) { + public void updateSelectedException(IOException ex, String traceId) { boolean updatedException = false; - if (selectedException == null || - (!(ex instanceof SocketTimeoutException)) && (selectedException instanceof SocketTimeoutException)) { + if (selectedException == null + || (!(ex instanceof SocketTimeoutException)) && (selectedException instanceof SocketTimeoutException)) { selectedException = ex; updatedException = true; } if (updatedException) { if (logger.isLoggable(Level.FINER)) { - logger.finer("The selected exception is updated to the following: ExceptionType:" + ex.getClass() + "; ExceptionMessage:" - + ex.getMessage() + "; by the following thread:" + traceId); + logger.finer("The selected exception is updated to the following: ExceptionType:" + ex.getClass() + + "; ExceptionMessage:" + ex.getMessage() + "; by the following thread:" + traceId); } } } @@ -2898,6 +2851,7 @@ public String toString() { } } + /** * This is used to connect a socket in a separate thread */ @@ -2928,9 +2882,7 @@ final class SocketConnector implements Runnable { /** * Constructs a new SocketConnector object with the associated socket and socketFinder */ - SocketConnector(Socket socket, - InetSocketAddress inetSocketAddress, - int timeOutInMilliSeconds, + SocketConnector(Socket socket, InetSocketAddress inetSocketAddress, int timeOutInMilliSeconds, SocketFinder socketFinder) { this.socket = socket; this.inetSocketAddress = inetSocketAddress; @@ -2941,8 +2893,8 @@ final class SocketConnector implements Runnable { } /** - * If search for socket has not finished, this function tries to connect a socket(with a timeout) synchronously. It further notifies the - * socketFinder the result of the connection attempt + * If search for socket has not finished, this function tries to connect a socket(with a timeout) synchronously. It + * further notifies the socketFinder the result of the connection attempt */ public void run() { IOException exception = null; @@ -2953,13 +2905,12 @@ public void run() { if (result.equals(SocketFinder.Result.UNKNOWN)) { try { if (logger.isLoggable(Level.FINER)) { - logger.finer( - this.toString() + " connecting to InetSocketAddress:" + inetSocketAddress + " with timeout:" + timeoutInMilliseconds); + logger.finer(this.toString() + " connecting to InetSocketAddress:" + inetSocketAddress + + " with timeout:" + timeoutInMilliseconds); } socket.connect(inetSocketAddress, timeoutInMilliseconds); - } - catch (IOException ex) { + } catch (IOException ex) { if (logger.isLoggable(Level.FINER)) { logger.finer(this.toString() + " exception:" + ex.getClass() + " with message:" + ex.getMessage() + " occured while connecting to InetSocketAddress:" + inetSocketAddress); @@ -2989,14 +2940,14 @@ private static synchronized long nextThreadID() { if (logger.isLoggable(Level.FINER)) logger.finer("Resetting the Id count"); lastThreadID = 1; - } - else { + } else { lastThreadID++; } return lastThreadID; } } + /** * TDSWriter implements the client to server TDS data pipe. */ @@ -3077,8 +3028,7 @@ boolean isEOMSent() { private CryptoMetadata cryptoMeta = null; - TDSWriter(TDSChannel tdsChannel, - SQLServerConnection con) { + TDSWriter(TDSChannel tdsChannel, SQLServerConnection con) { this.tdsChannel = tdsChannel; this.con = con; traceID = "TDSWriter@" + Integer.toHexString(hashCode()) + " (" + con.toString() + ")"; @@ -3089,7 +3039,7 @@ boolean isEOMSent() { void preparePacket() throws SQLServerException { if (tdsChannel.isLoggingPackets()) { Arrays.fill(logBuffer.array(), (byte) 0xFE); - ((Buffer)logBuffer).clear(); + ((Buffer) logBuffer).clear(); } // Write a placeholder packet header. This will be replaced @@ -3108,7 +3058,8 @@ void writeMessageHeader() throws SQLServerException { boolean includeTraceHeader = false; int totalHeaderLength = TDS.MESSAGE_HEADER_LENGTH; if (TDS.PKT_QUERY == tdsMessageType || TDS.PKT_RPC == tdsMessageType) { - if (con.isDenaliOrLater() && !ActivityCorrelator.getCurrent().IsSentToServer() && Util.IsActivityTraceOn()) { + if (con.isDenaliOrLater() && !ActivityCorrelator.getCurrent().IsSentToServer() + && Util.IsActivityTraceOn()) { includeTraceHeader = true; totalHeaderLength += TDS.TRACE_HEADER_LENGTH; } @@ -3130,9 +3081,9 @@ void writeTraceHeaderData() throws SQLServerException { ActivityId activityId = ActivityCorrelator.getCurrent(); final byte[] actIdByteArray = Util.asGuidByteArray(activityId.getId()); long seqNum = activityId.getSequence(); - writeShort(TDS.HEADERTYPE_TRACE); // trace header type - writeBytes(actIdByteArray, 0, actIdByteArray.length); // guid part of ActivityId - writeInt((int) seqNum); // sequence number of ActivityId + writeShort(TDS.HEADERTYPE_TRACE); // trace header type + writeBytes(actIdByteArray, 0, actIdByteArray.length); // guid part of ActivityId + writeInt((int) seqNum); // sequence number of ActivityId if (logger.isLoggable(Level.FINER)) logger.finer("Send Trace Header - ActivityID: " + activityId.toString()); @@ -3142,12 +3093,11 @@ void writeTraceHeaderData() throws SQLServerException { * Convenience method to prepare the TDS channel for writing and start a new TDS message. * * @param command - * The TDS command + * The TDS command * @param tdsMessageType - * The TDS message type (PKT_QUERY, PKT_RPC, etc.) + * The TDS message type (PKT_QUERY, PKT_RPC, etc.) */ - void startMessage(TDSCommand command, - byte tdsMessageType) throws SQLServerException { + void startMessage(TDSCommand command, byte tdsMessageType) throws SQLServerException { this.command = command; this.tdsMessageType = tdsMessageType; this.packetNum = 0; @@ -3166,7 +3116,7 @@ void startMessage(TDSCommand command, } ((Buffer) socketBuffer).position(((Buffer) socketBuffer).limit()); - ((Buffer)stagingBuffer).clear(); + ((Buffer) stagingBuffer).clear(); preparePacket(); writeMessageHeader(); @@ -3208,10 +3158,9 @@ void writeByte(byte value) throws SQLServerException { if (dataIsLoggable) logBuffer.put(value); else - ((Buffer)logBuffer).position(((Buffer)logBuffer).position() + 1); + ((Buffer) logBuffer).position(((Buffer) logBuffer).position() + 1); } - } - else { + } else { valueBytes[0] = value; writeWrappedBytes(valueBytes, 1); } @@ -3235,10 +3184,9 @@ void writeChar(char value) throws SQLServerException { if (dataIsLoggable) logBuffer.putChar(value); else - ((Buffer)logBuffer).position( ((Buffer)logBuffer).position() + 2); + ((Buffer) logBuffer).position(((Buffer) logBuffer).position() + 2); } - } - else { + } else { Util.writeShort((short) value, valueBytes, 0); writeWrappedBytes(valueBytes, 2); } @@ -3251,10 +3199,9 @@ void writeShort(short value) throws SQLServerException { if (dataIsLoggable) logBuffer.putShort(value); else - ((Buffer)logBuffer).position( ((Buffer)logBuffer).position() + 2); + ((Buffer) logBuffer).position(((Buffer) logBuffer).position() + 2); } - } - else { + } else { Util.writeShort(value, valueBytes, 0); writeWrappedBytes(valueBytes, 2); } @@ -3267,10 +3214,9 @@ void writeInt(int value) throws SQLServerException { if (dataIsLoggable) logBuffer.putInt(value); else - ((Buffer)logBuffer).position( ((Buffer)logBuffer).position() + 4); + ((Buffer) logBuffer).position(((Buffer) logBuffer).position() + 4); } - } - else { + } else { Util.writeInt(value, valueBytes, 0); writeWrappedBytes(valueBytes, 4); } @@ -3280,7 +3226,7 @@ void writeInt(int value) throws SQLServerException { * Append a real value in the TDS stream. * * @param value - * the data value + * the data value */ void writeReal(Float value) throws SQLServerException { writeInt(Float.floatToRawIntBits(value)); @@ -3290,7 +3236,7 @@ void writeReal(Float value) throws SQLServerException { * Append a double value in the TDS stream. * * @param value - * the data value + * the data value */ void writeDouble(double value) throws SQLServerException { if (stagingBuffer.remaining() >= 8) { @@ -3299,10 +3245,9 @@ void writeDouble(double value) throws SQLServerException { if (dataIsLoggable) logBuffer.putDouble(value); else - ((Buffer)logBuffer).position( ((Buffer)logBuffer).position() + 8); + ((Buffer) logBuffer).position(((Buffer) logBuffer).position() + 8); } - } - else { + } else { long bits = Double.doubleToLongBits(value); long mask = 0xFF; int nShift = 0; @@ -3318,27 +3263,27 @@ void writeDouble(double value) throws SQLServerException { * Append a big decimal in the TDS stream. * * @param bigDecimalVal - * the big decimal data value + * the big decimal data value * @param srcJdbcType - * the source JDBCType + * the source JDBCType * @param precision - * the precision of the data value + * the precision of the data value * @param scale - * the scale of the column + * the scale of the column * @throws SQLServerException */ - void writeBigDecimal(BigDecimal bigDecimalVal, - int srcJdbcType, - int precision, + void writeBigDecimal(BigDecimal bigDecimalVal, int srcJdbcType, int precision, int scale) throws SQLServerException { /* - * Length including sign byte One 1-byte unsigned integer that represents the sign of the decimal value (0 => Negative, 1 => positive) One 4-, - * 8-, 12-, or 16-byte signed integer that represents the decimal value multiplied by 10^scale. + * Length including sign byte One 1-byte unsigned integer that represents the sign of the decimal value (0 => + * Negative, 1 => positive) One 4-, 8-, 12-, or 16-byte signed integer that represents the decimal value + * multiplied by 10^scale. */ /* - * setScale of all BigDecimal value based on metadata as scale is not sent seperately for individual value. Use the rounding used in Server. - * Say, for BigDecimal("0.1"), if scale in metdadata is 0, then ArithmeticException would be thrown if RoundingMode is not set + * setScale of all BigDecimal value based on metadata as scale is not sent seperately for individual value. Use + * the rounding used in Server. Say, for BigDecimal("0.1"), if scale in metdadata is 0, then ArithmeticException + * would be thrown if RoundingMode is not set */ bigDecimalVal = bigDecimalVal.setScale(scale, RoundingMode.HALF_UP); @@ -3354,27 +3299,26 @@ void writeBigDecimal(BigDecimal bigDecimalVal, System.arraycopy(valueBytes, 2, bytes, 0, valueBytes.length - 2); writeBytes(bytes); } - + /** * Append a big decimal inside sql_variant in the TDS stream. * * @param bigDecimalVal - * the big decimal data value + * the big decimal data value * @param srcJdbcType - * the source JDBCType + * the source JDBCType */ - void writeSqlVariantInternalBigDecimal(BigDecimal bigDecimalVal, - int srcJdbcType) throws SQLServerException { + void writeSqlVariantInternalBigDecimal(BigDecimal bigDecimalVal, int srcJdbcType) throws SQLServerException { /* - * Length including sign byte One 1-byte unsigned integer that represents the sign of the decimal value (0 => Negative, 1 => positive) One - * 16-byte signed integer that represents the decimal value multiplied by 10^scale. In sql_variant, we send the bigdecimal with precision 38, - * therefore we use 16 bytes for the maximum size of this integer. + * Length including sign byte One 1-byte unsigned integer that represents the sign of the decimal value (0 => + * Negative, 1 => positive) One 16-byte signed integer that represents the decimal value multiplied by 10^scale. + * In sql_variant, we send the bigdecimal with precision 38, therefore we use 16 bytes for the maximum size of + * this integer. */ boolean isNegative = (bigDecimalVal.signum() < 0); BigInteger bi = bigDecimalVal.unscaledValue(); - if (isNegative) - { + if (isNegative) { bi = bi.negate(); } int bLength; @@ -3390,7 +3334,8 @@ void writeSqlVariantInternalBigDecimal(BigDecimal bigDecimalVal, // If precession of input is greater than maximum allowed (p><= 38) throw Exception MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_valueOutOfRange")); Object[] msgArgs = {JDBCType.of(srcJdbcType)}; - throw new SQLServerException(form.format(msgArgs), SQLState.DATA_EXCEPTION_LENGTH_MISMATCH, DriverError.NOT_SET, null); + throw new SQLServerException(form.format(msgArgs), SQLState.DATA_EXCEPTION_LENGTH_MISMATCH, + DriverError.NOT_SET, null); } // Byte array to hold all the reversed and padding bytes. @@ -3406,8 +3351,7 @@ void writeSqlVariantInternalBigDecimal(BigDecimal bigDecimalVal, bytes[i++] = unscaledBytes[j--]; // Fill the rest of the array with zeros. - for (; i < remaining; i++) - { + for (; i < remaining; i++) { bytes[i] = (byte) 0x00; } writeBytes(bytes); @@ -3415,7 +3359,7 @@ void writeSqlVariantInternalBigDecimal(BigDecimal bigDecimalVal, void writeSmalldatetime(String value) throws SQLServerException { GregorianCalendar calendar = initializeCalender(TimeZone.getDefault()); - long utcMillis; // Value to which the calendar is to be set (in milliseconds 1/1/1970 00:00:00 GMT) + long utcMillis; // Value to which the calendar is to be set (in milliseconds 1/1/1970 00:00:00 GMT) java.sql.Timestamp timestampValue = java.sql.Timestamp.valueOf(value); utcMillis = timestampValue.getTime(); @@ -3423,7 +3367,8 @@ void writeSmalldatetime(String value) throws SQLServerException { calendar.setTimeInMillis(utcMillis); // Number of days since the SQL Server Base Date (January 1, 1900) - int daysSinceSQLBaseDate = DDC.daysSinceBaseDate(calendar.get(Calendar.YEAR), calendar.get(Calendar.DAY_OF_YEAR), TDS.BASE_YEAR_1900); + int daysSinceSQLBaseDate = DDC.daysSinceBaseDate(calendar.get(Calendar.YEAR), + calendar.get(Calendar.DAY_OF_YEAR), TDS.BASE_YEAR_1900); // Next, figure out the number of milliseconds since midnight of the current day. int millisSinceMidnight = 1000 * calendar.get(Calendar.SECOND) + // Seconds into the current minute @@ -3452,7 +3397,7 @@ void writeSmalldatetime(String value) throws SQLServerException { void writeDatetime(String value) throws SQLServerException { GregorianCalendar calendar = initializeCalender(TimeZone.getDefault()); - long utcMillis; // Value to which the calendar is to be set (in milliseconds 1/1/1970 00:00:00 GMT) + long utcMillis; // Value to which the calendar is to be set (in milliseconds 1/1/1970 00:00:00 GMT) int subSecondNanos; java.sql.Timestamp timestampValue = java.sql.Timestamp.valueOf(value); utcMillis = timestampValue.getTime(); @@ -3463,10 +3408,13 @@ void writeDatetime(String value) throws SQLServerException { // Number of days there have been since the SQL Base Date. // These are based on SQL Server algorithms - int daysSinceSQLBaseDate = DDC.daysSinceBaseDate(calendar.get(Calendar.YEAR), calendar.get(Calendar.DAY_OF_YEAR), TDS.BASE_YEAR_1900); + int daysSinceSQLBaseDate = DDC.daysSinceBaseDate(calendar.get(Calendar.YEAR), + calendar.get(Calendar.DAY_OF_YEAR), TDS.BASE_YEAR_1900); // Number of milliseconds since midnight of the current day. - int millisSinceMidnight = (subSecondNanos + Nanos.PER_MILLISECOND / 2) / Nanos.PER_MILLISECOND + // Millis into the current second + int millisSinceMidnight = (subSecondNanos + Nanos.PER_MILLISECOND / 2) / Nanos.PER_MILLISECOND + // Millis into + // the current + // second 1000 * calendar.get(Calendar.SECOND) + // Seconds into the current minute 60 * 1000 * calendar.get(Calendar.MINUTE) + // Minutes into the current hour 60 * 60 * 1000 * calendar.get(Calendar.HOUR_OF_DAY); // Hours into the current day @@ -3488,7 +3436,8 @@ void writeDatetime(String value) throws SQLServerException { || daysSinceSQLBaseDate >= DDC.daysSinceBaseDate(10000, 1, TDS.BASE_YEAR_1900)) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_valueOutOfRange")); Object[] msgArgs = {SSType.DATETIME}; - throw new SQLServerException(form.format(msgArgs), SQLState.DATA_EXCEPTION_DATETIME_FIELD_OVERFLOW, DriverError.NOT_SET, null); + throw new SQLServerException(form.format(msgArgs), SQLState.DATA_EXCEPTION_DATETIME_FIELD_OVERFLOW, + DriverError.NOT_SET, null); } // Number of days since the SQL Server Base Date (January 1, 1900) @@ -3512,10 +3461,9 @@ void writeDate(String value) throws SQLServerException { SSType.DATE); } - void writeTime(java.sql.Timestamp value, - int scale) throws SQLServerException { + void writeTime(java.sql.Timestamp value, int scale) throws SQLServerException { GregorianCalendar calendar = initializeCalender(TimeZone.getDefault()); - long utcMillis; // Value to which the calendar is to be set (in milliseconds 1/1/1970 00:00:00 GMT) + long utcMillis; // Value to which the calendar is to be set (in milliseconds 1/1/1970 00:00:00 GMT) int subSecondNanos; utcMillis = value.getTime(); subSecondNanos = value.getNanos(); @@ -3526,12 +3474,10 @@ void writeTime(java.sql.Timestamp value, writeScaledTemporal(calendar, subSecondNanos, scale, SSType.TIME); } - void writeDateTimeOffset(Object value, - int scale, - SSType destSSType) throws SQLServerException { + void writeDateTimeOffset(Object value, int scale, SSType destSSType) throws SQLServerException { GregorianCalendar calendar; TimeZone timeZone; // Time zone to associate with the value in the Gregorian calendar - long utcMillis; // Value to which the calendar is to be set (in milliseconds 1/1/1970 00:00:00 GMT) + long utcMillis; // Value to which the calendar is to be set (in milliseconds 1/1/1970 00:00:00 GMT) int subSecondNanos; int minutesOffset; @@ -3545,7 +3491,8 @@ void writeDateTimeOffset(Object value, // Otherwise, when converting from DATETIMEOFFSET to other temporal data types, // use a local time zone determined by the minutes offset of the value, since // the writers for those types expect local calendars. - timeZone = (SSType.DATETIMEOFFSET == destSSType) ? UTC.timeZone : new SimpleTimeZone(minutesOffset * 60 * 1000, ""); + timeZone = (SSType.DATETIMEOFFSET == destSSType) ? UTC.timeZone + : new SimpleTimeZone(minutesOffset * 60 * 1000, ""); calendar = new GregorianCalendar(timeZone, Locale.US); calendar.setLenient(true); @@ -3557,8 +3504,7 @@ void writeDateTimeOffset(Object value, writeShort((short) minutesOffset); } - void writeOffsetDateTimeWithTimezone(OffsetDateTime offsetDateTimeValue, - int scale) throws SQLServerException { + void writeOffsetDateTimeWithTimezone(OffsetDateTime offsetDateTimeValue, int scale) throws SQLServerException { GregorianCalendar calendar; TimeZone timeZone; long utcMillis; @@ -3570,9 +3516,10 @@ void writeOffsetDateTimeWithTimezone(OffsetDateTime offsetDateTimeValue, // components. So the result of the division will be an integer always. SQL Server also supports // offsets in minutes precision. minutesOffset = offsetDateTimeValue.getOffset().getTotalSeconds() / 60; - } - catch (Exception e) { - throw new SQLServerException(SQLServerException.getErrString("R_zoneOffsetError"), null, // SQLState is null as this error is generated in + } catch (Exception e) { + throw new SQLServerException(SQLServerException.getErrString("R_zoneOffsetError"), null, // SQLState is null + // as this error is + // generated in // the driver 0, // Use 0 instead of DriverError.NOT_SET to use the correct constructor e); @@ -3592,9 +3539,11 @@ void writeOffsetDateTimeWithTimezone(OffsetDateTime offsetDateTimeValue, timeZone = UTC.timeZone; // The behavior is similar to microsoft.sql.DateTimeOffset - // In Timestamp format, only YEAR needs to have 4 digits. The leading zeros for the rest of the fields can be omitted. - String offDateTimeStr = String.format("%04d", offsetDateTimeValue.getYear()) + '-' + offsetDateTimeValue.getMonthValue() + '-' - + offsetDateTimeValue.getDayOfMonth() + ' ' + offsetDateTimeValue.getHour() + ':' + offsetDateTimeValue.getMinute() + ':' + // In Timestamp format, only YEAR needs to have 4 digits. The leading zeros for the rest of the fields can be + // omitted. + String offDateTimeStr = String.format("%04d", offsetDateTimeValue.getYear()) + '-' + + offsetDateTimeValue.getMonthValue() + '-' + offsetDateTimeValue.getDayOfMonth() + ' ' + + offsetDateTimeValue.getHour() + ':' + offsetDateTimeValue.getMinute() + ':' + offsetDateTimeValue.getSecond(); utcMillis = Timestamp.valueOf(offDateTimeStr).getTime(); calendar = initializeCalender(timeZone); @@ -3613,8 +3562,7 @@ void writeOffsetDateTimeWithTimezone(OffsetDateTime offsetDateTimeValue, writeShort((short) minutesOffset); } - void writeOffsetTimeWithTimezone(OffsetTime offsetTimeValue, - int scale) throws SQLServerException { + void writeOffsetTimeWithTimezone(OffsetTime offsetTimeValue, int scale) throws SQLServerException { GregorianCalendar calendar; TimeZone timeZone; long utcMillis; @@ -3626,9 +3574,10 @@ void writeOffsetTimeWithTimezone(OffsetTime offsetTimeValue, // components. So the result of the division will be an integer always. SQL Server also supports // offsets in minutes precision. minutesOffset = offsetTimeValue.getOffset().getTotalSeconds() / 60; - } - catch (Exception e) { - throw new SQLServerException(SQLServerException.getErrString("R_zoneOffsetError"), null, // SQLState is null as this error is generated in + } catch (Exception e) { + throw new SQLServerException(SQLServerException.getErrString("R_zoneOffsetError"), null, // SQLState is null + // as this error is + // generated in // the driver 0, // Use 0 instead of DriverError.NOT_SET to use the correct constructor e); @@ -3651,8 +3600,8 @@ void writeOffsetTimeWithTimezone(OffsetTime offsetTimeValue, // If date only contains a time part, the return value is 1900, the base year. // https://msdn.microsoft.com/en-us/library/ms186313.aspx // In Timestamp format, leading zeros for the fields can be omitted. - String offsetTimeStr = TDS.BASE_YEAR_1900 + "-01-01" + ' ' + offsetTimeValue.getHour() + ':' + offsetTimeValue.getMinute() + ':' - + offsetTimeValue.getSecond(); + String offsetTimeStr = TDS.BASE_YEAR_1900 + "-01-01" + ' ' + offsetTimeValue.getHour() + ':' + + offsetTimeValue.getMinute() + ':' + offsetTimeValue.getSecond(); utcMillis = Timestamp.valueOf(offsetTimeStr).getTime(); calendar = initializeCalender(timeZone); @@ -3677,10 +3626,9 @@ void writeLong(long value) throws SQLServerException { if (dataIsLoggable) logBuffer.putLong(value); else - ((Buffer)logBuffer).position( ((Buffer)logBuffer).position() + 8); + ((Buffer) logBuffer).position(((Buffer) logBuffer).position() + 8); } - } - else { + } else { valueBytes[0] = (byte) ((value >> 0) & 0xFF); valueBytes[1] = (byte) ((value >> 8) & 0xFF); valueBytes[2] = (byte) ((value >> 16) & 0xFF); @@ -3697,9 +3645,7 @@ void writeBytes(byte[] value) throws SQLServerException { writeBytes(value, 0, value.length); } - void writeBytes(byte[] value, - int offset, - int length) throws SQLServerException { + void writeBytes(byte[] value, int offset, int length) throws SQLServerException { assert length <= value.length; int bytesWritten = 0; @@ -3720,20 +3666,19 @@ void writeBytes(byte[] value, if (dataIsLoggable) logBuffer.put(value, offset + bytesWritten, bytesToWrite); else - ((Buffer)logBuffer).position( ((Buffer)logBuffer).position() + bytesToWrite); + ((Buffer) logBuffer).position(((Buffer) logBuffer).position() + bytesToWrite); } bytesWritten += bytesToWrite; } } - void writeWrappedBytes(byte value[], - int valueLength) throws SQLServerException { + void writeWrappedBytes(byte value[], int valueLength) throws SQLServerException { // This function should only be used to write a value that is longer than // what remains in the current staging buffer. However, the value must // be short enough to fit in an empty buffer. assert valueLength <= value.length; - + int remaining = stagingBuffer.remaining(); assert remaining < valueLength; @@ -3747,7 +3692,7 @@ void writeWrappedBytes(byte value[], if (dataIsLoggable) logBuffer.put(value, 0, remaining); else - ((Buffer)logBuffer).position( ((Buffer)logBuffer).position() + remaining); + ((Buffer) logBuffer).position(((Buffer) logBuffer).position() + remaining); } } @@ -3760,7 +3705,7 @@ void writeWrappedBytes(byte value[], if (dataIsLoggable) logBuffer.put(value, remaining, valueLength - remaining); else - ((Buffer)logBuffer).position( ((Buffer)logBuffer).position() + remaining); + ((Buffer) logBuffer).position(((Buffer) logBuffer).position() + remaining); } } @@ -3784,8 +3729,7 @@ void writeString(String value) throws SQLServerException { } } - void writeStream(InputStream inputStream, - long advertisedLength, + void writeStream(InputStream inputStream, long advertisedLength, boolean writeChunkSizes) throws SQLServerException { assert DataTypes.UNKNOWN_STREAM_LENGTH == advertisedLength || advertisedLength >= 0; @@ -3795,11 +3739,12 @@ void writeStream(InputStream inputStream, int bytesToWrite; do { // Read in next chunk - for (bytesToWrite = 0; -1 != bytesRead && bytesToWrite < streamByteBuffer.length; bytesToWrite += bytesRead) { + for (bytesToWrite = 0; -1 != bytesRead && bytesToWrite < streamByteBuffer.length; + bytesToWrite += bytesRead) { try { - bytesRead = inputStream.read(streamByteBuffer, bytesToWrite, streamByteBuffer.length - bytesToWrite); - } - catch (IOException e) { + bytesRead = inputStream.read(streamByteBuffer, bytesToWrite, + streamByteBuffer.length - bytesToWrite); + } catch (IOException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_errorReadingStream")); Object[] msgArgs = {e.toString()}; error(form.format(msgArgs), SQLState.DATA_EXCEPTION_NOT_SPECIFIC, DriverError.NOT_SET); @@ -3822,8 +3767,7 @@ void writeStream(InputStream inputStream, writeBytes(streamByteBuffer, 0, bytesToWrite); actualLength += bytesToWrite; - } - while (-1 != bytesRead || bytesToWrite > 0); + } while (-1 != bytesRead || bytesToWrite > 0); // If we were given an input stream length that we had to match and // the actual stream length did not match then cancel the request. @@ -3835,20 +3779,19 @@ void writeStream(InputStream inputStream, } /* - * Adding another function for writing non-unicode reader instead of re-factoring the writeReader() for performance efficiency. As this method - * will only be used in bulk copy, it needs to be efficient. Note: Any changes in algorithm/logic should propagate to both writeReader() and - * writeNonUnicodeReader(). + * Adding another function for writing non-unicode reader instead of re-factoring the writeReader() for performance + * efficiency. As this method will only be used in bulk copy, it needs to be efficient. Note: Any changes in + * algorithm/logic should propagate to both writeReader() and writeNonUnicodeReader(). */ - void writeNonUnicodeReader(Reader reader, - long advertisedLength, - boolean isDestBinary, + void writeNonUnicodeReader(Reader reader, long advertisedLength, boolean isDestBinary, Charset charSet) throws SQLServerException { assert DataTypes.UNKNOWN_STREAM_LENGTH == advertisedLength || advertisedLength >= 0; long actualLength = 0; char[] streamCharBuffer = new char[currentPacketSize]; - // The unicode version, writeReader() allocates a byte buffer that is 4 times the currentPacketSize, not sure why. + // The unicode version, writeReader() allocates a byte buffer that is 4 times the currentPacketSize, not sure + // why. byte[] streamByteBuffer = new byte[currentPacketSize]; int charsRead = 0; int charsToWrite; @@ -3857,11 +3800,11 @@ void writeNonUnicodeReader(Reader reader, do { // Read in next chunk - for (charsToWrite = 0; -1 != charsRead && charsToWrite < streamCharBuffer.length; charsToWrite += charsRead) { + for (charsToWrite = 0; -1 != charsRead && charsToWrite < streamCharBuffer.length; + charsToWrite += charsRead) { try { charsRead = reader.read(streamCharBuffer, charsToWrite, streamCharBuffer.length - charsToWrite); - } - catch (IOException e) { + } catch (IOException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_errorReadingStream")); Object[] msgArgs = {e.toString()}; error(form.format(msgArgs), SQLState.DATA_EXCEPTION_NOT_SPECIFIC, DriverError.NOT_SET); @@ -3882,21 +3825,21 @@ void writeNonUnicodeReader(Reader reader, // Write it out // This also writes the PLP_TERMINATOR token after all the data in the the stream are sent. // The Do-While loop goes on one more time as charsToWrite is greater than 0 for the last chunk, and - // in this last round the only thing that is written is an int value of 0, which is the PLP Terminator token(0x00000000). + // in this last round the only thing that is written is an int value of 0, which is the PLP Terminator + // token(0x00000000). writeInt(charsToWrite); for (int charsCopied = 0; charsCopied < charsToWrite; ++charsCopied) { if (null == charSet) { streamByteBuffer[charsCopied] = (byte) (streamCharBuffer[charsCopied] & 0xFF); - } - else { + } else { // encoding as per collation - streamByteBuffer[charsCopied] = new String(streamCharBuffer[charsCopied] + "").getBytes(charSet)[0]; + streamByteBuffer[charsCopied] = new String(streamCharBuffer[charsCopied] + "") + .getBytes(charSet)[0]; } } writeBytes(streamByteBuffer, 0, charsToWrite); - } - else { + } else { bytesToWrite = charsToWrite; if (0 != charsToWrite) bytesToWrite = charsToWrite / 2; @@ -3907,8 +3850,7 @@ void writeNonUnicodeReader(Reader reader, writeBytes(bytes, 0, bytesToWrite); } actualLength += charsToWrite; - } - while (-1 != charsRead || charsToWrite > 0); + } while (-1 != charsRead || charsToWrite > 0); // If we were given an input stream length that we had to match and // the actual stream length did not match then cancel the request. @@ -3917,15 +3859,14 @@ void writeNonUnicodeReader(Reader reader, Object[] msgArgs = {advertisedLength, actualLength}; error(form.format(msgArgs), SQLState.DATA_EXCEPTION_LENGTH_MISMATCH, DriverError.NOT_SET); } - } + } /* - * Note: There is another method with same code logic for non unicode reader, writeNonUnicodeReader(), implemented for performance efficiency. Any - * changes in algorithm/logic should propagate to both writeReader() and writeNonUnicodeReader(). + * Note: There is another method with same code logic for non unicode reader, writeNonUnicodeReader(), implemented + * for performance efficiency. Any changes in algorithm/logic should propagate to both writeReader() and + * writeNonUnicodeReader(). */ - void writeReader(Reader reader, - long advertisedLength, - boolean writeChunkSizes) throws SQLServerException { + void writeReader(Reader reader, long advertisedLength, boolean writeChunkSizes) throws SQLServerException { assert DataTypes.UNKNOWN_STREAM_LENGTH == advertisedLength || advertisedLength >= 0; long actualLength = 0; @@ -3935,11 +3876,11 @@ void writeReader(Reader reader, int charsToWrite; do { // Read in next chunk - for (charsToWrite = 0; -1 != charsRead && charsToWrite < streamCharBuffer.length; charsToWrite += charsRead) { + for (charsToWrite = 0; -1 != charsRead && charsToWrite < streamCharBuffer.length; + charsToWrite += charsRead) { try { charsRead = reader.read(streamCharBuffer, charsToWrite, streamCharBuffer.length - charsToWrite); - } - catch (IOException e) { + } catch (IOException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_errorReadingStream")); Object[] msgArgs = {e.toString()}; error(form.format(msgArgs), SQLState.DATA_EXCEPTION_NOT_SPECIFIC, DriverError.NOT_SET); @@ -3972,8 +3913,7 @@ void writeReader(Reader reader, writeBytes(streamByteBuffer, 0, 2 * charsToWrite); actualLength += charsToWrite; - } - while (-1 != charsRead || charsToWrite > 0); + } while (-1 != charsRead || charsToWrite > 0); // If we were given an input stream length that we had to match and // the actual stream length did not match then cancel the request. @@ -4002,22 +3942,21 @@ GregorianCalendar initializeCalender(TimeZone timeZone) { return calendar; } - final void error(String reason, - SQLState sqlState, - DriverError driverError) throws SQLServerException { + final void error(String reason, SQLState sqlState, DriverError driverError) throws SQLServerException { assert null != command; command.interrupt(reason); throw new SQLServerException(reason, sqlState, driverError, null); } /** - * Sends an attention signal to the server, if necessary, to tell it to stop processing the current command on this connection. + * Sends an attention signal to the server, if necessary, to tell it to stop processing the current command on this + * connection. * - * If no packets of the command's request have yet been sent to the server, then no attention signal needs to be sent. The interrupt will be - * handled entirely by the driver. + * If no packets of the command's request have yet been sent to the server, then no attention signal needs to be + * sent. The interrupt will be handled entirely by the driver. * - * This method does not need synchronization as it does not manipulate interrupt state and writing is guaranteed to occur only from one thread at - * a time. + * This method does not need synchronization as it does not manipulate interrupt state and writing is guaranteed to + * occur only from one thread at a time. */ final boolean sendAttention() throws SQLServerException { // If any request packets were already written to the server then send an @@ -4071,7 +4010,8 @@ private void writePacket(int tdsMessageStatus) throws SQLServerException { // If we just sent the first login request packet and SSL encryption was enabled // for login only, then disable SSL now. - if (TDS.PKT_LOGON70 == tdsMessageType && 1 == packetNum && TDS.ENCRYPT_OFF == con.getNegotiatedEncryptionLevel()) { + if (TDS.PKT_LOGON70 == tdsMessageType && 1 == packetNum + && TDS.ENCRYPT_OFF == con.getNegotiatedEncryptionLevel()) { tdsChannel.disableSSL(); } @@ -4082,16 +4022,21 @@ private void writePacket(int tdsMessageStatus) throws SQLServerException { } private void writePacketHeader(int tdsMessageStatus) { - int tdsMessageLength = ((Buffer)stagingBuffer).position(); + int tdsMessageLength = ((Buffer) stagingBuffer).position(); ++packetNum; // Write the TDS packet header back at the start of the staging buffer stagingBuffer.put(TDS.PACKET_HEADER_MESSAGE_TYPE, tdsMessageType); stagingBuffer.put(TDS.PACKET_HEADER_MESSAGE_STATUS, (byte) tdsMessageStatus); - stagingBuffer.put(TDS.PACKET_HEADER_MESSAGE_LENGTH, (byte) ((tdsMessageLength >> 8) & 0xFF)); // Note: message length is 16 bits, - stagingBuffer.put(TDS.PACKET_HEADER_MESSAGE_LENGTH + 1, (byte) ((tdsMessageLength >> 0) & 0xFF)); // written BIG ENDIAN - stagingBuffer.put(TDS.PACKET_HEADER_SPID, (byte) ((tdsChannel.getSPID() >> 8) & 0xFF)); // Note: SPID is 16 bits, - stagingBuffer.put(TDS.PACKET_HEADER_SPID + 1, (byte) ((tdsChannel.getSPID() >> 0) & 0xFF)); // written BIG ENDIAN + stagingBuffer.put(TDS.PACKET_HEADER_MESSAGE_LENGTH, (byte) ((tdsMessageLength >> 8) & 0xFF)); // Note: message + // length is 16 + // bits, + stagingBuffer.put(TDS.PACKET_HEADER_MESSAGE_LENGTH + 1, (byte) ((tdsMessageLength >> 0) & 0xFF)); // written BIG + // ENDIAN + stagingBuffer.put(TDS.PACKET_HEADER_SPID, (byte) ((tdsChannel.getSPID() >> 8) & 0xFF)); // Note: SPID is 16 + // bits, + stagingBuffer.put(TDS.PACKET_HEADER_SPID + 1, (byte) ((tdsChannel.getSPID() >> 0) & 0xFF)); // written BIG + // ENDIAN stagingBuffer.put(TDS.PACKET_HEADER_SEQUENCE_NUM, (byte) (packetNum % 256)); stagingBuffer.put(TDS.PACKET_HEADER_WINDOW, (byte) 0); // Window (Reserved/Not used) @@ -4099,10 +4044,15 @@ private void writePacketHeader(int tdsMessageStatus) { if (tdsChannel.isLoggingPackets()) { logBuffer.put(TDS.PACKET_HEADER_MESSAGE_TYPE, tdsMessageType); logBuffer.put(TDS.PACKET_HEADER_MESSAGE_STATUS, (byte) tdsMessageStatus); - logBuffer.put(TDS.PACKET_HEADER_MESSAGE_LENGTH, (byte) ((tdsMessageLength >> 8) & 0xFF)); // Note: message length is 16 bits, - logBuffer.put(TDS.PACKET_HEADER_MESSAGE_LENGTH + 1, (byte) ((tdsMessageLength >> 0) & 0xFF)); // written BIG ENDIAN - logBuffer.put(TDS.PACKET_HEADER_SPID, (byte) ((tdsChannel.getSPID() >> 8) & 0xFF)); // Note: SPID is 16 bits, - logBuffer.put(TDS.PACKET_HEADER_SPID + 1, (byte) ((tdsChannel.getSPID() >> 0) & 0xFF)); // written BIG ENDIAN + logBuffer.put(TDS.PACKET_HEADER_MESSAGE_LENGTH, (byte) ((tdsMessageLength >> 8) & 0xFF)); // Note: message + // length is 16 + // bits, + logBuffer.put(TDS.PACKET_HEADER_MESSAGE_LENGTH + 1, (byte) ((tdsMessageLength >> 0) & 0xFF)); // written BIG + // ENDIAN + logBuffer.put(TDS.PACKET_HEADER_SPID, (byte) ((tdsChannel.getSPID() >> 8) & 0xFF)); // Note: SPID is 16 + // bits, + logBuffer.put(TDS.PACKET_HEADER_SPID + 1, (byte) ((tdsChannel.getSPID() >> 0) & 0xFF)); // written BIG + // ENDIAN logBuffer.put(TDS.PACKET_HEADER_SEQUENCE_NUM, (byte) (packetNum % 256)); logBuffer.put(TDS.PACKET_HEADER_WINDOW, (byte) 0); // Window (Reserved/Not used); } @@ -4110,13 +4060,13 @@ private void writePacketHeader(int tdsMessageStatus) { void flush(boolean atEOM) throws SQLServerException { // First, flush any data left in the socket buffer. - tdsChannel.write(socketBuffer.array(), ((Buffer)socketBuffer).position(), socketBuffer.remaining()); - ((Buffer)socketBuffer).position(((Buffer)socketBuffer).limit()); + tdsChannel.write(socketBuffer.array(), ((Buffer) socketBuffer).position(), socketBuffer.remaining()); + ((Buffer) socketBuffer).position(((Buffer) socketBuffer).limit()); // If there is data in the staging buffer that needs to be written // to the socket, the socket buffer is now empty, so swap buffers // and start writing data from the staging buffer. - if (((Buffer)stagingBuffer).position() >= TDS_PACKET_HEADER_SIZE) { + if (((Buffer) stagingBuffer).position() >= TDS_PACKET_HEADER_SIZE) { // Swap the packet buffers ... ByteBuffer swapBuffer = stagingBuffer; stagingBuffer = socketBuffer; @@ -4128,8 +4078,8 @@ void flush(boolean atEOM) throws SQLServerException { // We need to use flip() rather than rewind() here so that // the socket buffer's limit is properly set for the last // packet, which may be shorter than the other packets. - ((Buffer)socketBuffer).flip(); - ((Buffer)stagingBuffer).clear(); + ((Buffer) socketBuffer).flip(); + ((Buffer) stagingBuffer).clear(); // If we are logging TDS packets then log the packet we're about // to send over the wire now. @@ -4143,8 +4093,8 @@ void flush(boolean atEOM) throws SQLServerException { preparePacket(); // Finally, start sending data from the new socket buffer. - tdsChannel.write(socketBuffer.array(), ((Buffer)socketBuffer).position(), socketBuffer.remaining()); - ((Buffer)socketBuffer).position( ((Buffer)socketBuffer).limit()); + tdsChannel.write(socketBuffer.array(), ((Buffer) socketBuffer).position(), socketBuffer.remaining()); + ((Buffer) socketBuffer).position(((Buffer) socketBuffer).limit()); } } @@ -4154,21 +4104,19 @@ void flush(boolean atEOM) throws SQLServerException { * Write out elements common to all RPC values. * * @param sName - * the optional parameter name + * the optional parameter name * @param bOut - * boolean true if the value that follows is being registered as an ouput parameter + * boolean true if the value that follows is being registered as an ouput parameter * @param tdsType - * TDS type of the value that follows + * TDS type of the value that follows */ - void writeRPCNameValType(String sName, - boolean bOut, - TDSType tdsType) throws SQLServerException { + void writeRPCNameValType(String sName, boolean bOut, TDSType tdsType) throws SQLServerException { int nNameLen = 0; if (null != sName) nNameLen = sName.length() + 1; // The @ prefix is required for the param - writeByte((byte) nNameLen); // param name len + writeByte((byte) nNameLen); // param name len if (nNameLen > 0) { writeChar('@'); writeString(sName); @@ -4178,28 +4126,25 @@ void writeRPCNameValType(String sName, writeByte((byte) (bOut ? 1 | TDS.AE_METADATA : 0 | TDS.AE_METADATA)); // status else writeByte((byte) (bOut ? 1 : 0)); // status - writeByte(tdsType.byteValue()); // type + writeByte(tdsType.byteValue()); // type } /** * Append a boolean value in RPC transmission format. * * @param sName - * the optional parameter name + * the optional parameter name * @param booleanValue - * the data value + * the data value * @param bOut - * boolean true if the data value is being registered as an ouput parameter + * boolean true if the data value is being registered as an ouput parameter */ - void writeRPCBit(String sName, - Boolean booleanValue, - boolean bOut) throws SQLServerException { + void writeRPCBit(String sName, Boolean booleanValue, boolean bOut) throws SQLServerException { writeRPCNameValType(sName, bOut, TDSType.BITN); writeByte((byte) 1); // max length of datatype if (null == booleanValue) { writeByte((byte) 0); // len of data bytes - } - else { + } else { writeByte((byte) 1); // length of datatype writeByte((byte) (booleanValue ? 1 : 0)); } @@ -4209,21 +4154,18 @@ void writeRPCBit(String sName, * Append a short value in RPC transmission format. * * @param sName - * the optional parameter name + * the optional parameter name * @param shortValue - * the data value + * the data value * @param bOut - * boolean true if the data value is being registered as an ouput parameter + * boolean true if the data value is being registered as an ouput parameter */ - void writeRPCByte(String sName, - Byte byteValue, - boolean bOut) throws SQLServerException { + void writeRPCByte(String sName, Byte byteValue, boolean bOut) throws SQLServerException { writeRPCNameValType(sName, bOut, TDSType.INTN); writeByte((byte) 1); // max length of datatype if (null == byteValue) { writeByte((byte) 0); // len of data bytes - } - else { + } else { writeByte((byte) 1); // length of datatype writeByte(byteValue); } @@ -4233,21 +4175,18 @@ void writeRPCByte(String sName, * Append a short value in RPC transmission format. * * @param sName - * the optional parameter name + * the optional parameter name * @param shortValue - * the data value + * the data value * @param bOut - * boolean true if the data value is being registered as an ouput parameter + * boolean true if the data value is being registered as an ouput parameter */ - void writeRPCShort(String sName, - Short shortValue, - boolean bOut) throws SQLServerException { + void writeRPCShort(String sName, Short shortValue, boolean bOut) throws SQLServerException { writeRPCNameValType(sName, bOut, TDSType.INTN); writeByte((byte) 2); // max length of datatype if (null == shortValue) { writeByte((byte) 0); // len of data bytes - } - else { + } else { writeByte((byte) 2); // length of datatype writeShort(shortValue); } @@ -4257,21 +4196,18 @@ void writeRPCShort(String sName, * Append an int value in RPC transmission format. * * @param sName - * the optional parameter name + * the optional parameter name * @param intValue - * the data value + * the data value * @param bOut - * boolean true if the data value is being registered as an ouput parameter + * boolean true if the data value is being registered as an ouput parameter */ - void writeRPCInt(String sName, - Integer intValue, - boolean bOut) throws SQLServerException { + void writeRPCInt(String sName, Integer intValue, boolean bOut) throws SQLServerException { writeRPCNameValType(sName, bOut, TDSType.INTN); writeByte((byte) 4); // max length of datatype if (null == intValue) { writeByte((byte) 0); // len of data bytes - } - else { + } else { writeByte((byte) 4); // length of datatype writeInt(intValue); } @@ -4281,21 +4217,18 @@ void writeRPCInt(String sName, * Append a long value in RPC transmission format. * * @param sName - * the optional parameter name + * the optional parameter name * @param longValue - * the data value + * the data value * @param bOut - * boolean true if the data value is being registered as an ouput parameter + * boolean true if the data value is being registered as an ouput parameter */ - void writeRPCLong(String sName, - Long longValue, - boolean bOut) throws SQLServerException { + void writeRPCLong(String sName, Long longValue, boolean bOut) throws SQLServerException { writeRPCNameValType(sName, bOut, TDSType.INTN); writeByte((byte) 8); // max length of datatype if (null == longValue) { writeByte((byte) 0); // len of data bytes - } - else { + } else { writeByte((byte) 8); // length of datatype writeLong(longValue); } @@ -4305,32 +4238,27 @@ void writeRPCLong(String sName, * Append a real value in RPC transmission format. * * @param sName - * the optional parameter name + * the optional parameter name * @param floatValue - * the data value + * the data value * @param bOut - * boolean true if the data value is being registered as an ouput parameter + * boolean true if the data value is being registered as an ouput parameter */ - void writeRPCReal(String sName, - Float floatValue, - boolean bOut) throws SQLServerException { + void writeRPCReal(String sName, Float floatValue, boolean bOut) throws SQLServerException { writeRPCNameValType(sName, bOut, TDSType.FLOATN); // Data and length if (null == floatValue) { writeByte((byte) 4); // max length writeByte((byte) 0); // actual length (0 == null) - } - else { + } else { writeByte((byte) 4); // max length writeByte((byte) 4); // actual length writeInt(Float.floatToRawIntBits(floatValue)); } } - void writeRPCSqlVariant(String sName, - SqlVariant sqlVariantValue, - boolean bOut) throws SQLServerException { + void writeRPCSqlVariant(String sName, SqlVariant sqlVariantValue, boolean bOut) throws SQLServerException { writeRPCNameValType(sName, bOut, TDSType.SQL_VARIANT); // Data and length @@ -4344,15 +4272,13 @@ void writeRPCSqlVariant(String sName, * Append a double value in RPC transmission format. * * @param sName - * the optional parameter name + * the optional parameter name * @param doubleValue - * the data value + * the data value * @param bOut - * boolean true if the data value is being registered as an ouput parameter + * boolean true if the data value is being registered as an ouput parameter */ - void writeRPCDouble(String sName, - Double doubleValue, - boolean bOut) throws SQLServerException { + void writeRPCDouble(String sName, Double doubleValue, boolean bOut) throws SQLServerException { writeRPCNameValType(sName, bOut, TDSType.FLOATN); int l = 8; @@ -4361,8 +4287,7 @@ void writeRPCDouble(String sName, // Data and length if (null == doubleValue) { writeByte((byte) 0); // len of data bytes - } - else { + } else { writeByte((byte) l); // len of data bytes long bits = Double.doubleToLongBits(doubleValue); long mask = 0xFF; @@ -4379,18 +4304,15 @@ void writeRPCDouble(String sName, * Append a big decimal in RPC transmission format. * * @param sName - * the optional parameter name + * the optional parameter name * @param bdValue - * the data value + * the data value * @param nScale - * the desired scale + * the desired scale * @param bOut - * boolean true if the data value is being registered as an ouput parameter + * boolean true if the data value is being registered as an ouput parameter */ - void writeRPCBigDecimal(String sName, - BigDecimal bdValue, - int nScale, - boolean bOut) throws SQLServerException { + void writeRPCBigDecimal(String sName, BigDecimal bdValue, int nScale, boolean bOut) throws SQLServerException { writeRPCNameValType(sName, bOut, TDSType.DECIMALN); writeByte((byte) 0x11); // maximum length writeByte((byte) SQLServerConnection.maxDecimalPrecision); // precision @@ -4403,15 +4325,13 @@ void writeRPCBigDecimal(String sName, * Appends a standard v*max header for RPC parameter transmission. * * @param headerLength - * the total length of the PLP data block. + * the total length of the PLP data block. * @param isNull - * true if the value is NULL. + * true if the value is NULL. * @param collation - * The SQL collation associated with the value that follows the v*max header. Null for non-textual types. + * The SQL collation associated with the value that follows the v*max header. Null for non-textual types. */ - void writeVMaxHeader(long headerLength, - boolean isNull, - SQLCollation collation) throws SQLServerException { + void writeVMaxHeader(long headerLength, boolean isNull, SQLCollation collation) throws SQLServerException { // Send v*max length indicator 0xFFFF. writeShort((short) 0xFFFF); @@ -4423,15 +4343,13 @@ void writeVMaxHeader(long headerLength, if (isNull) { // Null header for v*max types is 0xFFFFFFFFFFFFFFFF. writeLong(0xFFFFFFFFFFFFFFFFL); - } - else if (DataTypes.UNKNOWN_STREAM_LENGTH == headerLength) { + } else if (DataTypes.UNKNOWN_STREAM_LENGTH == headerLength) { // Append v*max length. // UNKNOWN_PLP_LEN is 0xFFFFFFFFFFFFFFFE writeLong(0xFFFFFFFFFFFFFFFEL); // NOTE: Don't send the first chunk length, this will be calculated by caller. - } - else { + } else { // For v*max types with known length, length is // We're sending same total length as chunk length (as we're sending 1 chunk). writeLong(headerLength); @@ -4449,17 +4367,15 @@ void writeRPCStringUnicode(String sValue) throws SQLServerException { * Writes a string value as Unicode for RPC * * @param sName - * the optional parameter name + * the optional parameter name * @param sValue - * the data value + * the data value * @param bOut - * boolean true if the data value is being registered as an ouput parameter + * boolean true if the data value is being registered as an ouput parameter * @param collation - * the collation of the data value + * the collation of the data value */ - void writeRPCStringUnicode(String sName, - String sValue, - boolean bOut, + void writeRPCStringUnicode(String sName, String sValue, boolean bOut, SQLCollation collation) throws SQLServerException { boolean bValueNull = (sValue == null); int nValueLen = bValueNull ? 0 : (2 * sValue.length()); @@ -4476,8 +4392,8 @@ void writeRPCStringUnicode(String sName, writeRPCNameValType(sName, bOut, TDSType.NVARCHAR); // Handle Yukon v*max type header here. - writeVMaxHeader(nValueLen, // Length - bValueNull, // Is null? + writeVMaxHeader(nValueLen, // Length + bValueNull, // Is null? collation); // Send the data. @@ -4490,15 +4406,13 @@ void writeRPCStringUnicode(String sName, // Send the terminator PLP chunk. writeInt(0); } - } - else // non-PLP type + } else // non-PLP type { // Write maximum length of data if (isShortValue) { writeRPCNameValType(sName, bOut, TDSType.NVARCHAR); writeShort((short) DataTypes.SHORT_VARTYPE_MAX_BYTES); - } - else { + } else { writeRPCNameValType(sName, bOut, TDSType.NTEXT); writeInt(DataTypes.IMAGE_TEXT_MAX_BYTES); } @@ -4508,8 +4422,7 @@ void writeRPCStringUnicode(String sName, // Data and length if (bValueNull) { writeShort((short) -1); // actual len - } - else { + } else { // Write actual length of data if (isShortValue) writeShort((short) nValueLen); @@ -4518,7 +4431,7 @@ void writeRPCStringUnicode(String sName, // If length is zero, we're done. if (0 != nValueLen) - writeString(sValue); // data + writeString(sValue); // data } } } @@ -4526,8 +4439,7 @@ void writeRPCStringUnicode(String sName, void writeTVP(TVP value) throws SQLServerException { if (!value.isNull()) { writeByte((byte) 0); // status - } - else { + } else { // Default TVP writeByte((byte) TDS.TVP_STATUS_DEFAULT); // default TVP } @@ -4541,33 +4453,29 @@ void writeTVP(TVP value) throws SQLServerException { if (null != value.getDbNameTVP()) { writeByte((byte) value.getDbNameTVP().length()); writeString(value.getDbNameTVP()); - } - else - writeByte((byte) 0x00); // empty DB name + } else + writeByte((byte) 0x00); // empty DB name // Schema where TVP type resides if (null != value.getOwningSchemaNameTVP()) { writeByte((byte) value.getOwningSchemaNameTVP().length()); writeString(value.getOwningSchemaNameTVP()); - } - else - writeByte((byte) 0x00); // empty Schema name + } else + writeByte((byte) 0x00); // empty Schema name // TVP type name if (null != value.getTVPName()) { writeByte((byte) value.getTVPName().length()); writeString(value.getTVPName()); - } - else - writeByte((byte) 0x00); // empty TVP name + } else + writeByte((byte) 0x00); // empty TVP name if (!value.isNull()) { writeTVPColumnMetaData(value); // optional OrderUnique metadata writeTvpOrderUnique(value); - } - else { + } else { writeShort((short) TDS.TVP_NULL_TOKEN); } @@ -4576,11 +4484,9 @@ void writeTVP(TVP value) throws SQLServerException { try { writeTVPRows(value); - } - catch (NumberFormatException e) { + } catch (NumberFormatException e) { throw new SQLServerException(SQLServerException.getErrString("R_TVPInvalidColumnValue"), e); - } - catch (ClassCastException e) { + } catch (ClassCastException e) { throw new SQLServerException(SQLServerException.getErrString("R_TVPInvalidColumnValue"), e); } } @@ -4596,8 +4502,10 @@ void writeTVPRows(TVP value) throws SQLServerException { if (!value.isNull()) { - // If the preparedStatement and the ResultSet are created by the same connection, and TVP is set with ResultSet and Server Cursor - // is used, the tdsWriter of the calling preparedStatement is overwritten by the SQLServerResultSet#next() method when fetching new rows. + // If the preparedStatement and the ResultSet are created by the same connection, and TVP is set with + // ResultSet and Server Cursor + // is used, the tdsWriter of the calling preparedStatement is overwritten by the SQLServerResultSet#next() + // method when fetching new rows. // Therefore, we need to send TVP data row by row before fetching new row. if (TVPType.ResultSet == value.tvpType) { if ((null != value.sourceResultSet) && (value.sourceResultSet instanceof SQLServerResultSet)) { @@ -4607,7 +4515,7 @@ void writeTVPRows(TVP value) throws SQLServerException { if (con.equals(src_stmt.getConnection()) && 0 != resultSetServerCursorId) { cachedTVPHeaders = ByteBuffer.allocate(stagingBuffer.capacity()).order(stagingBuffer.order()); - cachedTVPHeaders.put(stagingBuffer.array(), 0, ((Buffer)stagingBuffer).position()); + cachedTVPHeaders.put(stagingBuffer.array(), 0, ((Buffer) stagingBuffer).position()); cachedCommand = this.command; @@ -4633,9 +4541,9 @@ void writeTVPRows(TVP value) throws SQLServerException { if (tdsWritterCached) { command = cachedCommand; - ((Buffer)stagingBuffer).clear(); - ((Buffer)logBuffer).clear(); - writeBytes(cachedTVPHeaders.array(), 0, ((Buffer)cachedTVPHeaders).position()); + ((Buffer) stagingBuffer).clear(); + ((Buffer) logBuffer).clear(); + writeBytes(cachedTVPHeaders.array(), 0, ((Buffer) cachedTVPHeaders).position()); } Object[] rowData = value.getRowData(); @@ -4658,7 +4566,8 @@ void writeTVPRows(TVP value) throws SQLServerException { Object currentObject = null; if (null != rowData) { - // if rowData has value for the current column, retrieve it. If not, current column will stay null. + // if rowData has value for the current column, retrieve it. If not, current column will stay + // null. if (rowData.length > currentColumn) { currentObject = rowData[currentColumn]; if (null != currentObject) { @@ -4684,7 +4593,8 @@ void writeTVPRows(TVP value) throws SQLServerException { StreamError databaseError = new StreamError(); databaseError.setFromTDS(tdsReader); - SQLServerException.makeFromDatabaseError(con, null, databaseError.getMessage(), databaseError, false); + SQLServerException.makeFromDatabaseError(con, null, databaseError.getMessage(), databaseError, + false); } command.setInterruptsEnabled(true); @@ -4698,18 +4608,14 @@ void writeTVPRows(TVP value) throws SQLServerException { command.setRequestComplete(cachedRequestComplete); command.setInterruptsEnabled(cachedInterruptsEnabled); command.setProcessedResponse(cachedProcessedResponse); - } - else { + } else { // TVP_END_TOKEN writeByte((byte) 0x00); } } - private void writeInternalTVPRowValues(JDBCType jdbcType, - String currentColumnStringValue, - Object currentObject, - Map.Entry columnPair, - boolean isSqlVariant) throws SQLServerException { + private void writeInternalTVPRowValues(JDBCType jdbcType, String currentColumnStringValue, Object currentObject, + Map.Entry columnPair, boolean isSqlVariant) throws SQLServerException { boolean isShortValue, isNull; int dataLength; switch (jdbcType) { @@ -4719,8 +4625,7 @@ private void writeInternalTVPRowValues(JDBCType jdbcType, else { if (isSqlVariant) { writeTVPSqlVariantHeader(10, TDSType.INT8.byteValue(), (byte) 0); - } - else { + } else { writeByte((byte) 8); } writeLong(Long.valueOf(currentColumnStringValue).longValue()); @@ -4759,8 +4664,7 @@ private void writeInternalTVPRowValues(JDBCType jdbcType, if (isSqlVariant) { writeTVPSqlVariantHeader(6, TDSType.INT4.byteValue(), (byte) 0); writeInt(Integer.valueOf(currentColumnStringValue)); - } - else { + } else { writeByte((byte) 2); // length of datatype writeShort(Short.valueOf(currentColumnStringValue).shortValue()); } @@ -4776,16 +4680,15 @@ private void writeInternalTVPRowValues(JDBCType jdbcType, writeTVPSqlVariantHeader(21, TDSType.DECIMALN.byteValue(), (byte) 2); writeByte((byte) 38); // scale (byte)variantType.getScale() writeByte((byte) 4); // scale (byte)variantType.getScale() - } - else { + } else { writeByte((byte) TDSWriter.BIGDECIMAL_MAX_LENGTH); // maximum length } BigDecimal bdValue = new BigDecimal(currentColumnStringValue); /* - * setScale of all BigDecimal value based on metadata as scale is not sent seperately for individual value. Use the rounding used - * in Server. Say, for BigDecimal("0.1"), if scale in metdadata is 0, then ArithmeticException would be thrown if RoundingMode is - * not set + * setScale of all BigDecimal value based on metadata as scale is not sent seperately for individual + * value. Use the rounding used in Server. Say, for BigDecimal("0.1"), if scale in metdadata is 0, + * then ArithmeticException would be thrown if RoundingMode is not set */ bdValue = bdValue.setScale(columnPair.getValue().scale, RoundingMode.HALF_UP); @@ -4829,8 +4732,7 @@ private void writeInternalTVPRowValues(JDBCType jdbcType, if (isSqlVariant) { writeTVPSqlVariantHeader(6, TDSType.FLOAT4.byteValue(), (byte) 0); writeInt(Float.floatToRawIntBits(Float.valueOf(currentColumnStringValue).floatValue())); - } - else { + } else { writeByte((byte) 4); writeInt(Float.floatToRawIntBits(Float.valueOf(currentColumnStringValue).floatValue())); } @@ -4860,15 +4762,18 @@ private void writeInternalTVPRowValues(JDBCType jdbcType, if (isNull) { // Null header for v*max types is 0xFFFFFFFFFFFFFFFF. writeLong(0xFFFFFFFFFFFFFFFFL); - } - else if (isSqlVariant) { - // for now we send as bigger type, but is sendStringParameterAsUnicoe is set to false we can't send nvarchar + } else if (isSqlVariant) { + // for now we send as bigger type, but is sendStringParameterAsUnicoe is set to false we can't + // send nvarchar // since we are writing as nvarchar we need to write as tdstype.bigvarchar value because if we - // want to supprot varchar(8000) it becomes as nvarchar, 8000*2 therefore we should send as longvarchar, - // but we cannot send more than 8000 cause sql_variant datatype in sql server does not support it. + // want to supprot varchar(8000) it becomes as nvarchar, 8000*2 therefore we should send as + // longvarchar, + // but we cannot send more than 8000 cause sql_variant datatype in sql server does not support + // it. // then throw exception if user is sending more than that if (dataLength > 2 * DataTypes.SHORT_VARTYPE_MAX_BYTES) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidStringValue")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_invalidStringValue")); throw new SQLServerException(null, form.format(new Object[] {}), null, 0, false); } int length = currentColumnStringValue.length(); @@ -4897,13 +4802,13 @@ else if (DataTypes.UNKNOWN_STREAM_LENGTH == dataLength) // Send the terminator PLP chunk. writeInt(0); } - } - else { + } else { if (isNull) writeShort((short) -1); // actual len else { if (isSqlVariant) { - // for now we send as bigger type, but is sendStringParameterAsUnicoe is set to false we can't send nvarchar + // for now we send as bigger type, but is sendStringParameterAsUnicoe is set to false we + // can't send nvarchar // check for this int length = currentColumnStringValue.length() * 2; writeTVPSqlVariantHeader(9 + length, TDSType.NVARCHAR.byteValue(), (byte) 7); @@ -4918,8 +4823,7 @@ else if (DataTypes.UNKNOWN_STREAM_LENGTH == dataLength) writeBytes(typevarlen); writeString(currentColumnStringValue); break; - } - else { + } else { writeShort((short) dataLength); writeString(currentColumnStringValue); } @@ -4960,8 +4864,7 @@ else if (DataTypes.UNKNOWN_STREAM_LENGTH == dataLength) // Send the terminator PLP chunk. writeInt(0); } - } - else { + } else { if (isNull) writeShort((short) -1); // actual len else { @@ -4991,20 +4894,18 @@ else if (DataTypes.UNKNOWN_STREAM_LENGTH == dataLength) /** * writes Header for sql_variant for TVP + * * @param length * @param tdsType * @param probBytes * @throws SQLServerException */ - private void writeTVPSqlVariantHeader(int length, - byte tdsType, - byte probBytes) throws SQLServerException { + private void writeTVPSqlVariantHeader(int length, byte tdsType, byte probBytes) throws SQLServerException { writeInt(length); writeByte(tdsType); writeByte(probBytes); } - void writeTVPColumnMetaData(TVP value) throws SQLServerException { boolean isShortValue; @@ -5023,9 +4924,9 @@ void writeTVPColumnMetaData(TVP value) throws SQLServerException { // The value will be 0x0000 with the exceptions of TIMESTAMP (0x0050) and alias types (greater than 0x00FF). writeInt(0); /* - * Flags = fNullable ; Column is nullable - %x01 fCaseSen -- Ignored ; usUpdateable -- Ignored ; fIdentity ; Column is identity column - - * %x10 fComputed ; Column is computed - %x20 usReservedODBC -- Ignored ; fFixedLenCLRType-- Ignored ; fDefault ; Column is default value - * - %x200 usReserved -- Ignored ; + * Flags = fNullable ; Column is nullable - %x01 fCaseSen -- Ignored ; usUpdateable -- Ignored ; fIdentity ; + * Column is identity column - %x10 fComputed ; Column is computed - %x20 usReservedODBC -- Ignored ; + * fFixedLenCLRType-- Ignored ; fDefault ; Column is default value - %x200 usReserved -- Ignored ; */ short flags = TDS.FLAG_NULLABLE; @@ -5091,12 +4992,12 @@ void writeTVPColumnMetaData(TVP value) throws SQLServerException { writeByte(TDSType.NVARCHAR.byteValue()); isShortValue = (2L * pair.getValue().precision) <= DataTypes.SHORT_VARTYPE_MAX_BYTES; // Use PLP encoding on Yukon and later with long values - if (!isShortValue) // PLP + if (!isShortValue) // PLP { // Handle Yukon v*max type header here. writeShort((short) 0xFFFF); con.getDatabaseCollation().writeCollation(this); - } else // non PLP + } else // non PLP { writeShort((short) DataTypes.SHORT_VARTYPE_MAX_BYTES); con.getDatabaseCollation().writeCollation(this); @@ -5110,10 +5011,10 @@ void writeTVPColumnMetaData(TVP value) throws SQLServerException { writeByte(TDSType.BIGVARBINARY.byteValue()); isShortValue = pair.getValue().precision <= DataTypes.SHORT_VARTYPE_MAX_BYTES; // Use PLP encoding on Yukon and later with long values - if (!isShortValue) // PLP + if (!isShortValue) // PLP // Handle Yukon v*max type header here. writeShort((short) 0xFFFF); - else // non PLP + else // non PLP writeShort((short) DataTypes.SHORT_VARTYPE_MAX_BYTES); break; case SQL_VARIANT: @@ -5174,8 +5075,7 @@ private class TdsOrderUnique { int columnOrdinal; byte flags; - TdsOrderUnique(int ordinal, - byte flags) { + TdsOrderUnique(int ordinal, byte flags) { this.columnOrdinal = ordinal; this.flags = flags; } @@ -5199,26 +5099,21 @@ void writeEncryptedRPCByteArray(byte bValue[]) throws SQLServerException { // Handle Shiloh types here. if (isShortValue) { writeShort((short) DataTypes.SHORT_VARTYPE_MAX_BYTES); - } - else if (isPLP) { + } else if (isPLP) { writeShort((short) DataTypes.SQL_USHORTVARMAXLEN); - } - else { + } else { writeInt(DataTypes.IMAGE_TEXT_MAX_BYTES); } // Data and length if (bValueNull) { writeShort((short) -1); // actual len - } - else { + } else { if (isShortValue) { writeShort((short) nValueLen); // actual len - } - else if (isPLP) { + } else if (isPLP) { writeLong(nValueLen); // actual length - } - else { + } else { writeInt((int) nValueLen); // actual len } @@ -5252,10 +5147,7 @@ void writeCryptoMetaData() throws SQLServerException { writeByte(cryptoMeta.normalizationRuleVersion); } - void writeRPCByteArray(String sName, - byte bValue[], - boolean bOut, - JDBCType jdbcType, + void writeRPCByteArray(String sName, byte bValue[], boolean bOut, JDBCType jdbcType, SQLCollation collation) throws SQLServerException { boolean bValueNull = (bValue == null); int nValueLen = bValueNull ? 0 : bValue.length; @@ -5270,8 +5162,7 @@ void writeRPCByteArray(String sName, // send encrypted data as BIGVARBINARY tdsType = (isShortValue || usePLP) ? TDSType.BIGVARBINARY : TDSType.IMAGE; collation = null; - } - else + } else switch (jdbcType) { case BINARY: case VARBINARY: @@ -5317,14 +5208,12 @@ void writeRPCByteArray(String sName, // Send the terminator PLP chunk. writeInt(0); } - } - else // non-PLP type + } else // non-PLP type { // Handle Shiloh types here. if (isShortValue) { writeShort((short) DataTypes.SHORT_VARTYPE_MAX_BYTES); - } - else { + } else { writeInt(DataTypes.IMAGE_TEXT_MAX_BYTES); } @@ -5334,8 +5223,7 @@ void writeRPCByteArray(String sName, // Data and length if (bValueNull) { writeShort((short) -1); // actual len - } - else { + } else { if (isShortValue) writeShort((short) nValueLen); // actual len else @@ -5352,21 +5240,21 @@ void writeRPCByteArray(String sName, * Append a timestamp in RPC transmission format as a SQL Server DATETIME data type * * @param sName - * the optional parameter name + * the optional parameter name * @param cal - * Pure Gregorian calendar containing the timestamp, including its associated time zone + * Pure Gregorian calendar containing the timestamp, including its associated time zone * @param subSecondNanos - * the sub-second nanoseconds (0 - 999,999,999) + * the sub-second nanoseconds (0 - 999,999,999) * @param bOut - * boolean true if the data value is being registered as an ouput parameter + * boolean true if the data value is being registered as an ouput parameter * */ - void writeRPCDateTime(String sName, - GregorianCalendar cal, - int subSecondNanos, + void writeRPCDateTime(String sName, GregorianCalendar cal, int subSecondNanos, boolean bOut) throws SQLServerException { - assert (subSecondNanos >= 0) && (subSecondNanos < Nanos.PER_SECOND) : "Invalid subNanoSeconds value: " + subSecondNanos; - assert (cal != null) || (subSecondNanos == 0) : "Invalid subNanoSeconds value when calendar is null: " + subSecondNanos; + assert (subSecondNanos >= 0) && (subSecondNanos < Nanos.PER_SECOND) : "Invalid subNanoSeconds value: " + + subSecondNanos; + assert (cal != null) || (subSecondNanos == 0) : "Invalid subNanoSeconds value when calendar is null: " + + subSecondNanos; writeRPCNameValType(sName, bOut, TDSType.DATETIMEN); writeByte((byte) 8); // max length of datatype @@ -5395,10 +5283,13 @@ void writeRPCDateTime(String sName, // First, figure out how many days there have been since the SQL Base Date. // These are based on SQL Server algorithms - int daysSinceSQLBaseDate = DDC.daysSinceBaseDate(cal.get(Calendar.YEAR), cal.get(Calendar.DAY_OF_YEAR), TDS.BASE_YEAR_1900); + int daysSinceSQLBaseDate = DDC.daysSinceBaseDate(cal.get(Calendar.YEAR), cal.get(Calendar.DAY_OF_YEAR), + TDS.BASE_YEAR_1900); // Next, figure out the number of milliseconds since midnight of the current day. - int millisSinceMidnight = (subSecondNanos + Nanos.PER_MILLISECOND / 2) / Nanos.PER_MILLISECOND + // Millis into the current second + int millisSinceMidnight = (subSecondNanos + Nanos.PER_MILLISECOND / 2) / Nanos.PER_MILLISECOND + // Millis into + // the current + // second 1000 * cal.get(Calendar.SECOND) + // Seconds into the current minute 60 * 1000 * cal.get(Calendar.MINUTE) + // Minutes into the current hour 60 * 60 * 1000 * cal.get(Calendar.HOUR_OF_DAY); // Hours into the current day @@ -5420,7 +5311,8 @@ void writeRPCDateTime(String sName, || daysSinceSQLBaseDate >= DDC.daysSinceBaseDate(10000, 1, TDS.BASE_YEAR_1900)) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_valueOutOfRange")); Object[] msgArgs = {SSType.DATETIME}; - throw new SQLServerException(form.format(msgArgs), SQLState.DATA_EXCEPTION_DATETIME_FIELD_OVERFLOW, DriverError.NOT_SET, null); + throw new SQLServerException(form.format(msgArgs), SQLState.DATA_EXCEPTION_DATETIME_FIELD_OVERFLOW, + DriverError.NOT_SET, null); } // And put it all on the wire... @@ -5432,10 +5324,7 @@ void writeRPCDateTime(String sName, writeInt((3 * millisSinceMidnight + 5) / 10); } - void writeRPCTime(String sName, - GregorianCalendar localCalendar, - int subSecondNanos, - int scale, + void writeRPCTime(String sName, GregorianCalendar localCalendar, int subSecondNanos, int scale, boolean bOut) throws SQLServerException { writeRPCNameValType(sName, bOut, TDSType.TIMEN); writeByte((byte) scale); @@ -5449,9 +5338,7 @@ void writeRPCTime(String sName, writeScaledTemporal(localCalendar, subSecondNanos, scale, SSType.TIME); } - void writeRPCDate(String sName, - GregorianCalendar localCalendar, - boolean bOut) throws SQLServerException { + void writeRPCDate(String sName, GregorianCalendar localCalendar, boolean bOut) throws SQLServerException { writeRPCNameValType(sName, bOut, TDSType.DATEN); if (null == localCalendar) { writeByte((byte) 0); @@ -5464,10 +5351,7 @@ void writeRPCDate(String sName, SSType.DATE); } - void writeEncryptedRPCTime(String sName, - GregorianCalendar localCalendar, - int subSecondNanos, - int scale, + void writeEncryptedRPCTime(String sName, GregorianCalendar localCalendar, int subSecondNanos, int scale, boolean bOut) throws SQLServerException { if (con.getSendTimeAsDatetime()) { throw new SQLServerException(SQLServerException.getErrString("R_sendTimeAsDateTimeForAE"), null); @@ -5477,22 +5361,22 @@ void writeEncryptedRPCTime(String sName, if (null == localCalendar) writeEncryptedRPCByteArray(null); else - writeEncryptedRPCByteArray(writeEncryptedScaledTemporal(localCalendar, subSecondNanos, scale, SSType.TIME, (short) 0)); + writeEncryptedRPCByteArray( + writeEncryptedScaledTemporal(localCalendar, subSecondNanos, scale, SSType.TIME, (short) 0)); writeByte(TDSType.TIMEN.byteValue()); writeByte((byte) scale); writeCryptoMetaData(); } - void writeEncryptedRPCDate(String sName, - GregorianCalendar localCalendar, - boolean bOut) throws SQLServerException { + void writeEncryptedRPCDate(String sName, GregorianCalendar localCalendar, boolean bOut) throws SQLServerException { writeRPCNameValType(sName, bOut, TDSType.BIGVARBINARY); if (null == localCalendar) writeEncryptedRPCByteArray(null); else - writeEncryptedRPCByteArray(writeEncryptedScaledTemporal(localCalendar, 0, // subsecond nanos (none for a date value) + writeEncryptedRPCByteArray(writeEncryptedScaledTemporal(localCalendar, 0, // subsecond nanos (none for a + // date value) 0, // scale (dates are not scaled) SSType.DATE, (short) 0)); @@ -5500,13 +5384,12 @@ void writeEncryptedRPCDate(String sName, writeCryptoMetaData(); } - void writeEncryptedRPCDateTime(String sName, - GregorianCalendar cal, - int subSecondNanos, - boolean bOut, + void writeEncryptedRPCDateTime(String sName, GregorianCalendar cal, int subSecondNanos, boolean bOut, JDBCType jdbcType) throws SQLServerException { - assert (subSecondNanos >= 0) && (subSecondNanos < Nanos.PER_SECOND) : "Invalid subNanoSeconds value: " + subSecondNanos; - assert (cal != null) || (subSecondNanos == 0) : "Invalid subNanoSeconds value when calendar is null: " + subSecondNanos; + assert (subSecondNanos >= 0) && (subSecondNanos < Nanos.PER_SECOND) : "Invalid subNanoSeconds value: " + + subSecondNanos; + assert (cal != null) || (subSecondNanos == 0) : "Invalid subNanoSeconds value when calendar is null: " + + subSecondNanos; writeRPCNameValType(sName, bOut, TDSType.BIGVARBINARY); @@ -5518,8 +5401,7 @@ void writeEncryptedRPCDateTime(String sName, if (JDBCType.SMALLDATETIME == jdbcType) { writeByte(TDSType.DATETIMEN.byteValue()); writeByte((byte) 4); - } - else { + } else { writeByte(TDSType.DATETIMEN.byteValue()); writeByte((byte) 8); } @@ -5527,13 +5409,15 @@ void writeEncryptedRPCDateTime(String sName, } // getEncryptedDateTimeAsBytes is called if jdbcType/ssType is SMALLDATETIME or DATETIME - byte[] getEncryptedDateTimeAsBytes(GregorianCalendar cal, - int subSecondNanos, + byte[] getEncryptedDateTimeAsBytes(GregorianCalendar cal, int subSecondNanos, JDBCType jdbcType) throws SQLServerException { - int daysSinceSQLBaseDate = DDC.daysSinceBaseDate(cal.get(Calendar.YEAR), cal.get(Calendar.DAY_OF_YEAR), TDS.BASE_YEAR_1900); + int daysSinceSQLBaseDate = DDC.daysSinceBaseDate(cal.get(Calendar.YEAR), cal.get(Calendar.DAY_OF_YEAR), + TDS.BASE_YEAR_1900); // Next, figure out the number of milliseconds since midnight of the current day. - int millisSinceMidnight = (subSecondNanos + Nanos.PER_MILLISECOND / 2) / Nanos.PER_MILLISECOND + // Millis into the current second + int millisSinceMidnight = (subSecondNanos + Nanos.PER_MILLISECOND / 2) / Nanos.PER_MILLISECOND + // Millis into + // the current + // second 1000 * cal.get(Calendar.SECOND) + // Seconds into the current minute 60 * 1000 * cal.get(Calendar.MINUTE) + // Minutes into the current hour 60 * 60 * 1000 * cal.get(Calendar.HOUR_OF_DAY); // Hours into the current day @@ -5551,13 +5435,15 @@ byte[] getEncryptedDateTimeAsBytes(GregorianCalendar cal, int minutesSinceMidnight = (secondsSinceMidnight / 60); // Values that are 29.998 seconds or less are rounded down to the nearest minute - minutesSinceMidnight = ((secondsSinceMidnight % 60) > 29.998) ? minutesSinceMidnight + 1 : minutesSinceMidnight; + minutesSinceMidnight = ((secondsSinceMidnight % 60) > 29.998) ? minutesSinceMidnight + 1 + : minutesSinceMidnight; // minutesSinceMidnight for (23:59:30) int maxMinutesSinceMidnight_SmallDateTime = 1440; // Verification for smalldatetime to be within valid range of (1900.01.01) to (2079.06.06) // smalldatetime for unencrypted does not allow insertion of 2079.06.06 23:59:59 and it is rounded up - // to 2079.06.07 00:00:00, therefore, we are checking minutesSinceMidnight for that condition. If it's not within valid range, then + // to 2079.06.07 00:00:00, therefore, we are checking minutesSinceMidnight for that condition. If it's not + // within valid range, then // throw an exception now so that statement execution is safely canceled. // 157 is the calculated day of year from 06-06 , 1440 is minutesince midnight for (23:59:30) if ((daysSinceSQLBaseDate < DDC.daysSinceBaseDate(1900, 1, TDS.BASE_YEAR_1900) @@ -5566,7 +5452,8 @@ byte[] getEncryptedDateTimeAsBytes(GregorianCalendar cal, && minutesSinceMidnight >= maxMinutesSinceMidnight_SmallDateTime)) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_valueOutOfRange")); Object[] msgArgs = {SSType.SMALLDATETIME}; - throw new SQLServerException(form.format(msgArgs), SQLState.DATA_EXCEPTION_DATETIME_FIELD_OVERFLOW, DriverError.NOT_SET, null); + throw new SQLServerException(form.format(msgArgs), SQLState.DATA_EXCEPTION_DATETIME_FIELD_OVERFLOW, + DriverError.NOT_SET, null); } ByteBuffer days = ByteBuffer.allocate(2).order(ByteOrder.LITTLE_ENDIAN); @@ -5578,8 +5465,7 @@ byte[] getEncryptedDateTimeAsBytes(GregorianCalendar cal, System.arraycopy(days.array(), 0, value, 0, 2); System.arraycopy(seconds.array(), 0, value, 2, 2); return SQLServerSecurityUtility.encryptWithKey(value, cryptoMeta, con); - } - else if (JDBCType.DATETIME == jdbcType) { + } else if (JDBCType.DATETIME == jdbcType) { // Last-ditch verification that the value is in the valid range for the // DATETIMEN TDS data type (1/1/1753 to 12/31/9999). If it's not, then // throw an exception now so that statement execution is safely canceled. @@ -5591,7 +5477,8 @@ else if (JDBCType.DATETIME == jdbcType) { || daysSinceSQLBaseDate >= DDC.daysSinceBaseDate(10000, 1, TDS.BASE_YEAR_1900)) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_valueOutOfRange")); Object[] msgArgs = {SSType.DATETIME}; - throw new SQLServerException(form.format(msgArgs), SQLState.DATA_EXCEPTION_DATETIME_FIELD_OVERFLOW, DriverError.NOT_SET, null); + throw new SQLServerException(form.format(msgArgs), SQLState.DATA_EXCEPTION_DATETIME_FIELD_OVERFLOW, + DriverError.NOT_SET, null); } // Number of days since the SQL Server Base Date (January 1, 1900) @@ -5610,37 +5497,31 @@ else if (JDBCType.DATETIME == jdbcType) { return null; } - void writeEncryptedRPCDateTime2(String sName, - GregorianCalendar localCalendar, - int subSecondNanos, - int scale, + void writeEncryptedRPCDateTime2(String sName, GregorianCalendar localCalendar, int subSecondNanos, int scale, boolean bOut) throws SQLServerException { writeRPCNameValType(sName, bOut, TDSType.BIGVARBINARY); if (null == localCalendar) writeEncryptedRPCByteArray(null); else - writeEncryptedRPCByteArray(writeEncryptedScaledTemporal(localCalendar, subSecondNanos, scale, SSType.DATETIME2, (short) 0)); + writeEncryptedRPCByteArray( + writeEncryptedScaledTemporal(localCalendar, subSecondNanos, scale, SSType.DATETIME2, (short) 0)); writeByte(TDSType.DATETIME2N.byteValue()); writeByte((byte) (scale)); writeCryptoMetaData(); } - void writeEncryptedRPCDateTimeOffset(String sName, - GregorianCalendar utcCalendar, - int minutesOffset, - int subSecondNanos, - int scale, - boolean bOut) throws SQLServerException { + void writeEncryptedRPCDateTimeOffset(String sName, GregorianCalendar utcCalendar, int minutesOffset, + int subSecondNanos, int scale, boolean bOut) throws SQLServerException { writeRPCNameValType(sName, bOut, TDSType.BIGVARBINARY); if (null == utcCalendar) writeEncryptedRPCByteArray(null); else { assert 0 == utcCalendar.get(Calendar.ZONE_OFFSET); - writeEncryptedRPCByteArray( - writeEncryptedScaledTemporal(utcCalendar, subSecondNanos, scale, SSType.DATETIMEOFFSET, (short) minutesOffset)); + writeEncryptedRPCByteArray(writeEncryptedScaledTemporal(utcCalendar, subSecondNanos, scale, + SSType.DATETIMEOFFSET, (short) minutesOffset)); } writeByte(TDSType.DATETIMEOFFSETN.byteValue()); @@ -5649,10 +5530,7 @@ void writeEncryptedRPCDateTimeOffset(String sName, } - void writeRPCDateTime2(String sName, - GregorianCalendar localCalendar, - int subSecondNanos, - int scale, + void writeRPCDateTime2(String sName, GregorianCalendar localCalendar, int subSecondNanos, int scale, boolean bOut) throws SQLServerException { writeRPCNameValType(sName, bOut, TDSType.DATETIME2N); writeByte((byte) scale); @@ -5666,12 +5544,8 @@ void writeRPCDateTime2(String sName, writeScaledTemporal(localCalendar, subSecondNanos, scale, SSType.DATETIME2); } - void writeRPCDateTimeOffset(String sName, - GregorianCalendar utcCalendar, - int minutesOffset, - int subSecondNanos, - int scale, - boolean bOut) throws SQLServerException { + void writeRPCDateTimeOffset(String sName, GregorianCalendar utcCalendar, int minutesOffset, int subSecondNanos, + int scale, boolean bOut) throws SQLServerException { writeRPCNameValType(sName, bOut, TDSType.DATETIMEOFFSETN); writeByte((byte) scale); @@ -5688,43 +5562,42 @@ void writeRPCDateTimeOffset(String sName, writeShort((short) minutesOffset); } - /** - * Returns subSecondNanos rounded to the maximum precision supported. The maximum fractional scale is MAX_FRACTIONAL_SECONDS_SCALE(7). Eg1: if you - * pass 456,790,123 the function would return 456,790,100 Eg2: if you pass 456,790,150 the function would return 456,790,200 Eg3: if you pass - * 999,999,951 the function would return 1,000,000,000 This is done to ensure that we have consistent rounding behaviour in setters and getters. - * Bug #507919 + * Returns subSecondNanos rounded to the maximum precision supported. The maximum fractional scale is + * MAX_FRACTIONAL_SECONDS_SCALE(7). Eg1: if you pass 456,790,123 the function would return 456,790,100 Eg2: if you + * pass 456,790,150 the function would return 456,790,200 Eg3: if you pass 999,999,951 the function would return + * 1,000,000,000 This is done to ensure that we have consistent rounding behaviour in setters and getters. Bug + * #507919 */ private int getRoundedSubSecondNanos(int subSecondNanos) { - int roundedNanos = ((subSecondNanos + (Nanos.PER_MAX_SCALE_INTERVAL / 2)) / Nanos.PER_MAX_SCALE_INTERVAL) * Nanos.PER_MAX_SCALE_INTERVAL; + int roundedNanos = ((subSecondNanos + (Nanos.PER_MAX_SCALE_INTERVAL / 2)) / Nanos.PER_MAX_SCALE_INTERVAL) + * Nanos.PER_MAX_SCALE_INTERVAL; return roundedNanos; } /** - * Writes to the TDS channel a temporal value as an instance instance of one of the scaled temporal SQL types: DATE, TIME, DATETIME2, or - * DATETIMEOFFSET. + * Writes to the TDS channel a temporal value as an instance instance of one of the scaled temporal SQL types: DATE, + * TIME, DATETIME2, or DATETIMEOFFSET. * * @param cal - * Calendar representing the value to write, except for any sub-second nanoseconds + * Calendar representing the value to write, except for any sub-second nanoseconds * @param subSecondNanos - * the sub-second nanoseconds (0 - 999,999,999) + * the sub-second nanoseconds (0 - 999,999,999) * @param scale - * the scale (in digits: 0 - 7) to use for the sub-second nanos component + * the scale (in digits: 0 - 7) to use for the sub-second nanos component * @param ssType - * the SQL Server data type (DATE, TIME, DATETIME2, or DATETIMEOFFSET) + * the SQL Server data type (DATE, TIME, DATETIME2, or DATETIMEOFFSET) * * @throws SQLServerException - * if an I/O error occurs or if the value is not in the valid range + * if an I/O error occurs or if the value is not in the valid range */ - private void writeScaledTemporal(GregorianCalendar cal, - int subSecondNanos, - int scale, + private void writeScaledTemporal(GregorianCalendar cal, int subSecondNanos, int scale, SSType ssType) throws SQLServerException { assert con.isKatmaiOrLater(); - assert SSType.DATE == ssType || SSType.TIME == ssType || SSType.DATETIME2 == ssType || SSType.DATETIMEOFFSET == ssType : "Unexpected SSType: " - + ssType; + assert SSType.DATE == ssType || SSType.TIME == ssType || SSType.DATETIME2 == ssType + || SSType.DATETIMEOFFSET == ssType : "Unexpected SSType: " + ssType; // First, for types with a time component, write the scaled nanos since midnight if (SSType.TIME == ssType || SSType.DATETIME2 == ssType || SSType.DATETIMEOFFSET == ssType) { @@ -5733,7 +5606,8 @@ private void writeScaledTemporal(GregorianCalendar cal, assert scale >= 0; assert scale <= TDS.MAX_FRACTIONAL_SECONDS_SCALE; - int secondsSinceMidnight = cal.get(Calendar.SECOND) + 60 * cal.get(Calendar.MINUTE) + 60 * 60 * cal.get(Calendar.HOUR_OF_DAY); + int secondsSinceMidnight = cal.get(Calendar.SECOND) + 60 * cal.get(Calendar.MINUTE) + + 60 * 60 * cal.get(Calendar.HOUR_OF_DAY); // Scale nanos since midnight to the desired scale, rounding the value as necessary long divisor = Nanos.PER_MAX_SCALE_INTERVAL * (long) Math.pow(10, TDS.MAX_FRACTIONAL_SECONDS_SCALE - scale); @@ -5742,7 +5616,8 @@ private void writeScaledTemporal(GregorianCalendar cal, // indicated by the scale variable. So, for example, scaledNanos = 3 means 300 nanoseconds // at scale TDS.MAX_FRACTIONAL_SECONDS_SCALE, but 3000 nanoseconds at // TDS.MAX_FRACTIONAL_SECONDS_SCALE - 1 - long scaledNanos = ((long) Nanos.PER_SECOND * secondsSinceMidnight + getRoundedSubSecondNanos(subSecondNanos) + divisor / 2) / divisor; + long scaledNanos = ((long) Nanos.PER_SECOND * secondsSinceMidnight + + getRoundedSubSecondNanos(subSecondNanos) + divisor / 2) / divisor; // SQL Server rounding behavior indicates that it always rounds up unless // we are at the max value of the type(NOT every day), in which case it truncates. @@ -5756,7 +5631,8 @@ private void writeScaledTemporal(GregorianCalendar cal, } // If the type is datetime2 or datetimeoffset, truncate only if its the max value supported else { - assert SSType.DATETIME2 == ssType || SSType.DATETIMEOFFSET == ssType : "Unexpected SSType: " + ssType; + assert SSType.DATETIME2 == ssType || SSType.DATETIMEOFFSET == ssType : "Unexpected SSType: " + + ssType; // ... then bump the date, provided that the resulting date is still within // the valid date range. @@ -5773,8 +5649,7 @@ private void writeScaledTemporal(GregorianCalendar cal, if (cal.get(Calendar.YEAR) <= 9999) { scaledNanos = 0; - } - else { + } else { cal.add(Calendar.SECOND, -1); --scaledNanos; } @@ -5821,7 +5696,8 @@ private void writeScaledTemporal(GregorianCalendar cal, if (daysIntoCE < 0 || daysIntoCE >= DDC.daysSinceBaseDate(10000, 1, 1)) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_valueOutOfRange")); Object[] msgArgs = {ssType}; - throw new SQLServerException(form.format(msgArgs), SQLState.DATA_EXCEPTION_DATETIME_FIELD_OVERFLOW, DriverError.NOT_SET, null); + throw new SQLServerException(form.format(msgArgs), SQLState.DATA_EXCEPTION_DATETIME_FIELD_OVERFLOW, + DriverError.NOT_SET, null); } byte encodedBytes[] = new byte[3]; @@ -5833,31 +5709,28 @@ private void writeScaledTemporal(GregorianCalendar cal, } /** - * Writes to the TDS channel a temporal value as an instance instance of one of the scaled temporal SQL types: DATE, TIME, DATETIME2, or - * DATETIMEOFFSET. + * Writes to the TDS channel a temporal value as an instance instance of one of the scaled temporal SQL types: DATE, + * TIME, DATETIME2, or DATETIMEOFFSET. * * @param cal - * Calendar representing the value to write, except for any sub-second nanoseconds + * Calendar representing the value to write, except for any sub-second nanoseconds * @param subSecondNanos - * the sub-second nanoseconds (0 - 999,999,999) + * the sub-second nanoseconds (0 - 999,999,999) * @param scale - * the scale (in digits: 0 - 7) to use for the sub-second nanos component + * the scale (in digits: 0 - 7) to use for the sub-second nanos component * @param ssType - * the SQL Server data type (DATE, TIME, DATETIME2, or DATETIMEOFFSET) + * the SQL Server data type (DATE, TIME, DATETIME2, or DATETIMEOFFSET) * @param minutesOffset - * the offset value for DATETIMEOFFSET + * the offset value for DATETIMEOFFSET * @throws SQLServerException - * if an I/O error occurs or if the value is not in the valid range + * if an I/O error occurs or if the value is not in the valid range */ - byte[] writeEncryptedScaledTemporal(GregorianCalendar cal, - int subSecondNanos, - int scale, - SSType ssType, + byte[] writeEncryptedScaledTemporal(GregorianCalendar cal, int subSecondNanos, int scale, SSType ssType, short minutesOffset) throws SQLServerException { assert con.isKatmaiOrLater(); - assert SSType.DATE == ssType || SSType.TIME == ssType || SSType.DATETIME2 == ssType || SSType.DATETIMEOFFSET == ssType : "Unexpected SSType: " - + ssType; + assert SSType.DATE == ssType || SSType.TIME == ssType || SSType.DATETIME2 == ssType + || SSType.DATETIMEOFFSET == ssType : "Unexpected SSType: " + ssType; // store the time and minutesOffset portion of DATETIME2 and DATETIMEOFFSET to be used with date portion byte encodedBytesForEncryption[] = null; @@ -5873,7 +5746,8 @@ byte[] writeEncryptedScaledTemporal(GregorianCalendar cal, assert scale >= 0; assert scale <= TDS.MAX_FRACTIONAL_SECONDS_SCALE; - secondsSinceMidnight = cal.get(Calendar.SECOND) + 60 * cal.get(Calendar.MINUTE) + 60 * 60 * cal.get(Calendar.HOUR_OF_DAY); + secondsSinceMidnight = cal.get(Calendar.SECOND) + 60 * cal.get(Calendar.MINUTE) + + 60 * 60 * cal.get(Calendar.HOUR_OF_DAY); // Scale nanos since midnight to the desired scale, rounding the value as necessary divisor = Nanos.PER_MAX_SCALE_INTERVAL * (long) Math.pow(10, TDS.MAX_FRACTIONAL_SECONDS_SCALE - scale); @@ -5882,13 +5756,14 @@ byte[] writeEncryptedScaledTemporal(GregorianCalendar cal, // indicated by the scale variable. So, for example, scaledNanos = 3 means 300 nanoseconds // at scale TDS.MAX_FRACTIONAL_SECONDS_SCALE, but 3000 nanoseconds at // TDS.MAX_FRACTIONAL_SECONDS_SCALE - 1 - scaledNanos = (((long) Nanos.PER_SECOND * secondsSinceMidnight + getRoundedSubSecondNanos(subSecondNanos) + divisor / 2) / divisor) - * divisor / 100; + scaledNanos = (((long) Nanos.PER_SECOND * secondsSinceMidnight + getRoundedSubSecondNanos(subSecondNanos) + + divisor / 2) / divisor) * divisor / 100; // for encrypted time value, SQL server cannot do rounding or casting, // So, driver needs to cast it before encryption. if (SSType.TIME == ssType && 864000000000L <= scaledNanos) { - scaledNanos = (((long) Nanos.PER_SECOND * secondsSinceMidnight + getRoundedSubSecondNanos(subSecondNanos)) / divisor) * divisor / 100; + scaledNanos = (((long) Nanos.PER_SECOND * secondsSinceMidnight + + getRoundedSubSecondNanos(subSecondNanos)) / divisor) * divisor / 100; } // SQL Server rounding behavior indicates that it always rounds up unless @@ -5903,7 +5778,8 @@ byte[] writeEncryptedScaledTemporal(GregorianCalendar cal, } // If the type is datetime2 or datetimeoffset, truncate only if its the max value supported else { - assert SSType.DATETIME2 == ssType || SSType.DATETIMEOFFSET == ssType : "Unexpected SSType: " + ssType; + assert SSType.DATETIME2 == ssType || SSType.DATETIMEOFFSET == ssType : "Unexpected SSType: " + + ssType; // ... then bump the date, provided that the resulting date is still within // the valid date range. @@ -5920,8 +5796,7 @@ byte[] writeEncryptedScaledTemporal(GregorianCalendar cal, if (cal.get(Calendar.YEAR) <= 9999) { scaledNanos = 0; - } - else { + } else { cal.add(Calendar.SECOND, -1); --scaledNanos; } @@ -5935,13 +5810,11 @@ byte[] writeEncryptedScaledTemporal(GregorianCalendar cal, if (SSType.TIME == ssType) { byte[] cipherText = SQLServerSecurityUtility.encryptWithKey(encodedBytes, cryptoMeta, con); return cipherText; - } - else if (SSType.DATETIME2 == ssType) { + } else if (SSType.DATETIME2 == ssType) { // for DATETIME2 sends both date and time part together for encryption encodedBytesForEncryption = new byte[encodedLength + 3]; System.arraycopy(encodedBytes, 0, encodedBytesForEncryption, 0, encodedBytes.length); - } - else if (SSType.DATETIMEOFFSET == ssType) { + } else if (SSType.DATETIMEOFFSET == ssType) { // for DATETIMEOFFSET sends date, time and offset part together for encryption encodedBytesForEncryption = new byte[encodedLength + 5]; System.arraycopy(encodedBytes, 0, encodedBytesForEncryption, 0, encodedBytes.length); @@ -5981,7 +5854,8 @@ else if (SSType.DATETIMEOFFSET == ssType) { if (daysIntoCE < 0 || daysIntoCE >= DDC.daysSinceBaseDate(10000, 1, 1)) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_valueOutOfRange")); Object[] msgArgs = {ssType}; - throw new SQLServerException(form.format(msgArgs), SQLState.DATA_EXCEPTION_DATETIME_FIELD_OVERFLOW, DriverError.NOT_SET, null); + throw new SQLServerException(form.format(msgArgs), SQLState.DATA_EXCEPTION_DATETIME_FIELD_OVERFLOW, + DriverError.NOT_SET, null); } byte encodedBytes[] = new byte[3]; @@ -5992,14 +5866,13 @@ else if (SSType.DATETIMEOFFSET == ssType) { byte[] cipherText; if (SSType.DATE == ssType) { cipherText = SQLServerSecurityUtility.encryptWithKey(encodedBytes, cryptoMeta, con); - } - else if (SSType.DATETIME2 == ssType) { + } else if (SSType.DATETIME2 == ssType) { // for Max value, does not round up, do casting instead. - if (3652058 == daysIntoCE) { // 9999-12-31 - if (864000000000L == scaledNanos) { // 24:00:00 in nanoseconds + if (3652058 == daysIntoCE) { // 9999-12-31 + if (864000000000L == scaledNanos) { // 24:00:00 in nanoseconds // does not round up - scaledNanos = (((long) Nanos.PER_SECOND * secondsSinceMidnight + getRoundedSubSecondNanos(subSecondNanos)) / divisor) - * divisor / 100; + scaledNanos = (((long) Nanos.PER_SECOND * secondsSinceMidnight + + getRoundedSubSecondNanos(subSecondNanos)) / divisor) * divisor / 100; int encodedLength = TDS.nanosSinceMidnightLength(TDS.MAX_FRACTIONAL_SECONDS_SCALE); byte[] encodedNanoBytes = scaledNanosToEncodedBytes(scaledNanos, encodedLength); @@ -6013,14 +5886,13 @@ else if (SSType.DATETIME2 == ssType) { System.arraycopy(encodedBytes, 0, encodedBytesForEncryption, (encodedBytesForEncryption.length - 3), 3); cipherText = SQLServerSecurityUtility.encryptWithKey(encodedBytesForEncryption, cryptoMeta, con); - } - else { + } else { // for Max value, does not round up, do casting instead. - if (3652058 == daysIntoCE) { // 9999-12-31 - if (864000000000L == scaledNanos) { // 24:00:00 in nanoseconds + if (3652058 == daysIntoCE) { // 9999-12-31 + if (864000000000L == scaledNanos) { // 24:00:00 in nanoseconds // does not round up - scaledNanos = (((long) Nanos.PER_SECOND * secondsSinceMidnight + getRoundedSubSecondNanos(subSecondNanos)) / divisor) - * divisor / 100; + scaledNanos = (((long) Nanos.PER_SECOND * secondsSinceMidnight + + getRoundedSubSecondNanos(subSecondNanos)) / divisor) * divisor / 100; int encodedLength = TDS.nanosSinceMidnightLength(TDS.MAX_FRACTIONAL_SECONDS_SCALE); byte[] encodedNanoBytes = scaledNanosToEncodedBytes(scaledNanos, encodedLength); @@ -6034,8 +5906,10 @@ else if (SSType.DATETIME2 == ssType) { // Copy the 3 byte date value System.arraycopy(encodedBytes, 0, encodedBytesForEncryption, (encodedBytesForEncryption.length - 5), 3); // Copy the 2 byte minutesOffset value - System.arraycopy(ByteBuffer.allocate(Short.SIZE / Byte.SIZE).order(ByteOrder.LITTLE_ENDIAN).putShort(minutesOffset).array(), 0, - encodedBytesForEncryption, (encodedBytesForEncryption.length - 2), 2); + System.arraycopy( + ByteBuffer.allocate(Short.SIZE / Byte.SIZE).order(ByteOrder.LITTLE_ENDIAN) + .putShort(minutesOffset).array(), + 0, encodedBytesForEncryption, (encodedBytesForEncryption.length - 2), 2); cipherText = SQLServerSecurityUtility.encryptWithKey(encodedBytesForEncryption, cryptoMeta, con); } @@ -6050,8 +5924,7 @@ else if (SSType.DATETIME2 == ssType) { return null; } - private byte[] scaledNanosToEncodedBytes(long scaledNanos, - int encodedLength) { + private byte[] scaledNanosToEncodedBytes(long scaledNanos, int encodedLength) { byte encodedBytes[] = new byte[encodedLength]; for (int i = 0; i < encodedLength; i++) encodedBytes[i] = (byte) ((scaledNanos >> (8 * i)) & 0xFF); @@ -6062,31 +5935,28 @@ private byte[] scaledNanosToEncodedBytes(long scaledNanos, * Append the data in a stream in RPC transmission format. * * @param sName - * the optional parameter name + * the optional parameter name * @param stream - * is the stream + * is the stream * @param streamLength - * length of the stream (may be unknown) + * length of the stream (may be unknown) * @param bOut - * boolean true if the data value is being registered as an ouput parameter + * boolean true if the data value is being registered as an ouput parameter * @param jdbcType - * The JDBC type used to determine whether the value is textual or non-textual. + * The JDBC type used to determine whether the value is textual or non-textual. * @param collation - * The SQL collation associated with the value. Null for non-textual SQL Server types. + * The SQL collation associated with the value. Null for non-textual SQL Server types. * @throws SQLServerException */ - void writeRPCInputStream(String sName, - InputStream stream, - long streamLength, - boolean bOut, - JDBCType jdbcType, + void writeRPCInputStream(String sName, InputStream stream, long streamLength, boolean bOut, JDBCType jdbcType, SQLCollation collation) throws SQLServerException { assert null != stream; assert DataTypes.UNKNOWN_STREAM_LENGTH == streamLength || streamLength >= 0; // Send long values and values with unknown length // using PLP chunking on Yukon and later. - boolean usePLP = (DataTypes.UNKNOWN_STREAM_LENGTH == streamLength || streamLength > DataTypes.SHORT_VARTYPE_MAX_BYTES); + boolean usePLP = (DataTypes.UNKNOWN_STREAM_LENGTH == streamLength + || streamLength > DataTypes.SHORT_VARTYPE_MAX_BYTES); if (usePLP) { assert DataTypes.UNKNOWN_STREAM_LENGTH == streamLength || streamLength <= DataTypes.MAX_VARTYPE_MAX_BYTES; @@ -6119,9 +5989,9 @@ void writeRPCInputStream(String sName, baos.write(buff); streamLength += bytesRead; } - } - catch (IOException e) { - throw new SQLServerException(e.getMessage(), SQLState.DATA_EXCEPTION_NOT_SPECIFIC, DriverError.NOT_SET, e); + } catch (IOException e) { + throw new SQLServerException(e.getMessage(), SQLState.DATA_EXCEPTION_NOT_SPECIFIC, + DriverError.NOT_SET, e); } if (streamLength >= maxStreamLength) { @@ -6139,7 +6009,8 @@ void writeRPCInputStream(String sName, boolean useVarType = streamLength <= DataTypes.SHORT_VARTYPE_MAX_BYTES; writeRPCNameValType(sName, bOut, - jdbcType.isTextual() ? (useVarType ? TDSType.BIGVARCHAR : TDSType.TEXT) : (useVarType ? TDSType.BIGVARBINARY : TDSType.IMAGE)); + jdbcType.isTextual() ? (useVarType ? TDSType.BIGVARCHAR : TDSType.TEXT) + : (useVarType ? TDSType.BIGVARBINARY : TDSType.IMAGE)); // Write maximum length, optional collation, and actual length if (useVarType) { @@ -6147,8 +6018,7 @@ void writeRPCInputStream(String sName, if (jdbcType.isTextual()) collation.writeCollation(this); writeShort((short) streamLength); - } - else { + } else { writeInt(DataTypes.IMAGE_TEXT_MAX_BYTES); if (jdbcType.isTextual()) collation.writeCollation(this); @@ -6164,19 +6034,16 @@ void writeRPCInputStream(String sName, * Append the XML data in a stream in RPC transmission format. * * @param sName - * the optional parameter name + * the optional parameter name * @param stream - * is the stream + * is the stream * @param streamLength - * length of the stream (may be unknown) + * length of the stream (may be unknown) * @param bOut - * boolean true if the data value is being registered as an ouput parameter + * boolean true if the data value is being registered as an ouput parameter * @throws SQLServerException */ - void writeRPCXML(String sName, - InputStream stream, - long streamLength, - boolean bOut) throws SQLServerException { + void writeRPCXML(String sName, InputStream stream, long streamLength, boolean bOut) throws SQLServerException { assert DataTypes.UNKNOWN_STREAM_LENGTH == streamLength || streamLength >= 0; assert DataTypes.UNKNOWN_STREAM_LENGTH == streamLength || streamLength <= DataTypes.MAX_VARTYPE_MAX_BYTES; @@ -6186,15 +6053,13 @@ void writeRPCXML(String sName, if (null == stream) { // Null header for v*max types is 0xFFFFFFFFFFFFFFFF. writeLong(0xFFFFFFFFFFFFFFFFL); - } - else if (DataTypes.UNKNOWN_STREAM_LENGTH == streamLength) { + } else if (DataTypes.UNKNOWN_STREAM_LENGTH == streamLength) { // Append v*max length. // UNKNOWN_PLP_LEN is 0xFFFFFFFFFFFFFFFE writeLong(0xFFFFFFFFFFFFFFFEL); // NOTE: Don't send the first chunk length, this will be calculated by caller. - } - else { + } else { // For v*max types with known length, length is // We're sending same total length as chunk length (as we're sending 1 chunk). writeLong(streamLength); @@ -6208,21 +6073,18 @@ else if (DataTypes.UNKNOWN_STREAM_LENGTH == streamLength) { * Append the data in a character reader in RPC transmission format. * * @param sName - * the optional parameter name + * the optional parameter name * @param re - * the reader + * the reader * @param reLength - * the reader data length (in characters) + * the reader data length (in characters) * @param bOut - * boolean true if the data value is being registered as an ouput parameter + * boolean true if the data value is being registered as an ouput parameter * @param collation - * The SQL collation associated with the value. Null for non-textual SQL Server types. + * The SQL collation associated with the value. Null for non-textual SQL Server types. * @throws SQLServerException */ - void writeRPCReaderUnicode(String sName, - Reader re, - long reLength, - boolean bOut, + void writeRPCReaderUnicode(String sName, Reader re, long reLength, boolean bOut, SQLCollation collation) throws SQLServerException { assert null != re; assert DataTypes.UNKNOWN_STREAM_LENGTH == reLength || reLength >= 0; @@ -6241,7 +6103,10 @@ void writeRPCReaderUnicode(String sName, writeRPCNameValType(sName, bOut, TDSType.NVARCHAR); // Handle Yukon v*max type header here. - writeVMaxHeader((DataTypes.UNKNOWN_STREAM_LENGTH == reLength) ? DataTypes.UNKNOWN_STREAM_LENGTH : 2 * reLength, // Length (in bytes) + writeVMaxHeader( + (DataTypes.UNKNOWN_STREAM_LENGTH == reLength) ? DataTypes.UNKNOWN_STREAM_LENGTH : 2 * reLength, // Length + // (in + // bytes) false, collation); } @@ -6264,8 +6129,7 @@ void writeRPCReaderUnicode(String sName, writeShort((short) DataTypes.SHORT_VARTYPE_MAX_BYTES); collation.writeCollation(this); writeShort((short) (2 * reLength)); - } - else { + } else { writeInt(DataTypes.NTEXT_MAX_CHARS); collation.writeCollation(this); writeInt((int) (2 * reLength)); @@ -6277,12 +6141,14 @@ void writeRPCReaderUnicode(String sName, } } + /** * TDSPacket provides a mechanism for chaining TDS response packets together in a singly-linked list. * - * Having both the link and the data in the same class allows TDSReader marks (see below) to automatically hold onto exactly as much response data as - * they need, and no more. Java reference semantics ensure that a mark holds onto its referenced packet and subsequent packets (through next - * references). When all marked references to a packet go away, the packet, and any linked unmarked packets, can be reclaimed by GC. + * Having both the link and the data in the same class allows TDSReader marks (see below) to automatically hold onto + * exactly as much response data as they need, and no more. Java reference semantics ensure that a mark holds onto its + * referenced packet and subsequent packets (through next references). When all marked references to a packet go away, + * the packet, and any linked unmarked packets, can be reclaimed by GC. */ final class TDSPacket { final byte[] header = new byte[TDS.PACKET_HEADER_SIZE]; @@ -6291,8 +6157,8 @@ final class TDSPacket { volatile TDSPacket next; final public String toString() { - return "TDSPacket(SPID:" + Util.readUnsignedShortBigEndian(header, TDS.PACKET_HEADER_SPID) + " Seq:" + header[TDS.PACKET_HEADER_SEQUENCE_NUM] - + ")"; + return "TDSPacket(SPID:" + Util.readUnsignedShortBigEndian(header, TDS.PACKET_HEADER_SPID) + " Seq:" + + header[TDS.PACKET_HEADER_SEQUENCE_NUM] + ")"; } TDSPacket(int size) { @@ -6306,23 +6172,25 @@ final boolean isEOM() { } }; + /** * TDSReaderMark encapsulates a fixed position in the response data stream. * - * Response data is quantized into a linked chain of packets. A mark refers to a specific location in a specific packet and relies on Java's reference - * semantics to automatically keep all subsequent packets accessible until the mark is destroyed. + * Response data is quantized into a linked chain of packets. A mark refers to a specific location in a specific packet + * and relies on Java's reference semantics to automatically keep all subsequent packets accessible until the mark is + * destroyed. */ final class TDSReaderMark { final TDSPacket packet; final int payloadOffset; - TDSReaderMark(TDSPacket packet, - int payloadOffset) { + TDSReaderMark(TDSPacket packet, int payloadOffset) { this.packet = packet; this.payloadOffset = payloadOffset; } } + /** * TDSReader encapsulates the TDS response data stream. * @@ -6332,7 +6200,7 @@ final class TDSReader { private final static Logger logger = Logger.getLogger("com.microsoft.sqlserver.jdbc.internals.TDS.Reader"); final private String traceID; private TimeoutTimer tcpKeepAliveTimeoutTimer; - + final public String toString() { return traceID; } @@ -6350,7 +6218,7 @@ final TDSCommand getCommand() { final SQLServerConnection getConnection() { return con; } - + private TDSPacket currentPacket = new TDSPacket(0); private TDSPacket lastPacket = currentPacket; private int payloadOffset = 0; @@ -6362,7 +6230,7 @@ final SQLServerConnection getConnection() { private boolean serverSupportsDataClassification = false; private final byte valueBytes[] = new byte[256]; - + protected SensitivityClassification sensitivityClassification; private static final AtomicInteger lastReaderID = new AtomicInteger(0); @@ -6371,16 +6239,20 @@ private static int nextReaderID() { return lastReaderID.incrementAndGet(); } - TDSReader(TDSChannel tdsChannel, - SQLServerConnection con, - TDSCommand command) { + TDSReader(TDSChannel tdsChannel, SQLServerConnection con, TDSCommand command) { this.tdsChannel = tdsChannel; this.con = con; this.command = command; // may be null - if(null != command) { - //if cancelQueryTimeout is set, we should wait for the total amount of queryTimeout + cancelQueryTimeout to terminate the connection. - this.tcpKeepAliveTimeoutTimer = (command.getCancelQueryTimeoutSeconds() > 0 && command.getQueryTimeoutSeconds() > 0 ) ? - (new TimeoutTimer(command.getCancelQueryTimeoutSeconds() + command.getQueryTimeoutSeconds(), null, con)) : null; + if (null != command) { + // if cancelQueryTimeout is set, we should wait for the total amount of queryTimeout + cancelQueryTimeout to + // terminate the connection. + this.tcpKeepAliveTimeoutTimer = (command.getCancelQueryTimeoutSeconds() > 0 + && command.getQueryTimeoutSeconds() > 0) + ? (new TimeoutTimer( + command.getCancelQueryTimeoutSeconds() + + command.getQueryTimeoutSeconds(), + null, con)) + : null; } // if the logging level is not detailed than fine or more we will not have proper reader IDs. if (logger.isLoggable(Level.FINE)) @@ -6405,7 +6277,7 @@ final boolean getServerSupportsColumnEncryption() { final boolean getServerSupportsDataClassification() { return serverSupportsDataClassification; } - + final void throwInvalidTDS() throws SQLServerException { if (logger.isLoggable(Level.SEVERE)) logger.severe(toString() + " got unexpected value in TDS response at offset:" + payloadOffset); @@ -6419,7 +6291,8 @@ final void throwInvalidTDSToken(String tokenName) throws SQLServerException { } /** - * Ensures that payload data is available to be read, automatically advancing to (and possibly reading) the next packet. + * Ensures that payload data is available to be read, automatically advancing to (and possibly reading) the next + * packet. * * @return true if additional data is available to be read false if no more data is available */ @@ -6471,8 +6344,8 @@ private boolean nextPacket() throws SQLServerException { /** * Reads the next packet of the TDS channel. * - * This method is synchronized to guard against simultaneously reading packets from one thread that is processing the response and another thread - * that is trying to buffer it with TDSCommand.detach(). + * This method is synchronized to guard against simultaneously reading packets from one thread that is processing + * the response and another thread that is trying to buffer it with TDSCommand.detach(). */ synchronized final boolean readPacket() throws SQLServerException { if (null != command && !command.readingResponse()) @@ -6481,8 +6354,8 @@ synchronized final boolean readPacket() throws SQLServerException { // Number of packets in should always be less than number of packets out. // If the server has been notified for an interrupt, it may be less by // more than one packet. - assert tdsChannel.numMsgsRcvd < tdsChannel.numMsgsSent : "numMsgsRcvd:" + tdsChannel.numMsgsRcvd + " should be less than numMsgsSent:" - + tdsChannel.numMsgsSent; + assert tdsChannel.numMsgsRcvd < tdsChannel.numMsgsSent : "numMsgsRcvd:" + tdsChannel.numMsgsRcvd + + " should be less than numMsgsSent:" + tdsChannel.numMsgsSent; TDSPacket newPacket = new TDSPacket(con.getTDSPacketSize()); if (null != tcpKeepAliveTimeoutTimer) { @@ -6493,18 +6366,21 @@ synchronized final boolean readPacket() throws SQLServerException { } // First, read the packet header. for (int headerBytesRead = 0; headerBytesRead < TDS.PACKET_HEADER_SIZE;) { - int bytesRead = tdsChannel.read(newPacket.header, headerBytesRead, TDS.PACKET_HEADER_SIZE - headerBytesRead); + int bytesRead = tdsChannel.read(newPacket.header, headerBytesRead, + TDS.PACKET_HEADER_SIZE - headerBytesRead); if (bytesRead < 0) { if (logger.isLoggable(Level.FINER)) - logger.finer(toString() + " Premature EOS in response. packetNum:" + packetNum + " headerBytesRead:" + headerBytesRead); + logger.finer(toString() + " Premature EOS in response. packetNum:" + packetNum + " headerBytesRead:" + + headerBytesRead); - con.terminate(SQLServerException.DRIVER_ERROR_IO_FAILED, ((0 == packetNum && 0 == headerBytesRead) - ? SQLServerException.getErrString("R_noServerResponse") : SQLServerException.getErrString("R_truncatedServerResponse"))); + con.terminate(SQLServerException.DRIVER_ERROR_IO_FAILED, + ((0 == packetNum && 0 == headerBytesRead) ? SQLServerException.getErrString( + "R_noServerResponse") : SQLServerException.getErrString("R_truncatedServerResponse"))); } headerBytesRead += bytesRead; } - + // if execution was subject to timeout then stop timing if (null != tcpKeepAliveTimeoutTimer) { if (logger.isLoggable(Level.FINEST)) { @@ -6518,8 +6394,8 @@ synchronized final boolean readPacket() throws SQLServerException { // Make header size is properly bounded and compute length of the packet payload. if (packetLength < TDS.PACKET_HEADER_SIZE || packetLength > con.getTDSPacketSize()) { if (logger.isLoggable(Level.WARNING)) { - logger.warning( - toString() + " TDS header contained invalid packet length:" + packetLength + "; packet size:" + con.getTDSPacketSize()); + logger.warning(toString() + " TDS header contained invalid packet length:" + packetLength + + "; packet size:" + con.getTDSPacketSize()); } throwInvalidTDS(); } @@ -6539,9 +6415,11 @@ synchronized final boolean readPacket() throws SQLServerException { // Now for the payload... for (int payloadBytesRead = 0; payloadBytesRead < newPacket.payloadLength;) { - int bytesRead = tdsChannel.read(newPacket.payload, payloadBytesRead, newPacket.payloadLength - payloadBytesRead); + int bytesRead = tdsChannel.read(newPacket.payload, payloadBytesRead, + newPacket.payloadLength - payloadBytesRead); if (bytesRead < 0) - con.terminate(SQLServerException.DRIVER_ERROR_IO_FAILED, SQLServerException.getErrString("R_truncatedServerResponse")); + con.terminate(SQLServerException.DRIVER_ERROR_IO_FAILED, + SQLServerException.getErrString("R_truncatedServerResponse")); payloadBytesRead += bytesRead; } @@ -6595,8 +6473,8 @@ final void stream() { } /** - * Returns the number of bytes that can be read (or skipped over) from this TDSReader without blocking by the next caller of a method for this - * TDSReader. + * Returns the number of bytes that can be read (or skipped over) from this TDSReader without blocking by the next + * caller of a method for this TDSReader. * * @return the actual number of bytes available. */ @@ -6616,8 +6494,8 @@ final int available() { */ final int availableCurrentPacket() { /* - * The number of bytes that can be read from the current chunk, without including the next chunk that is buffered. This is so the driver can - * confirm if the next chunk sent is new packet or just continuation + * The number of bytes that can be read from the current chunk, without including the next chunk that is + * buffered. This is so the driver can confirm if the next chunk sent is new packet or just continuation */ int available = currentPacket.payloadLength - payloadOffset; return available; @@ -6716,9 +6594,7 @@ final long readLong() throws SQLServerException { return Util.readLong(readWrappedBytes(8), 0); } - final void readBytes(byte[] value, - int valueOffset, - int valueLength) throws SQLServerException { + final void readBytes(byte[] value, int valueOffset, int valueLength) throws SQLServerException { for (int bytesRead = 0; bytesRead < valueLength;) { // Ensure that we have a packet to read from. if (!ensurePayload()) @@ -6746,9 +6622,7 @@ final byte[] readWrappedBytes(int valueLength) throws SQLServerException { return valueBytes; } - final Object readDecimal(int valueLength, - TypeInfo typeInfo, - JDBCType jdbcType, + final Object readDecimal(int valueLength, TypeInfo typeInfo, JDBCType jdbcType, StreamType streamType) throws SQLServerException { if (valueLength > valueBytes.length) { if (logger.isLoggable(Level.WARNING)) { @@ -6758,12 +6632,11 @@ final Object readDecimal(int valueLength, } readBytes(valueBytes, 0, valueLength); - return DDC.convertBigDecimalToObject(Util.readBigDecimal(valueBytes, valueLength, typeInfo.getScale()), jdbcType, streamType); + return DDC.convertBigDecimalToObject(Util.readBigDecimal(valueBytes, valueLength, typeInfo.getScale()), + jdbcType, streamType); } - final Object readMoney(int valueLength, - JDBCType jdbcType, - StreamType streamType) throws SQLServerException { + final Object readMoney(int valueLength, JDBCType jdbcType, StreamType streamType) throws SQLServerException { BigInteger bi; switch (valueLength) { case 8: // money @@ -6800,27 +6673,21 @@ final Object readMoney(int valueLength, return DDC.convertBigDecimalToObject(new BigDecimal(bi, 4), jdbcType, streamType); } - final Object readReal(int valueLength, - JDBCType jdbcType, - StreamType streamType) throws SQLServerException { + final Object readReal(int valueLength, JDBCType jdbcType, StreamType streamType) throws SQLServerException { if (4 != valueLength) throwInvalidTDS(); return DDC.convertFloatToObject(Float.intBitsToFloat(readInt()), jdbcType, streamType); } - final Object readFloat(int valueLength, - JDBCType jdbcType, - StreamType streamType) throws SQLServerException { + final Object readFloat(int valueLength, JDBCType jdbcType, StreamType streamType) throws SQLServerException { if (8 != valueLength) throwInvalidTDS(); return DDC.convertDoubleToObject(Double.longBitsToDouble(readLong()), jdbcType, streamType); } - final Object readDateTime(int valueLength, - Calendar appTimeZoneCalendar, - JDBCType jdbcType, + final Object readDateTime(int valueLength, Calendar appTimeZoneCalendar, JDBCType jdbcType, StreamType streamType) throws SQLServerException { // Build and return the right kind of temporal object. int daysSinceSQLBaseDate; @@ -6843,7 +6710,8 @@ final Object readDateTime(int valueLength, return value; } - msecSinceMidnight = (ticksSinceMidnight * 10 + 1) / 3; // Convert to msec (1 tick = 1 300th of a sec = 3 msec) + msecSinceMidnight = (ticksSinceMidnight * 10 + 1) / 3; // Convert to msec (1 tick = 1 300th of a sec = 3 + // msec) break; case 4: @@ -6869,17 +6737,16 @@ final Object readDateTime(int valueLength, } // Convert the DATETIME/SMALLDATETIME value to the desired Java type. - return DDC.convertTemporalToObject(jdbcType, SSType.DATETIME, appTimeZoneCalendar, daysSinceSQLBaseDate, msecSinceMidnight, 0); // scale - // (ignored - // for - // fixed-scale - // DATETIME/SMALLDATETIME - // types) + return DDC.convertTemporalToObject(jdbcType, SSType.DATETIME, appTimeZoneCalendar, daysSinceSQLBaseDate, + msecSinceMidnight, 0); // scale + // (ignored + // for + // fixed-scale + // DATETIME/SMALLDATETIME + // types) } - final Object readDate(int valueLength, - Calendar appTimeZoneCalendar, - JDBCType jdbcType) throws SQLServerException { + final Object readDate(int valueLength, Calendar appTimeZoneCalendar, JDBCType jdbcType) throws SQLServerException { if (TDS.DAYS_INTO_CE_LENGTH != valueLength) throwInvalidTDS(); @@ -6887,13 +6754,14 @@ final Object readDate(int valueLength, int localDaysIntoCE = readDaysIntoCE(); // Convert the DATE value to the desired Java type. - return DDC.convertTemporalToObject(jdbcType, SSType.DATE, appTimeZoneCalendar, localDaysIntoCE, 0, // midnight local to app time zone + return DDC.convertTemporalToObject(jdbcType, SSType.DATE, appTimeZoneCalendar, localDaysIntoCE, 0, // midnight + // local to + // app time + // zone 0); // scale (ignored for DATE) } - final Object readTime(int valueLength, - TypeInfo typeInfo, - Calendar appTimeZoneCalendar, + final Object readTime(int valueLength, TypeInfo typeInfo, Calendar appTimeZoneCalendar, JDBCType jdbcType) throws SQLServerException { if (TDS.timeValueLength(typeInfo.getScale()) != valueLength) throwInvalidTDS(); @@ -6902,12 +6770,11 @@ final Object readTime(int valueLength, long localNanosSinceMidnight = readNanosSinceMidnight(typeInfo.getScale()); // Convert the TIME value to the desired Java type. - return DDC.convertTemporalToObject(jdbcType, SSType.TIME, appTimeZoneCalendar, 0, localNanosSinceMidnight, typeInfo.getScale()); + return DDC.convertTemporalToObject(jdbcType, SSType.TIME, appTimeZoneCalendar, 0, localNanosSinceMidnight, + typeInfo.getScale()); } - final Object readDateTime2(int valueLength, - TypeInfo typeInfo, - Calendar appTimeZoneCalendar, + final Object readDateTime2(int valueLength, TypeInfo typeInfo, Calendar appTimeZoneCalendar, JDBCType jdbcType) throws SQLServerException { if (TDS.datetime2ValueLength(typeInfo.getScale()) != valueLength) throwInvalidTDS(); @@ -6917,13 +6784,11 @@ final Object readDateTime2(int valueLength, int localDaysIntoCE = readDaysIntoCE(); // Convert the DATETIME2 value to the desired Java type. - return DDC.convertTemporalToObject(jdbcType, SSType.DATETIME2, appTimeZoneCalendar, localDaysIntoCE, localNanosSinceMidnight, - typeInfo.getScale()); + return DDC.convertTemporalToObject(jdbcType, SSType.DATETIME2, appTimeZoneCalendar, localDaysIntoCE, + localNanosSinceMidnight, typeInfo.getScale()); } - final Object readDateTimeOffset(int valueLength, - TypeInfo typeInfo, - JDBCType jdbcType) throws SQLServerException { + final Object readDateTimeOffset(int valueLength, TypeInfo typeInfo, JDBCType jdbcType) throws SQLServerException { if (TDS.datetimeoffsetValueLength(typeInfo.getScale()) != valueLength) throwInvalidTDS(); @@ -6935,8 +6800,8 @@ final Object readDateTimeOffset(int valueLength, // Convert the DATETIMEOFFSET value to the desired Java type. return DDC.convertTemporalToObject(jdbcType, SSType.DATETIMEOFFSET, - new GregorianCalendar(new SimpleTimeZone(localMinutesOffset * 60 * 1000, ""), Locale.US), utcDaysIntoCE, utcNanosSinceMidnight, - typeInfo.getScale()); + new GregorianCalendar(new SimpleTimeZone(localMinutesOffset * 60 * 1000, ""), Locale.US), utcDaysIntoCE, + utcNanosSinceMidnight, typeInfo.getScale()); } private int readDaysIntoCE() throws SQLServerException { @@ -6979,9 +6844,7 @@ private long readNanosSinceMidnight(int scale) throws SQLServerException { final static String guidTemplate = "NNNNNNNN-NNNN-NNNN-NNNN-NNNNNNNNNNNN"; - final Object readGUID(int valueLength, - JDBCType jdbcType, - StreamType streamType) throws SQLServerException { + final Object readGUID(int valueLength, JDBCType jdbcType, StreamType streamType) throws SQLServerException { // GUIDs must be exactly 16 bytes if (16 != valueLength) throwInvalidTDS(); @@ -7023,8 +6886,7 @@ final Object readGUID(int valueLength, try { return DDC.convertStringToObject(sb.toString(), Encoding.UNICODE.charset(), jdbcType, streamType); - } - catch (UnsupportedEncodingException e) { + } catch (UnsupportedEncodingException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_errorConvertingValue")); throw new SQLServerException(form.format(new Object[] {"UNIQUEIDENTIFIER", jdbcType}), null, 0, e); } @@ -7071,8 +6933,7 @@ final SQLCollation readCollation() throws SQLServerException { try { collation = new SQLCollation(this); - } - catch (UnsupportedEncodingException e) { + } catch (UnsupportedEncodingException e) { con.terminate(SQLServerException.DRIVER_ERROR_INVALID_TDS, e.getMessage(), e); // not reached } @@ -7104,7 +6965,8 @@ final void tryProcessFeatureExtAck(boolean featureExtAckReceived) throws SQLServ } if (isColumnEncryptionSettingEnabled() && !featureExtAckReceived) - throw new SQLServerException(this, SQLServerException.getErrString("R_AE_NotSupportedByServer"), null, 0, false); + throw new SQLServerException(this, SQLServerException.getErrString("R_AE_NotSupportedByServer"), null, 0, + false); } final void trySetSensitivityClassification(SensitivityClassification sensitivityClassification) { @@ -7112,11 +6974,12 @@ final void trySetSensitivityClassification(SensitivityClassification sensitivity } } + /** * Timer for use with Commands that support a timeout. * - * Once started, the timer runs for the prescribed number of seconds unless stopped. If the timer runs out, it interrupts its associated Command with - * a reason like "timed out". + * Once started, the timer runs for the prescribed number of seconds unless stopped. If the timer runs out, it + * interrupts its associated Command with a reason like "timed out". */ final class TimeoutTimer implements Runnable { private static final String threadGroupName = "mssql-jdbc-TimeoutTimer"; @@ -7124,18 +6987,16 @@ final class TimeoutTimer implements Runnable { private final TDSCommand command; private volatile Future task; private final SQLServerConnection con; - + private static final ExecutorService executor = Executors.newCachedThreadPool(new ThreadFactory() { private final AtomicReference tgr = new AtomicReference<>(); private final AtomicInteger threadNumber = new AtomicInteger(0); @Override - public Thread newThread(Runnable r) - { + public Thread newThread(Runnable r) { ThreadGroup tg = tgr.get(); - if (tg == null || tg.isDestroyed()) - { + if (tg == null || tg.isDestroyed()) { tg = new ThreadGroup(threadGroupName); tgr.set(tg); } @@ -7148,9 +7009,7 @@ public Thread newThread(Runnable r) private volatile boolean canceled = false; - TimeoutTimer(int timeoutSeconds, - TDSCommand command, - SQLServerConnection con) { + TimeoutTimer(int timeoutSeconds, TDSCommand command, SQLServerConnection con) { assert timeoutSeconds > 0; this.timeoutSeconds = timeoutSeconds; @@ -7177,10 +7036,8 @@ public void run() { return; Thread.sleep(1000); - } - while (--secondsRemaining > 0); - } - catch (InterruptedException e) { + } while (--secondsRemaining > 0); + } catch (InterruptedException e) { // re-interrupt the current thread, in order to restore the thread's interrupt status. Thread.currentThread().interrupt(); return; @@ -7189,18 +7046,19 @@ public void run() { // If the timer wasn't canceled before it ran out of // time then interrupt the registered command. try { - // If TCP Connection to server is silently dropped, exceeding the query timeout on the same connection does not throw SQLTimeoutException - // The application stops responding instead until SocketTimeoutException is thrown. In this case, we must manually terminate the connection. + // If TCP Connection to server is silently dropped, exceeding the query timeout on the same connection does + // not throw SQLTimeoutException + // The application stops responding instead until SocketTimeoutException is thrown. In this case, we must + // manually terminate the connection. if (null == command && null != con) { - con.terminate(SQLServerException.DRIVER_ERROR_IO_FAILED, SQLServerException.getErrString("R_connectionIsClosed")); - } - else { + con.terminate(SQLServerException.DRIVER_ERROR_IO_FAILED, + SQLServerException.getErrString("R_connectionIsClosed")); + } else { // If the timer wasn't canceled before it ran out of // time then interrupt the registered command. command.interrupt(SQLServerException.getErrString("R_queryTimedOut")); } - } - catch (SQLServerException e) { + } catch (SQLServerException e) { // Unfortunately, there's nothing we can do if we // fail to time out the request. There is no way // to report back what happened. @@ -7210,14 +7068,17 @@ public void run() { } } + /** * TDSCommand encapsulates an interruptable TDS conversation. * - * A conversation may consist of one or more TDS request and response messages. A command may be interrupted at any point, from any thread, and for - * any reason. Acknowledgement and handling of an interrupt is fully encapsulated by this class. + * A conversation may consist of one or more TDS request and response messages. A command may be interrupted at any + * point, from any thread, and for any reason. Acknowledgement and handling of an interrupt is fully encapsulated by + * this class. * - * Commands may be created with an optional timeout (in seconds). Timeouts are implemented as a form of interrupt, where the interrupt event occurs - * when the timeout period expires. Currently, only the time to receive the response from the channel counts against the timeout period. + * Commands may be created with an optional timeout (in seconds). Timeouts are implemented as a form of interrupt, where + * the interrupt event occurs when the timeout period expires. Currently, only the time to receive the response from the + * channel counts against the timeout period. */ abstract class TDSCommand { abstract boolean doExecute() throws SQLServerException; @@ -7237,8 +7098,7 @@ final public String toString() { return traceID; } - final void log(Level level, - String message) { + final void log(Level level, String message) { logger.log(level, toString() + ": " + message); } @@ -7251,8 +7111,8 @@ final void log(Level level, // Volatile ensures visibility to execution thread and interrupt thread private volatile TDSWriter tdsWriter; private volatile TDSReader tdsReader; - - protected TDSWriter getTDSWriter(){ + + protected TDSWriter getTDSWriter() { return tdsWriter; } @@ -7332,17 +7192,17 @@ protected void setProcessedResponse(boolean processedResponse) { // any attention ack. The command's response is read either on demand as it is processed, // or by detaching. private volatile boolean readingResponse; - private int queryTimeoutSeconds; - private int cancelQueryTimeoutSeconds; + private int queryTimeoutSeconds; + private int cancelQueryTimeoutSeconds; protected int getQueryTimeoutSeconds() { - return this.queryTimeoutSeconds; + return this.queryTimeoutSeconds; } protected int getCancelQueryTimeoutSeconds() { - return this.cancelQueryTimeoutSeconds; + return this.cancelQueryTimeoutSeconds; } - + final boolean readingResponse() { return readingResponse; } @@ -7351,12 +7211,12 @@ final boolean readingResponse() { * Creates this command with an optional timeout. * * @param logContext - * the string describing the context for this command. + * the string describing the context for this command. * @param timeoutSeconds - * (optional) the time before which the command must complete before it is interrupted. A value of 0 means no timeout. + * (optional) the time before which the command must complete before it is interrupted. A value of 0 means no + * timeout. */ - TDSCommand(String logContext, - int queryTimeoutSeconds, int cancelQueryTimeoutSeconds) { + TDSCommand(String logContext, int queryTimeoutSeconds, int cancelQueryTimeoutSeconds) { this.logContext = logContext; this.queryTimeoutSeconds = queryTimeoutSeconds; this.cancelQueryTimeoutSeconds = cancelQueryTimeoutSeconds; @@ -7369,18 +7229,16 @@ final boolean readingResponse() { * @param tdsWriter * @param tdsReader * @throws SQLServerException - * on any error executing the command, including cancel or timeout. + * on any error executing the command, including cancel or timeout. */ - boolean execute(TDSWriter tdsWriter, - TDSReader tdsReader) throws SQLServerException { + boolean execute(TDSWriter tdsWriter, TDSReader tdsReader) throws SQLServerException { this.tdsWriter = tdsWriter; this.tdsReader = tdsReader; assert null != tdsReader; try { return doExecute(); // Derived classes implement the execution details - } - catch (SQLServerException e) { + } catch (SQLServerException e) { try { // If command execution threw an exception for any reason before the request // was complete then interrupt the command (it may already be interrupted) @@ -7392,10 +7250,10 @@ boolean execute(TDSWriter tdsWriter, onRequestComplete(); close(); } - } - catch (SQLServerException interruptException) { + } catch (SQLServerException interruptException) { if (logger.isLoggable(Level.FINE)) - logger.fine(this.toString() + ": Ignoring error in sending attention: " + interruptException.getMessage()); + logger.fine(this.toString() + ": Ignoring error in sending attention: " + + interruptException.getMessage()); } // throw the original exception even if trying to interrupt fails even in the case // of trying to send a cancel to the server. @@ -7413,8 +7271,7 @@ void processResponse(TDSReader tdsReader) throws SQLServerException { logger.finest(this.toString() + ": Processing response"); try { TDSParser.parse(tdsReader, getLogContext()); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { if (SQLServerException.DRIVER_ERROR_FROM_DATABASE != e.getDriverErrorCode()) throw e; @@ -7426,7 +7283,8 @@ void processResponse(TDSReader tdsReader) throws SQLServerException { /** * Clears this command from the TDS channel so that another command can execute. * - * This method does not process the response. It just buffers it in memory, including any attention ack that may be present. + * This method does not process the response. It just buffers it in memory, including any attention ack that may be + * present. */ final void detach() throws SQLServerException { if (logger.isLoggable(Level.FINEST)) @@ -7434,8 +7292,7 @@ final void detach() throws SQLServerException { // Read any remaining response packets from the server. // This operation may be timed out or cancelled from another thread. - while (tdsReader.readPacket()) - ; + while (tdsReader.readPacket()); // Postcondition: the entire response has been read assert !readingResponse; @@ -7451,8 +7308,7 @@ final void close() { while (!processedResponse) { try { processResponse(tdsReader); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { if (logger.isLoggable(Level.FINEST)) logger.finest(this + ": close ignoring error processing response: " + e.getMessage()); @@ -7469,14 +7325,12 @@ final void close() { try { TDSParser.parse(tdsReader, "attention ack"); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { if (tdsReader.getConnection().isSessionUnAvailable()) { if (logger.isLoggable(Level.FINEST)) logger.finest(this + ": giving up on attention ack after connection closed by exception: " + e); attentionPending = false; - } - else { + } else { if (logger.isLoggable(Level.FINEST)) logger.finest(this + ": ignored exception: " + e); } @@ -7487,13 +7341,13 @@ final void close() { // terminate the connection to prevent any other command from executing. if (attentionPending) { if (logger.isLoggable(Level.SEVERE)) { - logger.severe(this.toString() + ": expected attn ack missing or not processed; terminating connection..."); + logger.severe(this.toString() + + ": expected attn ack missing or not processed; terminating connection..."); } try { tdsReader.throwInvalidTDS(); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { if (logger.isLoggable(Level.FINEST)) logger.finest(this + ": ignored expected invalid TDS exception: " + e); @@ -7512,16 +7366,17 @@ final void close() { /** * Interrupts execution of this command, typically from another thread. * - * Only the first interrupt has any effect. Subsequent interrupts are ignored. Interrupts are also ignored until enabled. If interrupting the - * command requires an attention signal to be sent to the server, then this method sends that signal if the command's request is already complete. + * Only the first interrupt has any effect. Subsequent interrupts are ignored. Interrupts are also ignored until + * enabled. If interrupting the command requires an attention signal to be sent to the server, then this method + * sends that signal if the command's request is already complete. * - * Signalling mechanism is "fire and forget". It is up to either the execution thread or, possibly, a detaching thread, to ensure that any pending - * attention ack later will be received and processed. + * Signalling mechanism is "fire and forget". It is up to either the execution thread or, possibly, a detaching + * thread, to ensure that any pending attention ack later will be received and processed. * * @param reason - * the reason for the interrupt, typically cancel or timeout. + * the reason for the interrupt, typically cancel or timeout. * @throws SQLServerException - * if interrupting fails for some reason. This call does not throw the reason for the interrupt. + * if interrupting fails for some reason. This call does not throw the reason for the interrupt. */ void interrupt(String reason) throws SQLServerException { // Multiple, possibly simultaneous, interrupts may occur. @@ -7545,17 +7400,18 @@ void interrupt(String reason) throws SQLServerException { /** * Checks once whether an interrupt has occurred, and, if it has, throws an exception indicating that fact. * - * Any calls after the first to check for interrupts are no-ops. This method is called periodically from this command's execution thread to notify - * the app when an interrupt has happened. + * Any calls after the first to check for interrupts are no-ops. This method is called periodically from this + * command's execution thread to notify the app when an interrupt has happened. * - * It should only be called from places where consistent behavior can be ensured after the exception is thrown. For example, it should not be - * called at arbitrary times while processing the response, as doing so could leave the response token stream in an inconsistent state. Currently, - * response processing only checks for interrupts after every result or OUT parameter. + * It should only be called from places where consistent behavior can be ensured after the exception is thrown. For + * example, it should not be called at arbitrary times while processing the response, as doing so could leave the + * response token stream in an inconsistent state. Currently, response processing only checks for interrupts after + * every result or OUT parameter. * * Request processing checks for interrupts before writing each packet. * * @throws SQLServerException - * if this command was interrupted, throws the reason for the interrupt. + * if this command was interrupted, throws the reason for the interrupt. */ final void checkForInterrupt() throws SQLServerException { // Throw an exception with the interrupt reason if this command was interrupted. @@ -7576,17 +7432,18 @@ final void checkForInterrupt() throws SQLServerException { /** * Notifies this command when no more request packets are to be sent to the server. * - * After the last packet has been sent, the only way to interrupt the request is to send an attention signal from the interrupt() method. + * After the last packet has been sent, the only way to interrupt the request is to send an attention signal from + * the interrupt() method. * - * Note that this method is called when the request completes normally (last packet sent with EOM bit) or when it completes after being - * interrupted (0 or more packets sent with no EOM bit). + * Note that this method is called when the request completes normally (last packet sent with EOM bit) or when it + * completes after being interrupted (0 or more packets sent with no EOM bit). */ final void onRequestComplete() throws SQLServerException { synchronized (interruptLock) { - assert !requestComplete; - - if (logger.isLoggable(Level.FINEST)) - logger.finest(this + ": request complete"); + assert !requestComplete; + + if (logger.isLoggable(Level.FINEST)) + logger.finest(this + ": request complete"); requestComplete = true; @@ -7600,21 +7457,18 @@ final void onRequestComplete() throws SQLServerException { assert !processedResponse; assert !readingResponse; processedResponse = true; - } - else if (wasInterrupted()) { + } else if (wasInterrupted()) { if (tdsWriter.isEOMSent()) { attentionPending = tdsWriter.sendAttention(); readingResponse = attentionPending; - } - else { + } else { assert !attentionPending; readingResponse = tdsWriter.ignoreMessage(); } processedResponse = !readingResponse; - } - else { + } else { assert !attentionPending; assert !processedResponse; readingResponse = true; @@ -7625,13 +7479,13 @@ else if (wasInterrupted()) { /** * Notifies this command when the last packet of the response has been read. * - * When the last packet is read, interrupts are disabled. If an interrupt occurred prior to disabling that caused an attention signal to be sent - * to the server, then an extra packet containing the attention ack is read. + * When the last packet is read, interrupts are disabled. If an interrupt occurred prior to disabling that caused an + * attention signal to be sent to the server, then an extra packet containing the attention ack is read. * * This ensures that on return from this method, the TDS channel is clear of all response packets for this command. * - * Note that this method is called for the attention ack message itself as well, so we need to be sure not to expect more than one attention - * ack... + * Note that this method is called for the attention ack message itself as well, so we need to be sure not to expect + * more than one attention ack... */ final void onResponseEOM() throws SQLServerException { boolean readAttentionAck = false; @@ -7690,10 +7544,10 @@ final void onAttentionAck() { * Starts sending this command's TDS request to the server. * * @param tdsMessageType - * the type of the TDS message (RPC, QUERY, etc.) + * the type of the TDS message (RPC, QUERY, etc.) * @return the TDS writer used to write the request. * @throws SQLServerException - * on any error, including acknowledgement of an interrupt. + * on any error, including acknowledgement of an interrupt. */ final TDSWriter startRequest(byte tdsMessageType) throws SQLServerException { if (logger.isLoggable(Level.FINEST)) @@ -7702,8 +7556,7 @@ final TDSWriter startRequest(byte tdsMessageType) throws SQLServerException { // Start this command's request message try { tdsWriter.startMessage(this, tdsMessageType); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { if (logger.isLoggable(Level.FINEST)) logger.finest(this + ": starting request: exception: " + e.getMessage()); @@ -7731,7 +7584,7 @@ final TDSWriter startRequest(byte tdsMessageType) throws SQLServerException { * * @return the TDS reader used to read the response. * @throws SQLServerException - * if there is any kind of error. + * if there is any kind of error. */ final TDSReader startResponse() throws SQLServerException { return startResponse(false); @@ -7747,8 +7600,7 @@ final TDSReader startResponse(boolean isAdaptive) throws SQLServerException { try { tdsWriter.endMessage(); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { if (logger.isLoggable(Level.FINEST)) logger.finest(this + ": finishing request: endMessage threw exception: " + e.getMessage()); @@ -7773,19 +7625,15 @@ final TDSReader startResponse(boolean isAdaptive) throws SQLServerException { // of the response. if (isAdaptive) { tdsReader.readPacket(); + } else { + while (tdsReader.readPacket()); } - else { - while (tdsReader.readPacket()) - ; - } - } - catch (SQLServerException e) { + } catch (SQLServerException e) { if (logger.isLoggable(Level.FINEST)) logger.finest(this.toString() + ": Exception reading response: " + e.getMessage()); throw e; - } - finally { + } finally { // If command execution was subject to timeout then stop timing as soon // as the server returns the first response packet or errors out. if (null != timeoutTimer) { @@ -7800,11 +7648,13 @@ final TDSReader startResponse(boolean isAdaptive) throws SQLServerException { } } + /** * UninterruptableTDSCommand encapsulates an uninterruptable TDS conversation. * - * TDSCommands have interruptability built in. However, some TDSCommands such as DTC commands, connection commands, cursor close and prepared - * statement handle close shouldn't be interruptable. This class provides a base implementation for such commands. + * TDSCommands have interruptability built in. However, some TDSCommands such as DTC commands, connection commands, + * cursor close and prepared statement handle close shouldn't be interruptable. This class provides a base + * implementation for such commands. */ abstract class UninterruptableTDSCommand extends TDSCommand { UninterruptableTDSCommand(String logContext) { diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerBulkRecord.java b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerBulkRecord.java index 0bf41d944..1f347cac9 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerBulkRecord.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerBulkRecord.java @@ -1,84 +1,82 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; import java.time.format.DateTimeFormatter; + /** - * The ISQLServerBulkRecord interface can be used to create classes that read in data from any source (such as a file) and allow a SQLServerBulkCopy - * class to write the data to SQL Server tables. + * Provides an interface used to create classes that read in data from any source (such as a file) and allows a + * SQLServerBulkCopy class to write the data to SQL Server tables. * * This interface is implemented by {@link SQLServerBulkCommon} Class */ public interface ISQLServerBulkRecord { /** - * Get the ordinals for each of the columns represented in this data record. + * Returns the ordinals for each of the columns represented in this data record. * * @return Set of ordinals for the columns. */ public java.util.Set getColumnOrdinals(); /** - * Get the name of the given column. + * Returns the name of the given column. * * @param column - * Column ordinal + * Column ordinal * @return Name of the column */ public String getColumnName(int column); /** - * Get the JDBC data type of the given column. + * Returns the JDBC data type of the given column. * * @param column - * Column ordinal + * Column ordinal * @return JDBC data type of the column */ public int getColumnType(int column); /** - * Get the precision for the given column. + * Returns the precision for the given column. * * @param column - * Column ordinal + * Column ordinal * @return Precision of the column */ public int getPrecision(int column); /** - * Get the scale for the given column. + * Returns the scale for the given column. * * @param column - * Column ordinal + * Column ordinal * @return Scale of the column */ public int getScale(int column); /** - * Indicates whether the column represents an identity column. + * Returns whether the column represents an identity column. * * @param column - * Column ordinal + * Column ordinal * @return True if the column is an identity column; false otherwise. */ public boolean isAutoIncrement(int column); /** - * Gets the data for the current row as an array of Objects. + * Returns the data for the current row as an array of Objects. * - * Each Object must match the Java language Type that is used to represent the indicated JDBC data type for the given column. For more - * information, see 'Understanding the JDBC Driver Data Types' for the appropriate mappings. + * Each Object must match the Java language Type that is used to represent the indicated JDBC data type for the + * given column. For more information, see 'Understanding the JDBC Driver Data Types' for the appropriate mappings. * * @return The data for the row. * @throws SQLServerException - * If there are any errors in obtaining the data. + * If there are any errors in obtaining the data. */ public Object[] getRowData() throws SQLServerException; @@ -87,7 +85,7 @@ public interface ISQLServerBulkRecord { * * @return True if rows are available; false if there are no more rows * @throws SQLServerException - * If there are any errors in advancing to the next row. + * If there are any errors in advancing to the next row. */ public boolean next() throws SQLServerException; @@ -95,86 +93,79 @@ public interface ISQLServerBulkRecord { * Adds metadata for the given column in the file. * * @param positionInFile - * Indicates which column the metadata is for. Columns start at 1. + * Indicates which column the metadata is for. Columns start at 1. * @param name - * Name for the column (optional if only using column ordinal in a mapping for SQLServerBulkCopy operation) + * Name for the column (optional if only using column ordinal in a mapping for SQLServerBulkCopy operation) * @param jdbcType - * JDBC data type of the column + * JDBC data type of the column * @param precision - * Precision for the column (ignored for the appropriate data types) + * Precision for the column (ignored for the appropriate data types) * @param scale - * Scale for the column (ignored for the appropriate data types) + * Scale for the column (ignored for the appropriate data types) * @param dateTimeFormatter - * format to parse data that is sent + * format to parse data that is sent * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void addColumnMetadata(int positionInFile, - String name, - int jdbcType, - int precision, - int scale, + public void addColumnMetadata(int positionInFile, String name, int jdbcType, int precision, int scale, DateTimeFormatter dateTimeFormatter) throws SQLServerException; /** * Adds metadata for the given column in the file. * * @param positionInFile - * Indicates which column the metadata is for. Columns start at 1. + * Indicates which column the metadata is for. Columns start at 1. * @param name - * Name for the column (optional if only using column ordinal in a mapping for SQLServerBulkCopy operation) + * Name for the column (optional if only using column ordinal in a mapping for SQLServerBulkCopy operation) * @param jdbcType - * JDBC data type of the column + * JDBC data type of the column * @param precision - * Precision for the column (ignored for the appropriate data types) + * Precision for the column (ignored for the appropriate data types) * @param scale - * Scale for the column (ignored for the appropriate data types) + * Scale for the column (ignored for the appropriate data types) * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void addColumnMetadata(int positionInFile, - String name, - int jdbcType, - int precision, + public void addColumnMetadata(int positionInFile, String name, int jdbcType, int precision, int scale) throws SQLServerException; /** - * Set the format for reading in dates from the file. + * Sets the format for reading in dates from the file. * * @param dateTimeFormat - * format to parse data sent as java.sql.Types.TIMESTAMP_WITH_TIMEZONE + * format to parse data sent as java.sql.Types.TIMESTAMP_WITH_TIMEZONE */ public void setTimestampWithTimezoneFormat(String dateTimeFormat); /** - * Set the format for reading in dates from the file. + * Sets the format for reading in dates from the file. * * @param dateTimeFormatter - * format to parse data sent as java.sql.Types.TIMESTAMP_WITH_TIMEZONE + * format to parse data sent as java.sql.Types.TIMESTAMP_WITH_TIMEZONE */ public void setTimestampWithTimezoneFormat(DateTimeFormatter dateTimeFormatter); /** - * Set the format for reading in dates from the file. + * Sets the format for reading in dates from the file. * * @param timeFormat - * format to parse data sent as java.sql.Types.TIME_WITH_TIMEZONE + * format to parse data sent as java.sql.Types.TIME_WITH_TIMEZONE */ public void setTimeWithTimezoneFormat(String timeFormat); /** - * Set the format for reading in dates from the file. + * Sets the format for reading in dates from the file. * * @param dateTimeFormatter - * format to parse data sent as java.sql.Types.TIME_WITH_TIMEZONE + * format to parse data sent as java.sql.Types.TIME_WITH_TIMEZONE */ public void setTimeWithTimezoneFormat(DateTimeFormatter dateTimeFormatter); /** - * Retreives dateTimeFormatter for the given column + * Returns the dateTimeFormatter for the given column. * * @param column - * Column ordinal + * Column ordinal * @return dateTimeFormatter */ public DateTimeFormatter getColumnDateTimeFormatter(int column); diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerCallableStatement.java b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerCallableStatement.java index 7be9957b3..da7d75fde 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerCallableStatement.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerCallableStatement.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -13,365 +10,362 @@ import java.sql.Timestamp; import java.util.Calendar; + /** - * This interface is implemented by {@link SQLServerCallableStatement} Class. + * Provides an interface to the {@link SQLServerCallableStatement} class. */ public interface ISQLServerCallableStatement extends java.sql.CallableStatement, ISQLServerPreparedStatement { @Deprecated - public BigDecimal getBigDecimal(String parameterName, - int scale) throws SQLServerException; + public BigDecimal getBigDecimal(String parameterName, int scale) throws SQLServerException; /** - * Retrieves the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp object in the Java programming - * language. + * Returns the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp + * object in the Java programming language. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @return the column value; if the value is SQL NULL, the value returned is null * @throws SQLServerException - * when an error occurs + * when an error occurs */ public Timestamp getDateTime(int index) throws SQLServerException; /** - * Retrieves the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp object in the Java programming - * language. + * Returns the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp + * object in the Java programming language. * * @param parameterName - * the label for the column specified with the SQL AS clause. If the SQL AS clause was not specified, then the label is the name of the - * column + * the label for the column specified with the SQL AS clause. If the SQL AS clause was not specified, then + * the label is the name of the column * @return the column value; if the value is SQL NULL, the value returned is null * @throws SQLServerException - * when an error occurs + * when an error occurs */ public Timestamp getDateTime(String parameterName) throws SQLServerException; /** - * Retrieves the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp object in the Java programming - * language. This method uses the given calendar to construct an appropriate millisecond value for the timestamp if the underlying database does - * not store timezone information. + * Returns the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp + * object in the Java programming language. This method uses the given calendar to construct an appropriate + * millisecond value for the timestamp if the underlying database does not store timezone information. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param cal - * the java.util.Calendar object to use in constructing the dateTime + * the java.util.Calendar object to use in constructing the dateTime * @return the column value; if the value is SQL NULL, the value returned is null * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public Timestamp getDateTime(int index, - Calendar cal) throws SQLServerException; + public Timestamp getDateTime(int index, Calendar cal) throws SQLServerException; /** - * Retrieves the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp object in the Java programming - * language. This method uses the given calendar to construct an appropriate millisecond value for the timestamp if the underlying database does - * not store timezone information. + * Returns the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp + * object in the Java programming language. This method uses the given calendar to construct an appropriate + * millisecond value for the timestamp if the underlying database does not store timezone information. * * @param name - * the name of the column + * the name of the column * @param cal - * the java.util.Calendar object to use in constructing the dateTime + * the java.util.Calendar object to use in constructing the dateTime * @return the column value; if the value is SQL NULL, the value returned is null * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public Timestamp getDateTime(String name, - Calendar cal) throws SQLServerException; + public Timestamp getDateTime(String name, Calendar cal) throws SQLServerException; /** - * Retrieves the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp object in the Java programming - * language. + * Returns the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp + * object in the Java programming language. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @return the column value; if the value is SQL NULL, the value returned is null * @throws SQLServerException - * when an error occurs + * when an error occurs */ public Timestamp getSmallDateTime(int index) throws SQLServerException; /** - * Retrieves the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp object in the Java programming - * language. + * Returns the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp + * object in the Java programming language. * * @param parameterName - * The name of a column. + * The name of a column. * @return the column value; if the value is SQL NULL, the value returned is null * @throws SQLServerException - * when an error occurs + * when an error occurs */ public Timestamp getSmallDateTime(String parameterName) throws SQLServerException; /** - * Retrieves the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp object in the Java programming - * language. + * Returns the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp + * object in the Java programming language. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param cal - * the java.util.Calendar object to use in constructing the smalldateTime + * the java.util.Calendar object to use in constructing the smalldateTime * @return the column value; if the value is SQL NULL, the value returned is null * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public Timestamp getSmallDateTime(int index, - Calendar cal) throws SQLServerException; + public Timestamp getSmallDateTime(int index, Calendar cal) throws SQLServerException; /** - * Retrieves the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp object in the Java programming - * language. + * Returns the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp + * object in the Java programming language. * * @param name - * The name of a column + * The name of a column * @param cal - * the java.util.Calendar object to use in constructing the smalldateTime + * the java.util.Calendar object to use in constructing the smalldateTime * @return the column value; if the value is SQL NULL, the value returned is null * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public Timestamp getSmallDateTime(String name, - Calendar cal) throws SQLServerException; + public Timestamp getSmallDateTime(String name, Calendar cal) throws SQLServerException; /** - * Gets the DateTimeOffset value of parameter with index parameterIndex + * Returns the DateTimeOffset value of parameter with index parameterIndex. * * @param parameterIndex - * the first parameter is 1, the second is 2, and so on + * the first parameter is 1, the second is 2, and so on * @return DateTimeOffset value if the value is SQL NULL, the value returned is null * @throws SQLServerException - * if parameterIndex is out of range; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterIndex is out of range; if a database access error occurs or this method is called on a closed + * CallableStatement */ public microsoft.sql.DateTimeOffset getDateTimeOffset(int parameterIndex) throws SQLServerException; /** - * Gets the DateTimeOffset value of parameter with name parameterName + * Returns the DateTimeOffset value of parameter with name parameterName. * * @param parameterName - * the name of the parameter + * the name of the parameter * @return DateTimeOffset value if the value is SQL NULL, the value returned is null * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement */ public microsoft.sql.DateTimeOffset getDateTimeOffset(String parameterName) throws SQLServerException; /** - * Retrieves the value of the designated column in the current row of this ResultSet object as a stream of ASCII characters. The - * value can then be read in chunks from the stream. This method is particularly suitable for retrieving large LONGVARCHAR values. - * The JDBC driver will do any necessary conversion from the database format into ASCII. + * Returns the value of the designated column in the current row of this ResultSet object as a stream + * of ASCII characters. The value can then be read in chunks from the stream. This method is particularly suitable + * for retrieving large LONGVARCHAR values. The JDBC driver will do any necessary conversion from the + * database format into ASCII. * *

- * Note: All the data in the returned stream must be read prior to getting the value of any other column. The next call to a getter method - * implicitly closes the stream. Also, a stream may return 0 when the method InputStream.available is called whether - * there is data available or not. + * Note: All the data in the returned stream must be read prior to getting the value of any other column. The + * next call to a getter method implicitly closes the stream. Also, a stream may return 0 when the + * method InputStream.available is called whether there is data available or not. * * @param parameterIndex - * the first column is 1, the second is 2, ... - * @return a Java input stream that delivers the database column value as a stream of one-byte ASCII characters; if the value is SQL - * NULL, the value returned is null + * the first column is 1, the second is 2, ... + * @return a Java input stream that delivers the database column value as a stream of one-byte ASCII characters; if + * the value is SQL NULL, the value returned is null * @throws SQLServerException - * if the columnIndex is not valid; if a database access error occurs or this method is called on a closed result set + * if the columnIndex is not valid; if a database access error occurs or this method is called on a closed + * result set */ public java.io.InputStream getAsciiStream(int parameterIndex) throws SQLServerException; /** - * Retrieves the value of the designated column in the current row of this ResultSet object as a stream of ASCII characters. The - * value can then be read in chunks from the stream. This method is particularly suitable for retrieving large LONGVARCHAR values. - * The JDBC driver will do any necessary conversion from the database format into ASCII. + * Returns the value of the designated column in the current row of this ResultSet object as a stream + * of ASCII characters. The value can then be read in chunks from the stream. This method is particularly suitable + * for retrieving large LONGVARCHAR values. The JDBC driver will do any necessary conversion from the + * database format into ASCII. * *

- * Note: All the data in the returned stream must be read prior to getting the value of any other column. The next call to a getter method - * implicitly closes the stream. Also, a stream may return 0 when the method available is called whether there is data - * available or not. + * Note: All the data in the returned stream must be read prior to getting the value of any other column. The + * next call to a getter method implicitly closes the stream. Also, a stream may return 0 when the + * method available is called whether there is data available or not. * * @param parameterName - * the name of the parameter - * @return a Java input stream that delivers the database column value as a stream of one-byte ASCII characters. If the value is SQL - * NULL, the value returned is null. + * the name of the parameter + * @return a Java input stream that delivers the database column value as a stream of one-byte ASCII characters. If + * the value is SQL NULL, the value returned is null. * @throws SQLServerException - * if the columnLabel is not valid; if a database access error occurs or this method is called on a closed result set + * if the columnLabel is not valid; if a database access error occurs or this method is called on a closed + * result set */ public java.io.InputStream getAsciiStream(String parameterName) throws SQLServerException; /** - * Retrieves the value of the column specified as a java.math.BigDecimal object. + * Returns the value of the column specified as a java.math.BigDecimal object. * * @param parameterIndex - * The zero-based ordinal of a column. + * The zero-based ordinal of a column. * @return the column value; if the value is SQL NULL, the value returned is null * @throws SQLServerException - * when an error occurs + * when an error occurs */ public BigDecimal getMoney(int parameterIndex) throws SQLServerException; /** - * Retrieves the value of the column specified as a java.math.BigDecimal object. + * Returns the value of the column specified as a java.math.BigDecimal object. * * @param parameterName - * The name of a column. + * The name of a column. * @return the column value; if the value is SQL NULL, the value returned is null. * @throws SQLServerException - * when an error occurs + * when an error occurs */ public BigDecimal getMoney(String parameterName) throws SQLServerException; /** - * Retrieves the value of the column specified as a java.math.BigDecimal object. + * Returns the value of the column specified as a java.math.BigDecimal object. * * @param parameterIndex - * The zero-based ordinal of a column. + * The zero-based ordinal of a column. * @return the column value; if the value is SQL NULL, the value returned is null * @throws SQLServerException - * when an error occurs + * when an error occurs */ public BigDecimal getSmallMoney(int parameterIndex) throws SQLServerException; /** - * Retrieves the value of the column specified as a java.math.BigDecimal object. + * Returns the value of the column specified as a java.math.BigDecimal object. * * @param parameterName - * The name of a column. + * The name of a column. * @return the column value; if the value is SQL NULL, the value returned is null. * @throws SQLServerException - * when an error occurs + * when an error occurs */ public BigDecimal getSmallMoney(String parameterName) throws SQLServerException; /** - * Retrieves the value of the designated column in the current row of this ResultSet object as a stream of uninterpreted bytes. The - * value can then be read in chunks from the stream. This method is particularly suitable for retrieving large LONGVARBINARY values. + * Returns the value of the designated column in the current row of this ResultSet object as a stream + * of uninterpreted bytes. The value can then be read in chunks from the stream. This method is particularly + * suitable for retrieving large LONGVARBINARY values. * *

- * Note: All the data in the returned stream must be read prior to getting the value of any other column. The next call to a getter method - * implicitly closes the stream. Also, a stream may return 0 when the method InputStream.available is called whether - * there is data available or not. + * Note: All the data in the returned stream must be read prior to getting the value of any other column. The + * next call to a getter method implicitly closes the stream. Also, a stream may return 0 when the + * method InputStream.available is called whether there is data available or not. * * @param parameterIndex - * the first column is 1, the second is 2, ... - * @return a Java input stream that delivers the database column value as a stream of uninterpreted bytes; if the value is SQL NULL, - * the value returned is null + * the first column is 1, the second is 2, ... + * @return a Java input stream that delivers the database column value as a stream of uninterpreted bytes; if the + * value is SQL NULL, the value returned is null * @throws SQLServerException - * if the columnIndex is not valid; if a database access error occurs or this method is called on a closed result set + * if the columnIndex is not valid; if a database access error occurs or this method is called on a closed + * result set */ public java.io.InputStream getBinaryStream(int parameterIndex) throws SQLServerException; /** - * Retrieves the value of the designated column in the current row of this ResultSet object as a stream of uninterpreted - * bytes. The value can then be read in chunks from the stream. This method is particularly suitable for retrieving large - * LONGVARBINARY values. + * Returns the value of the designated column in the current row of this ResultSet object as a stream + * of uninterpreted bytes. The value can then be read in chunks from the stream. This method is + * particularly suitable for retrieving large LONGVARBINARY values. * *

- * Note: All the data in the returned stream must be read prior to getting the value of any other column. The next call to a getter method - * implicitly closes the stream. Also, a stream may return 0 when the method available is called whether there is data - * available or not. + * Note: All the data in the returned stream must be read prior to getting the value of any other column. The + * next call to a getter method implicitly closes the stream. Also, a stream may return 0 when the + * method available is called whether there is data available or not. * * @param parameterName - * the name of the parameter - * @return a Java input stream that delivers the database column value as a stream of uninterpreted bytes; if the value is SQL NULL, - * the result is null + * the name of the parameter + * @return a Java input stream that delivers the database column value as a stream of uninterpreted bytes; if the + * value is SQL NULL, the result is null * @throws SQLServerException - * if the columnLabel is not valid; if a database access error occurs or this method is called on a closed result set + * if the columnLabel is not valid; if a database access error occurs or this method is called on a closed + * result set */ public java.io.InputStream getBinaryStream(String parameterName) throws SQLServerException; /** - * Sets the designated parameter to the given java.sql.Timestamp value. The driver converts this to an SQL TIMESTAMP - * value when it sends it to the database. + * Sets the designated parameter to the given java.sql.Timestamp value. The driver converts this to an + * SQL TIMESTAMP value when it sends it to the database. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * the parameter value + * the parameter value * @param calendar - * a java.util.Calendar + * a java.util.Calendar * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement * @see #getTimestamp */ - public void setTimestamp(String parameterName, - java.sql.Timestamp value, - Calendar calendar, + public void setTimestamp(String parameterName, java.sql.Timestamp value, Calendar calendar, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given java.sql.Time value, using the given Calendar object. The driver uses the - * Calendar object to construct an SQL TIME value, which the driver then sends to the database. With a a - * Calendar object, the driver can calculate the time taking into account a custom timezone. If no Calendar object is + * Sets the designated parameter to the given java.sql.Time value, using the given + * Calendar object. The driver uses the Calendar object to construct an SQL + * TIME value, which the driver then sends to the database. With a a Calendar object, the + * driver can calculate the time taking into account a custom timezone. If no Calendar object is * specified, the driver uses the default timezone, which is that of the virtual machine running the application. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * the parameter value + * the parameter value * @param calendar - * the Calendar object the driver will use to construct the time + * the Calendar object the driver will use to construct the time * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement * @see #getTime */ - public void setTime(String parameterName, - java.sql.Time value, - Calendar calendar, + public void setTime(String parameterName, java.sql.Time value, Calendar calendar, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given java.sql.Date value, using the given Calendar object. The driver uses the - * Calendar object to construct an SQL DATE value, which the driver then sends to the database. With a a - * Calendar object, the driver can calculate the date taking into account a custom timezone. If no Calendar object is + * Sets the designated parameter to the given java.sql.Date value, using the given + * Calendar object. The driver uses the Calendar object to construct an SQL + * DATE value, which the driver then sends to the database. With a a Calendar object, the + * driver can calculate the date taking into account a custom timezone. If no Calendar object is * specified, the driver uses the default timezone, which is that of the virtual machine running the application. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * the parameter value + * the parameter value * @param calendar - * the Calendar object the driver will use to construct the date + * the Calendar object the driver will use to construct the date * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement * @see #getDate */ - public void setDate(String parameterName, - java.sql.Date value, - Calendar calendar, + public void setDate(String parameterName, java.sql.Date value, Calendar calendar, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given String object. The driver converts this to a SQL NCHAR or - * NVARCHAR or LONGNVARCHAR + * Sets the designated parameter to the given String object. The driver converts this to a SQL + * NCHAR or NVARCHAR or LONGNVARCHAR * * @param parameterName - * the name of the parameter to be set + * the name of the parameter to be set * @param value - * the parameter value + * the parameter value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if the driver does not support national character sets; if the driver - * can detect that a data conversion error could occur; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if the driver does not support national + * character sets; if the driver can detect that a data conversion error could occur; if a database access + * error occurs or this method is called on a closed CallableStatement */ - public void setNString(String parameterName, - String value, - boolean forceEncrypt) throws SQLServerException; + public void setNString(String parameterName, String value, boolean forceEncrypt) throws SQLServerException; /** * Sets the value of the designated parameter with the given object. @@ -379,36 +373,35 @@ public void setNString(String parameterName, *

* The given Java object will be converted to the given targetSqlType before being sent to the database. * - * If the object has a custom mapping (is of a class implementing the interface SQLData), the JDBC driver should call the method - * SQLData.writeSQL to write it to the SQL data stream. If, on the other hand, the object is of a class implementing - * Ref, Blob, Clob, NClob, Struct, java.net.URL, or - * Array, the driver should pass it to the database as a value of the corresponding SQL type. + * If the object has a custom mapping (is of a class implementing the interface SQLData), the JDBC + * driver should call the method SQLData.writeSQL to write it to the SQL data stream. If, on the other + * hand, the object is of a class implementing Ref, Blob, Clob, + * NClob, Struct, java.net.URL, or Array, the driver should pass + * it to the database as a value of the corresponding SQL type. *

* Note that this method may be used to pass database- specific abstract data types. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * the object containing the input parameter value + * the object containing the input parameter value * @param sqlType - * the SQL type (as defined in java.sql.Types) to be sent to the database. The scale argument may further qualify this type. + * the SQL type (as defined in java.sql.Types) to be sent to the database. The scale argument may further + * qualify this type. * @param decimals - * for java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types, this is the number of digits after the decimal point. For all other - * types, this value will be ignored. + * for java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types, this is the number of digits after the decimal + * point. For all other types, this value will be ignored. * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement * @see java.sql.Types * @see #getObject */ - public void setObject(String parameterName, - Object value, - int sqlType, - int decimals, + public void setObject(String parameterName, Object value, int sqlType, int decimals, boolean forceEncrypt) throws SQLServerException; /** @@ -417,714 +410,658 @@ public void setObject(String parameterName, *

* The given Java object will be converted to the given targetSqlType before being sent to the database. * - * If the object has a custom mapping (is of a class implementing the interface SQLData), the JDBC driver should call the method - * SQLData.writeSQL to write it to the SQL data stream. If, on the other hand, the object is of a class implementing - * Ref, Blob, Clob, NClob, Struct, java.net.URL, or - * Array, the driver should pass it to the database as a value of the corresponding SQL type. + * If the object has a custom mapping (is of a class implementing the interface SQLData), the JDBC + * driver should call the method SQLData.writeSQL to write it to the SQL data stream. If, on the other + * hand, the object is of a class implementing Ref, Blob, Clob, + * NClob, Struct, java.net.URL, or Array, the driver should pass + * it to the database as a value of the corresponding SQL type. *

* Note that this method may be used to pass datatabase- specific abstract data types. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * the object containing the input parameter value + * the object containing the input parameter value * @param targetSqlType - * the SQL type (as defined in java.sql.Types) to be sent to the database. The scale argument may further qualify this type. + * the SQL type (as defined in java.sql.Types) to be sent to the database. The scale argument may further + * qualify this type. * @param precision - * the precision of the column. + * the precision of the column. * @param scale - * the scale of the column. + * the scale of the column. * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement * @see java.sql.Types * @see #getObject */ - public void setObject(String parameterName, - Object value, - int targetSqlType, - Integer precision, + public void setObject(String parameterName, Object value, int targetSqlType, Integer precision, int scale) throws SQLServerException; /** - * Sets the designated parameter to the given java.sql.Timestamp value. The driver converts this to an SQL TIMESTAMP - * value when it sends it to the database. + * Sets the designated parameter to the given java.sql.Timestamp value. The driver converts this to an + * SQL TIMESTAMP value when it sends it to the database. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * the parameter value + * the parameter value * @param scale - * the scale of the parameter + * the scale of the parameter * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement * @see #getTimestamp */ - public void setTimestamp(String parameterName, - java.sql.Timestamp value, - int scale) throws SQLServerException; + public void setTimestamp(String parameterName, java.sql.Timestamp value, int scale) throws SQLServerException; /** - * Sets the designated parameter to the given java.sql.Timestamp value. The driver converts this to an SQL TIMESTAMP - * value when it sends it to the database. + * Sets the designated parameter to the given java.sql.Timestamp value. The driver converts this to an + * SQL TIMESTAMP value when it sends it to the database. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * the parameter value + * the parameter value * @param scale - * the scale of the parameter + * the scale of the parameter * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement * @see #getTimestamp */ - public void setTimestamp(String parameterName, - java.sql.Timestamp value, - int scale, + public void setTimestamp(String parameterName, java.sql.Timestamp value, int scale, boolean forceEncrypt) throws SQLServerException; /** - * Sets parameter parameterName to DateTimeOffset x + * Sets parameter parameterName to DateTimeOffset value. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * DateTimeOffset value + * DateTimeOffset value * @throws SQLServerException - * if an error occurs + * if an error occurs */ - public void setDateTimeOffset(String parameterName, - microsoft.sql.DateTimeOffset value) throws SQLServerException; + public void setDateTimeOffset(String parameterName, microsoft.sql.DateTimeOffset value) throws SQLServerException; /** - * Sets parameter parameterName to DateTimeOffset x + * Sets parameter parameterName to DateTimeOffset value. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * DateTimeOffset value + * DateTimeOffset value * @param scale - * the scale of the parameter + * the scale of the parameter * @throws SQLServerException - * if an error occurs + * if an error occurs */ - public void setDateTimeOffset(String parameterName, - microsoft.sql.DateTimeOffset value, + public void setDateTimeOffset(String parameterName, microsoft.sql.DateTimeOffset value, int scale) throws SQLServerException; /** - * Sets parameter parameterName to DateTimeOffset x + * Sets parameter parameterName to DateTimeOffset value. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * DateTimeOffset value + * DateTimeOffset value * @param scale - * the scale of the parameter + * the scale of the parameter * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * if an error occurs + * if an error occurs */ - public void setDateTimeOffset(String parameterName, - microsoft.sql.DateTimeOffset value, - int scale, + public void setDateTimeOffset(String parameterName, microsoft.sql.DateTimeOffset value, int scale, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given java.sql.Time value. The driver converts this to an SQL TIME value when it - * sends it to the database. + * Sets the designated parameter to the given java.sql.Time value. The driver converts this to an SQL + * TIME value when it sends it to the database. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * the parameter value + * the parameter value * @param scale - * the scale of the column + * the scale of the column * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement * @see #getTime */ - public void setTime(String parameterName, - java.sql.Time value, - int scale) throws SQLServerException; + public void setTime(String parameterName, java.sql.Time value, int scale) throws SQLServerException; /** - * Sets the designated parameter to the given java.sql.Time value. The driver converts this to an SQL TIME value when it - * sends it to the database. + * Sets the designated parameter to the given java.sql.Time value. The driver converts this to an SQL + * TIME value when it sends it to the database. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * the parameter value + * the parameter value * @param scale - * the scale of the column + * the scale of the column * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement * @see #getTime */ - public void setTime(String parameterName, - java.sql.Time value, - int scale, + public void setTime(String parameterName, java.sql.Time value, int scale, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given java.sql.Timestamp value. The driver converts this to an SQL DATETIME - * value when it sends it to the database. + * Sets the designated parameter to the given java.sql.Timestamp value. The driver converts this to an + * SQL DATETIME value when it sends it to the database. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * the parameter value + * the parameter value * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement */ - public void setDateTime(String parameterName, - java.sql.Timestamp value) throws SQLServerException; + public void setDateTime(String parameterName, java.sql.Timestamp value) throws SQLServerException; /** - * Sets the designated parameter to the given java.sql.Timestamp value. The driver converts this to an SQL DATETIME - * value when it sends it to the database. + * Sets the designated parameter to the given java.sql.Timestamp value. The driver converts this to an + * SQL DATETIME value when it sends it to the database. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * the parameter value + * the parameter value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement */ - public void setDateTime(String parameterName, - java.sql.Timestamp value, + public void setDateTime(String parameterName, java.sql.Timestamp value, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given java.sql.Timestamp value. The driver converts this to an SQL SMALLDATETIME - * value when it sends it to the database. + * Sets the designated parameter to the given java.sql.Timestamp value. The driver converts this to an + * SQL SMALLDATETIME value when it sends it to the database. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * the parameter value + * the parameter value * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement */ - public void setSmallDateTime(String parameterName, - java.sql.Timestamp value) throws SQLServerException; + public void setSmallDateTime(String parameterName, java.sql.Timestamp value) throws SQLServerException; /** - * Sets the designated parameter to the given java.sql.Timestamp value. The driver converts this to an SQL SMALLDATETIME - * value when it sends it to the database. + * Sets the designated parameter to the given java.sql.Timestamp value. The driver converts this to an + * SQL SMALLDATETIME value when it sends it to the database. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * the parameter value + * the parameter value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement */ - public void setSmallDateTime(String parameterName, - java.sql.Timestamp value, + public void setSmallDateTime(String parameterName, java.sql.Timestamp value, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given String value. The driver converts this to an SQL uniqueIdentifier value - * when it sends it to the database. + * Sets the designated parameter to the given String value. The driver converts this to an SQL + * uniqueIdentifier value when it sends it to the database. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param guid - * the parameter value + * the parameter value * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement */ - public void setUniqueIdentifier(String parameterName, - String guid) throws SQLServerException; + public void setUniqueIdentifier(String parameterName, String guid) throws SQLServerException; /** - * Sets the designated parameter to the given String value. The driver converts this to an SQL uniqueIdentifier value - * when it sends it to the database. + * Sets the designated parameter to the given String value. The driver converts this to an SQL + * uniqueIdentifier value when it sends it to the database. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param guid - * the parameter value + * the parameter value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement */ - public void setUniqueIdentifier(String parameterName, - String guid, - boolean forceEncrypt) throws SQLServerException; + public void setUniqueIdentifier(String parameterName, String guid, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given Java array of bytes. The driver converts this to an SQL VARBINARY or - * LONGVARBINARY (depending on the argument's size relative to the driver's limits on VARBINARY values) when it sends it - * to the database. + * Sets the designated parameter to the given Java array of bytes. The driver converts this to an SQL + * VARBINARY or LONGVARBINARY (depending on the argument's size relative to the driver's + * limits on VARBINARY values) when it sends it to the database. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * the parameter value + * the parameter value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement */ - public void setBytes(String parameterName, - byte[] value, - boolean forceEncrypt) throws SQLServerException; + public void setBytes(String parameterName, byte[] value, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given Java byte value. The driver converts this to an SQL TINYINT value when it - * sends it to the database. + * Sets the designated parameter to the given Java byte value. The driver converts this to an SQL + * TINYINT value when it sends it to the database. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * the parameter value + * the parameter value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement */ - public void setByte(String parameterName, - byte value, - boolean forceEncrypt) throws SQLServerException; + public void setByte(String parameterName, byte value, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given Java String value. The driver converts this to an SQL VARCHAR or - * LONGVARCHAR value (depending on the argument's size relative to the driver's limits on VARCHAR values) when it sends - * it to the database. + * Sets the designated parameter to the given Java String value. The driver converts this to an SQL + * VARCHAR or LONGVARCHAR value (depending on the argument's size relative to the driver's + * limits on VARCHAR values) when it sends it to the database. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * the parameter value + * the parameter value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement */ - public void setString(String parameterName, - String value, - boolean forceEncrypt) throws SQLServerException; + public void setString(String parameterName, String value, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given Java java.math.BigDecimal value. The driver converts this to an SQL Money - * value. + * Sets the designated parameter to the given Java java.math.BigDecimal value. The driver converts this + * to an SQL Money value. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * the parameter value + * the parameter value * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement */ - public void setMoney(String parameterName, - BigDecimal value) throws SQLServerException; + public void setMoney(String parameterName, BigDecimal value) throws SQLServerException; /** - * Sets the designated parameter to the given Java java.math.BigDecimal value. The driver converts this to an SQL Money - * value. + * Sets the designated parameter to the given Java java.math.BigDecimal value. The driver converts this + * to an SQL Money value. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * the parameter value + * the parameter value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement */ - public void setMoney(String parameterName, - BigDecimal value, - boolean forceEncrypt) throws SQLServerException; + public void setMoney(String parameterName, BigDecimal value, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given Java java.math.BigDecimal value. The driver converts this to an SQL - * smallMoney value. + * Sets the designated parameter to the given Java java.math.BigDecimal value. The driver converts this + * to an SQL smallMoney value. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * the parameter value + * the parameter value * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement */ - public void setSmallMoney(String parameterName, - BigDecimal value) throws SQLServerException; + public void setSmallMoney(String parameterName, BigDecimal value) throws SQLServerException; /** - * Sets the designated parameter to the given Java java.math.BigDecimal value. The driver converts this to an SQL - * smallMoney value. + * Sets the designated parameter to the given Java java.math.BigDecimal value. The driver converts this + * to an SQL smallMoney value. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * the parameter value + * the parameter value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement */ - public void setSmallMoney(String parameterName, - BigDecimal value, - boolean forceEncrypt) throws SQLServerException; + public void setSmallMoney(String parameterName, BigDecimal value, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given java.math.BigDecimal value. The driver converts this to an SQL NUMERIC - * value when it sends it to the database. + * Sets the designated parameter to the given java.math.BigDecimal value. The driver converts this to + * an SQL NUMERIC value when it sends it to the database. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * the parameter value + * the parameter value * @param precision - * the precision of the column + * the precision of the column * @param scale - * the scale of the column + * the scale of the column * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement */ - public void setBigDecimal(String parameterName, - BigDecimal value, - int precision, + public void setBigDecimal(String parameterName, BigDecimal value, int precision, int scale) throws SQLServerException; /** - * Sets the designated parameter to the given java.math.BigDecimal value. The driver converts this to an SQL NUMERIC - * value when it sends it to the database. + * Sets the designated parameter to the given java.math.BigDecimal value. The driver converts this to + * an SQL NUMERIC value when it sends it to the database. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * the parameter value + * the parameter value * @param precision - * the precision of the column + * the precision of the column * @param scale - * the scale of the column + * the scale of the column * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement */ - public void setBigDecimal(String parameterName, - BigDecimal value, - int precision, - int scale, + public void setBigDecimal(String parameterName, BigDecimal value, int precision, int scale, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given Java double value. The driver converts this to an SQL DOUBLE value when it - * sends it to the database. + * Sets the designated parameter to the given Java double value. The driver converts this to an SQL + * DOUBLE value when it sends it to the database. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * the parameter value + * the parameter value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement */ - public void setDouble(String parameterName, - double value, - boolean forceEncrypt) throws SQLServerException; + public void setDouble(String parameterName, double value, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given Java float value. The driver converts this to an SQL FLOAT value when it - * sends it to the database. + * Sets the designated parameter to the given Java float value. The driver converts this to an SQL + * FLOAT value when it sends it to the database. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * the parameter value + * the parameter value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement */ - public void setFloat(String parameterName, - float value, - boolean forceEncrypt) throws SQLServerException; + public void setFloat(String parameterName, float value, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given Java int value. The driver converts this to an SQL INTEGER value when it - * sends it to the database. + * Sets the designated parameter to the given Java int value. The driver converts this to an SQL + * INTEGER value when it sends it to the database. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * the parameter value + * the parameter value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement */ - public void setInt(String parameterName, - int value, - boolean forceEncrypt) throws SQLServerException; + public void setInt(String parameterName, int value, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given Java long value. The driver converts this to an SQL BIGINT value when it - * sends it to the database. + * Sets the designated parameter to the given Java long value. The driver converts this to an SQL + * BIGINT value when it sends it to the database. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * the parameter value + * the parameter value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement */ - public void setLong(String parameterName, - long value, - boolean forceEncrypt) throws SQLServerException; + public void setLong(String parameterName, long value, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given Java short value. The driver converts this to an SQL SMALLINT value when - * it sends it to the database. + * Sets the designated parameter to the given Java short value. The driver converts this to an SQL + * SMALLINT value when it sends it to the database. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * the parameter value + * the parameter value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement */ - public void setShort(String parameterName, - short value, - boolean forceEncrypt) throws SQLServerException; + public void setShort(String parameterName, short value, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given Java boolean value. The driver converts this to an SQL BIT or - * BOOLEAN value when it sends it to the database. + * Sets the designated parameter to the given Java boolean value. The driver converts this to an SQL + * BIT or BOOLEAN value when it sends it to the database. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * the parameter value + * the parameter value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement */ - public void setBoolean(String parameterName, - boolean value, - boolean forceEncrypt) throws SQLServerException; + public void setBoolean(String parameterName, boolean value, boolean forceEncrypt) throws SQLServerException; /** * Populates a table valued parameter passed to a stored procedure with a data table. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param tvpName - * the name of the type TVP + * the name of the type TVP * @param tvpDataTable - * the data table object + * the data table object * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setStructured(String parameterName, - String tvpName, + public void setStructured(String parameterName, String tvpName, SQLServerDataTable tvpDataTable) throws SQLServerException; /** * Populates a table valued parameter passed to a stored procedure with a ResultSet retrieved from another table * * @param parameterName - * the name of the parameter + * the name of the parameter * @param tvpName - * the name of the type TVP + * the name of the type TVP * @param tvpResultSet - * the source result set object + * the source result set object * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setStructured(String parameterName, - String tvpName, + public void setStructured(String parameterName, String tvpName, java.sql.ResultSet tvpResultSet) throws SQLServerException; /** * Populates a table valued parameter passed to a stored procedure with an ISQLServerDataRecord object. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param tvpName - * the name of the type TVP + * the name of the type TVP * @param tvpDataRecord - * ISQLServerDataRecord is used for streaming data and the user decides how to use it. tvpDataRecord is an ISQLServerDataRecord - * object.the source result set object + * ISQLServerDataRecord is used for streaming data and the user decides how to use it. tvpDataRecord is an + * ISQLServerDataRecord object.the source result set object * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setStructured(String parameterName, - String tvpName, + public void setStructured(String parameterName, String tvpName, ISQLServerDataRecord tvpDataRecord) throws SQLServerException; /** - * Registers the parameter in ordinal position index to be of JDBC type sqlType. All OUT parameters must be registered before a stored procedure - * is executed. + * Registers the parameter in ordinal position index to be of JDBC type sqlType. All OUT parameters must be + * registered before a stored procedure is executed. *

- * The JDBC type specified by sqlType for an OUT parameter determines the Java type that must be used in the get method to read the value of that - * parameter. + * The JDBC type specified by sqlType for an OUT parameter determines the Java type that must be used in the get + * method to read the value of that parameter. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param sqlType - * the JDBC type code defined by SQLType to use to register the OUT Parameter. + * the JDBC type code defined by SQLType to use to register the OUT Parameter. * @param precision - * the sum of the desired number of digits to the left and right of the decimal point. It must be greater than or equal to zero. + * the sum of the desired number of digits to the left and right of the decimal point. It must be greater + * than or equal to zero. * @param scale - * the desired number of digits to the right of the decimal point. It must be greater than or equal to zero. + * the desired number of digits to the right of the decimal point. It must be greater than or equal to zero. * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void registerOutParameter(String parameterName, - SQLType sqlType, - int precision, + public void registerOutParameter(String parameterName, SQLType sqlType, int precision, int scale) throws SQLServerException; /** - * Registers the parameter in ordinal position index to be of JDBC type sqlType. All OUT parameters must be registered before a stored procedure - * is executed. + * Registers the parameter in ordinal position index to be of JDBC type sqlType. All OUT parameters must be + * registered before a stored procedure is executed. *

- * The JDBC type specified by sqlType for an OUT parameter determines the Java type that must be used in the get method to read the value of that - * parameter. + * The JDBC type specified by sqlType for an OUT parameter determines the Java type that must be used in the get + * method to read the value of that parameter. * * @param parameterIndex - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param sqlType - * the JDBC type code defined by SQLType to use to register the OUT Parameter. + * the JDBC type code defined by SQLType to use to register the OUT Parameter. * @param precision - * the sum of the desired number of digits to the left and right of the decimal point. It must be greater than or equal to zero. + * the sum of the desired number of digits to the left and right of the decimal point. It must be greater + * than or equal to zero. * @param scale - * the desired number of digits to the right of the decimal point. It must be greater than or equal to zero. + * the desired number of digits to the right of the decimal point. It must be greater than or equal to zero. * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void registerOutParameter(int parameterIndex, - SQLType sqlType, - int precision, + public void registerOutParameter(int parameterIndex, SQLType sqlType, int precision, int scale) throws SQLServerException; /** - * Registers the parameter in ordinal position index to be of JDBC type sqlType. All OUT parameters must be registered before a stored procedure - * is executed. + * Registers the parameter in ordinal position index to be of JDBC type sqlType. All OUT parameters must be + * registered before a stored procedure is executed. *

- * The JDBC type specified by sqlType for an OUT parameter determines the Java type that must be used in the get method to read the value of that - * parameter. + * The JDBC type specified by sqlType for an OUT parameter determines the Java type that must be used in the get + * method to read the value of that parameter. * * @param parameterIndex - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param sqlType - * the JDBC type code defined by SQLType to use to register the OUT Parameter. + * the JDBC type code defined by SQLType to use to register the OUT Parameter. * @param precision - * the sum of the desired number of digits to the left and right of the decimal point. It must be greater than or equal to zero. + * the sum of the desired number of digits to the left and right of the decimal point. It must be greater + * than or equal to zero. * @param scale - * the desired number of digits to the right of the decimal point. It must be greater than or equal to zero. + * the desired number of digits to the right of the decimal point. It must be greater than or equal to zero. * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void registerOutParameter(int parameterIndex, - int sqlType, - int precision, + public void registerOutParameter(int parameterIndex, int sqlType, int precision, int scale) throws SQLServerException; /** - * Registers the parameter in ordinal position index to be of JDBC type sqlType. All OUT parameters must be registered before a stored procedure - * is executed. + * Registers the parameter in ordinal position index to be of JDBC type sqlType. All OUT parameters must be + * registered before a stored procedure is executed. *

- * The JDBC type specified by sqlType for an OUT parameter determines the Java type that must be used in the get method to read the value of that - * parameter. + * The JDBC type specified by sqlType for an OUT parameter determines the Java type that must be used in the get + * method to read the value of that parameter. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param sqlType - * the JDBC type code defined by SQLType to use to register the OUT Parameter. + * the JDBC type code defined by SQLType to use to register the OUT Parameter. * @param precision - * the sum of the desired number of digits to the left and right of the decimal point. It must be greater than or equal to zero. + * the sum of the desired number of digits to the left and right of the decimal point. It must be greater + * than or equal to zero. * @param scale - * the desired number of digits to the right of the decimal point. It must be greater than or equal to zero. + * the desired number of digits to the right of the decimal point. It must be greater than or equal to zero. * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void registerOutParameter(String parameterName, - int sqlType, - int precision, + public void registerOutParameter(String parameterName, int sqlType, int precision, int scale) throws SQLServerException; /** @@ -1133,34 +1070,33 @@ public void registerOutParameter(String parameterName, *

* The given Java object will be converted to the given targetSqlType before being sent to the database. * - * If the object has a custom mapping (is of a class implementing the interface SQLData), the JDBC driver should call the method - * SQLData.writeSQL to write it to the SQL data stream. If, on the other hand, the object is of a class implementing - * Ref, Blob, Clob, NClob, Struct, java.net.URL, or - * Array, the driver should pass it to the database as a value of the corresponding SQL type. + * If the object has a custom mapping (is of a class implementing the interface SQLData), the JDBC + * driver should call the method SQLData.writeSQL to write it to the SQL data stream. If, on the other + * hand, the object is of a class implementing Ref, Blob, Clob, + * NClob, Struct, java.net.URL, or Array, the driver should pass + * it to the database as a value of the corresponding SQL type. *

* Note that this method may be used to pass datatabase- specific abstract data types. * * @param parameterName - * the name of the parameter + * the name of the parameter * @param value - * the object containing the input parameter value + * the object containing the input parameter value * @param jdbcType - * the SQL type (as defined in java.sql.Types) to be sent to the database. The scale argument may further qualify this type. + * the SQL type (as defined in java.sql.Types) to be sent to the database. The scale argument may further + * qualify this type. * @param scale - * the scale of the column. + * the scale of the column. * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * if parameterName does not correspond to a named parameter; if a database access error occurs or this method is called on a closed - * CallableStatement + * if parameterName does not correspond to a named parameter; if a database access error occurs or this + * method is called on a closed CallableStatement * @see java.sql.Types * @see #getObject */ - public void setObject(String parameterName, - Object value, - SQLType jdbcType, - int scale, + public void setObject(String parameterName, Object value, SQLType jdbcType, int scale, boolean forceEncrypt) throws SQLServerException; } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerConnection.java b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerConnection.java index 7ebf9dcfc..44d991782 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerConnection.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerConnection.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -13,8 +10,9 @@ import java.sql.Statement; import java.util.UUID; + /** - * This interface is implemented by {@link SQLServerConnection} and {@link SQLServerConnectionPoolProxy} Classes. + * Provides an interface to the {@link SQLServerConnection} and {@link SQLServerConnectionPoolProxy} classes. */ public interface ISQLServerConnection extends java.sql.Connection { @@ -23,223 +21,223 @@ public interface ISQLServerConnection extends java.sql.Connection { public final static int TRANSACTION_SNAPSHOT = 0x1000; /** - * Gets the connection ID of the most recent connection attempt, regardless of whether the attempt succeeded or failed. + * Returns the connection ID of the most recent connection attempt, regardless of whether the attempt succeeded or + * failed. * - * @return 16-byte GUID representing the connection ID of the most recent connection attempt. Or, NULL if there is a failure after the connection - * request is initiated and the pre-login handshake. + * @return 16-byte GUID representing the connection ID of the most recent connection attempt. Or, NULL if there is a + * failure after the connection request is initiated and the pre-login handshake. * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ public UUID getClientConnectionId() throws SQLServerException; /** - * Creates a Statement object that will generate ResultSet objects with the given type, concurrency, and holdability. - * This method is the same as the createStatement method above, but it allows the default result set type, concurrency, and - * holdability to be overridden. + * Creates a Statement object that will generate ResultSet objects with the given type, + * concurrency, and holdability. This method is the same as the createStatement method above, but it + * allows the default result set type, concurrency, and holdability to be overridden. * * @param nType - * one of the following ResultSet constants: ResultSet.TYPE_FORWARD_ONLY, - * ResultSet.TYPE_SCROLL_INSENSITIVE, or ResultSet.TYPE_SCROLL_SENSITIVE + * one of the following ResultSet constants: ResultSet.TYPE_FORWARD_ONLY, + * ResultSet.TYPE_SCROLL_INSENSITIVE, or ResultSet.TYPE_SCROLL_SENSITIVE * @param nConcur - * one of the following ResultSet constants: ResultSet.CONCUR_READ_ONLY or - * ResultSet.CONCUR_UPDATABLE + * one of the following ResultSet constants: ResultSet.CONCUR_READ_ONLY or + * ResultSet.CONCUR_UPDATABLE * @param nHold - * one of the following ResultSet constants: ResultSet.HOLD_CURSORS_OVER_COMMIT or - * ResultSet.CLOSE_CURSORS_AT_COMMIT + * one of the following ResultSet constants: ResultSet.HOLD_CURSORS_OVER_COMMIT or + * ResultSet.CLOSE_CURSORS_AT_COMMIT * @param stmtColEncSetting - * Specifies how data will be sent and received when reading and writing encrypted columns. - * @return a new Statement object that will generate ResultSet objects with the given type, concurrency, and holdability + * Specifies how data will be sent and received when reading and writing encrypted columns. + * @return a new Statement object that will generate ResultSet objects with the given + * type, concurrency, and holdability * @throws SQLServerException - * if a database access error occurs, this method is called on a closed connection or the given parameters are not - * ResultSet constants indicating type, concurrency, and holdability + * if a database access error occurs, this method is called on a closed connection or the given parameters + * are not ResultSet constants indicating type, concurrency, and holdability */ - public Statement createStatement(int nType, - int nConcur, - int nHold, + public Statement createStatement(int nType, int nConcur, int nHold, SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException; /** - * Creates a default PreparedStatement object that has the capability to retrieve auto-generated keys. The given constant tells the - * driver whether it should make auto-generated keys available for retrieval. This parameter is ignored if the SQL statement is not an - * INSERT statement, or an SQL statement able to return auto-generated keys (the list of such statements is vendor-specific). + * Creates a default PreparedStatement object that has the capability to retrieve auto-generated keys. + * The given constant tells the driver whether it should make auto-generated keys available for retrieval. This + * parameter is ignored if the SQL statement is not an INSERT statement, or an SQL statement able to + * return auto-generated keys (the list of such statements is vendor-specific). *

- * Note: This method is optimized for handling parametric SQL statements that benefit from precompilation. If the driver supports - * precompilation, the method prepareStatement will send the statement to the database for precompilation. Some drivers may not - * support precompilation. In this case, the statement may not be sent to the database until the PreparedStatement object is - * executed. This has no direct effect on users; however, it does affect which methods throw certain SQLExceptions. + * Note: This method is optimized for handling parametric SQL statements that benefit from precompilation. If + * the driver supports precompilation, the method prepareStatement will send the statement to the + * database for precompilation. Some drivers may not support precompilation. In this case, the statement may not be + * sent to the database until the PreparedStatement object is executed. This has no direct effect on + * users; however, it does affect which methods throw certain SQLExceptions. *

- * Result sets created using the returned PreparedStatement object will by default be type TYPE_FORWARD_ONLY and have a - * concurrency level of CONCUR_READ_ONLY. The holdability of the created result sets can be determined by calling - * {@link #getHoldability}. + * Result sets created using the returned PreparedStatement object will by default be type + * TYPE_FORWARD_ONLY and have a concurrency level of CONCUR_READ_ONLY. The holdability of + * the created result sets can be determined by calling {@link #getHoldability}. * * @param sql - * an SQL statement that may contain one or more '?' IN parameter placeholders + * an SQL statement that may contain one or more '?' IN parameter placeholders * @param flag - * a flag indicating whether auto-generated keys should be returned; one of Statement.RETURN_GENERATED_KEYS or - * Statement.NO_GENERATED_KEYS + * a flag indicating whether auto-generated keys should be returned; one of + * Statement.RETURN_GENERATED_KEYS or Statement.NO_GENERATED_KEYS * @param stmtColEncSetting - * Specifies how data will be sent and received when reading and writing encrypted columns. - * @return a new PreparedStatement object, containing the pre-compiled SQL statement, that will have the capability of returning - * auto-generated keys + * Specifies how data will be sent and received when reading and writing encrypted columns. + * @return a new PreparedStatement object, containing the pre-compiled SQL statement, that will have + * the capability of returning auto-generated keys * @throws SQLServerException - * if a database access error occurs, this method is called on a closed connection or the given parameter is not a - * Statement constant indicating whether auto-generated keys should be returned + * if a database access error occurs, this method is called on a closed connection or the given parameter is + * not a Statement constant indicating whether auto-generated keys should be returned */ - public PreparedStatement prepareStatement(String sql, - int flag, + public PreparedStatement prepareStatement(String sql, int flag, SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException; /** - * Creates a default PreparedStatement object capable of returning the auto-generated keys designated by the given array. This array - * contains the indexes of the columns in the target table that contain the auto-generated keys that should be made available. The driver will - * ignore the array if the SQL statement is not an INSERT statement, or an SQL statement able to return auto-generated keys (the list - * of such statements is vendor-specific). + * Creates a default PreparedStatement object capable of returning the auto-generated keys designated + * by the given array. This array contains the indexes of the columns in the target table that contain the + * auto-generated keys that should be made available. The driver will ignore the array if the SQL statement is not + * an INSERT statement, or an SQL statement able to return auto-generated keys (the list of such + * statements is vendor-specific). *

- * An SQL statement with or without IN parameters can be pre-compiled and stored in a PreparedStatement object. This object can then - * be used to efficiently execute this statement multiple times. + * An SQL statement with or without IN parameters can be pre-compiled and stored in a PreparedStatement + * object. This object can then be used to efficiently execute this statement multiple times. *

- * Note: This method is optimized for handling parametric SQL statements that benefit from precompilation. If the driver supports - * precompilation, the method prepareStatement will send the statement to the database for precompilation. Some drivers may not - * support precompilation. In this case, the statement may not be sent to the database until the PreparedStatement object is - * executed. This has no direct effect on users; however, it does affect which methods throw certain SQLExceptions. + * Note: This method is optimized for handling parametric SQL statements that benefit from precompilation. If + * the driver supports precompilation, the method prepareStatement will send the statement to the + * database for precompilation. Some drivers may not support precompilation. In this case, the statement may not be + * sent to the database until the PreparedStatement object is executed. This has no direct effect on + * users; however, it does affect which methods throw certain SQLExceptions. *

- * Result sets created using the returned PreparedStatement object will by default be type TYPE_FORWARD_ONLY and have a - * concurrency level of CONCUR_READ_ONLY. The holdability of the created result sets can be determined by calling - * {@link #getHoldability}. + * Result sets created using the returned PreparedStatement object will by default be type + * TYPE_FORWARD_ONLY and have a concurrency level of CONCUR_READ_ONLY. The holdability of + * the created result sets can be determined by calling {@link #getHoldability}. * * @param sql - * an SQL statement that may contain one or more '?' IN parameter placeholders + * an SQL statement that may contain one or more '?' IN parameter placeholders * @param columnIndexes - * an array of column indexes indicating the columns that should be returned from the inserted row or rows + * an array of column indexes indicating the columns that should be returned from the inserted row or rows * @param stmtColEncSetting - * Specifies how data will be sent and received when reading and writing encrypted columns. - * @return a new PreparedStatement object, containing the pre-compiled statement, that is capable of returning the auto-generated - * keys designated by the given array of column indexes + * Specifies how data will be sent and received when reading and writing encrypted columns. + * @return a new PreparedStatement object, containing the pre-compiled statement, that is capable of + * returning the auto-generated keys designated by the given array of column indexes * @throws SQLServerException - * if a database access error occurs or this method is called on a closed connection + * if a database access error occurs or this method is called on a closed connection */ - public PreparedStatement prepareStatement(String sql, - int[] columnIndexes, + public PreparedStatement prepareStatement(String sql, int[] columnIndexes, SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException; /** - * Creates a default PreparedStatement object capable of returning the auto-generated keys designated by the given array. This array - * contains the names of the columns in the target table that contain the auto-generated keys that should be returned. The driver will ignore the - * array if the SQL statement is not an INSERT statement, or an SQL statement able to return auto-generated keys (the list of such + * Creates a default PreparedStatement object capable of returning the auto-generated keys designated + * by the given array. This array contains the names of the columns in the target table that contain the + * auto-generated keys that should be returned. The driver will ignore the array if the SQL statement is not an + * INSERT statement, or an SQL statement able to return auto-generated keys (the list of such * statements is vendor-specific). *

- * An SQL statement with or without IN parameters can be pre-compiled and stored in a PreparedStatement object. This object can then - * be used to efficiently execute this statement multiple times. + * An SQL statement with or without IN parameters can be pre-compiled and stored in a PreparedStatement + * object. This object can then be used to efficiently execute this statement multiple times. *

- * Note: This method is optimized for handling parametric SQL statements that benefit from precompilation. If the driver supports - * precompilation, the method prepareStatement will send the statement to the database for precompilation. Some drivers may not - * support precompilation. In this case, the statement may not be sent to the database until the PreparedStatement object is - * executed. This has no direct effect on users; however, it does affect which methods throw certain SQLExceptions. + * Note: This method is optimized for handling parametric SQL statements that benefit from precompilation. If + * the driver supports precompilation, the method prepareStatement will send the statement to the + * database for precompilation. Some drivers may not support precompilation. In this case, the statement may not be + * sent to the database until the PreparedStatement object is executed. This has no direct effect on + * users; however, it does affect which methods throw certain SQLExceptions. *

- * Result sets created using the returned PreparedStatement object will by default be type TYPE_FORWARD_ONLY and have a - * concurrency level of CONCUR_READ_ONLY. The holdability of the created result sets can be determined by calling - * {@link #getHoldability}. + * Result sets created using the returned PreparedStatement object will by default be type + * TYPE_FORWARD_ONLY and have a concurrency level of CONCUR_READ_ONLY. The holdability of + * the created result sets can be determined by calling {@link #getHoldability}. * * @param sql - * an SQL statement that may contain one or more '?' IN parameter placeholders + * an SQL statement that may contain one or more '?' IN parameter placeholders * @param columnNames - * an array of column names indicating the columns that should be returned from the inserted row or rows + * an array of column names indicating the columns that should be returned from the inserted row or rows * @param stmtColEncSetting - * Specifies how data will be sent and received when reading and writing encrypted columns. - * @return a new PreparedStatement object, containing the pre-compiled statement, that is capable of returning the auto-generated - * keys designated by the given array of column names + * Specifies how data will be sent and received when reading and writing encrypted columns. + * @return a new PreparedStatement object, containing the pre-compiled statement, that is capable of + * returning the auto-generated keys designated by the given array of column names * @throws SQLServerException - * if a database access error occurs or this method is called on a closed connection + * if a database access error occurs or this method is called on a closed connection */ - public PreparedStatement prepareStatement(String sql, - String[] columnNames, + public PreparedStatement prepareStatement(String sql, String[] columnNames, SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException; /** - * Creates a PreparedStatement object that will generate ResultSet objects with the given type, concurrency, and - * holdability. + * Creates a PreparedStatement object that will generate ResultSet objects with the given + * type, concurrency, and holdability. *

- * This method is the same as the prepareStatement method above, but it allows the default result set type, concurrency, and - * holdability to be overridden. + * This method is the same as the prepareStatement method above, but it allows the default result set + * type, concurrency, and holdability to be overridden. * * @param sql - * a String object that is the SQL statement to be sent to the database; may contain one or more '?' IN parameters + * a String object that is the SQL statement to be sent to the database; may contain one or more + * '?' IN parameters * @param nType - * one of the following ResultSet constants: ResultSet.TYPE_FORWARD_ONLY, - * ResultSet.TYPE_SCROLL_INSENSITIVE, or ResultSet.TYPE_SCROLL_SENSITIVE + * one of the following ResultSet constants: ResultSet.TYPE_FORWARD_ONLY, + * ResultSet.TYPE_SCROLL_INSENSITIVE, or ResultSet.TYPE_SCROLL_SENSITIVE * @param nConcur - * one of the following ResultSet constants: ResultSet.CONCUR_READ_ONLY or - * ResultSet.CONCUR_UPDATABLE + * one of the following ResultSet constants: ResultSet.CONCUR_READ_ONLY or + * ResultSet.CONCUR_UPDATABLE * @param resultSetHoldability - * one of the following ResultSet constants: ResultSet.HOLD_CURSORS_OVER_COMMIT or - * ResultSet.CLOSE_CURSORS_AT_COMMIT + * one of the following ResultSet constants: ResultSet.HOLD_CURSORS_OVER_COMMIT or + * ResultSet.CLOSE_CURSORS_AT_COMMIT * @param stmtColEncSetting - * Specifies how data will be sent and received when reading and writing encrypted columns. - * @return a new PreparedStatement object, containing the pre-compiled SQL statement, that will generate ResultSet - * objects with the given type, concurrency, and holdability + * Specifies how data will be sent and received when reading and writing encrypted columns. + * @return a new PreparedStatement object, containing the pre-compiled SQL statement, that will + * generate ResultSet objects with the given type, concurrency, and holdability * @throws SQLServerException - * if a database access error occurs, this method is called on a closed connection or the given parameters are not - * ResultSet constants indicating type, concurrency, and holdability + * if a database access error occurs, this method is called on a closed connection or the given parameters + * are not ResultSet constants indicating type, concurrency, and holdability */ - public PreparedStatement prepareStatement(java.lang.String sql, - int nType, - int nConcur, - int resultSetHoldability, + public PreparedStatement prepareStatement(java.lang.String sql, int nType, int nConcur, int resultSetHoldability, SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException; /** - * Creates a CallableStatement object that will generate ResultSet objects with the given type and concurrency. This - * method is the same as the prepareCall method above, but it allows the default result set type, result set concurrency type and - * holdability to be overridden. + * Creates a CallableStatement object that will generate ResultSet objects with the given + * type and concurrency. This method is the same as the prepareCall method above, but it allows the + * default result set type, result set concurrency type and holdability to be overridden. * * @param sql - * a String object that is the SQL statement to be sent to the database; may contain on or more '?' parameters + * a String object that is the SQL statement to be sent to the database; may contain on or more + * '?' parameters * @param nType - * one of the following ResultSet constants: ResultSet.TYPE_FORWARD_ONLY, - * ResultSet.TYPE_SCROLL_INSENSITIVE, or ResultSet.TYPE_SCROLL_SENSITIVE + * one of the following ResultSet constants: ResultSet.TYPE_FORWARD_ONLY, + * ResultSet.TYPE_SCROLL_INSENSITIVE, or ResultSet.TYPE_SCROLL_SENSITIVE * @param nConcur - * one of the following ResultSet constants: ResultSet.CONCUR_READ_ONLY or - * ResultSet.CONCUR_UPDATABLE + * one of the following ResultSet constants: ResultSet.CONCUR_READ_ONLY or + * ResultSet.CONCUR_UPDATABLE * @param nHold - * one of the following ResultSet constants: ResultSet.HOLD_CURSORS_OVER_COMMIT or - * ResultSet.CLOSE_CURSORS_AT_COMMIT + * one of the following ResultSet constants: ResultSet.HOLD_CURSORS_OVER_COMMIT or + * ResultSet.CLOSE_CURSORS_AT_COMMIT * @param stmtColEncSetting - * Specifies how data will be sent and received when reading and writing encrypted columns. - * @return a new CallableStatement object, containing the pre-compiled SQL statement, that will generate ResultSet - * objects with the given type, concurrency, and holdability + * Specifies how data will be sent and received when reading and writing encrypted columns. + * @return a new CallableStatement object, containing the pre-compiled SQL statement, that will + * generate ResultSet objects with the given type, concurrency, and holdability * @throws SQLServerException - * if a database access error occurs, this method is called on a closed connection or the given parameters are not - * ResultSet constants indicating type, concurrency, and holdability + * if a database access error occurs, this method is called on a closed connection or the given parameters + * are not ResultSet constants indicating type, concurrency, and holdability */ - public CallableStatement prepareCall(String sql, - int nType, - int nConcur, - int nHold, + public CallableStatement prepareCall(String sql, int nType, int nConcur, int nHold, SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException; /** - * Modifies the setting of the sendTimeAsDatetime connection property. When true, java.sql.Time values will be sent to the server as SQL - * Serverdatetime values. When false, java.sql.Time values will be sent to the server as SQL Servertime values. sendTimeAsDatetime can also be - * modified programmatically with SQLServerDataSource.setSendTimeAsDatetime. The default value for this property may change in a future release. + * Sets the value of the sendTimeAsDatetime connection property. When true, java.sql.Time values will be sent to the + * server as SQL Serverdatetime values. When false, java.sql.Time values will be sent to the server as SQL + * Servertime values. sendTimeAsDatetime can also be modified programmatically with + * SQLServerDataSource.setSendTimeAsDatetime. The default value for this property may change in a future release. * * @param sendTimeAsDateTimeValue - * enables/disables setting the sendTimeAsDatetime connection property. For more information about how the Microsoft JDBC Driver for - * SQL Server configures java.sql.Time values before sending them to the server, see - * Configuring How java.sql.Time Values are Sent to the - * Server. + * enables/disables setting the sendTimeAsDatetime connection property. For more information about how the + * Microsoft JDBC Driver for SQL Server configures java.sql.Time values before sending them to the server, + * see Configuring How + * java.sql.Time Values are Sent to the Server. * * @throws SQLServerException - * if a database access error occurs + * if a database access error occurs */ public void setSendTimeAsDatetime(boolean sendTimeAsDateTimeValue) throws SQLServerException; /** - * Checks the sendTimeAsDatetime property. + * Returns the value of the sendTimeAsDatetime property. * * @return boolean value of sendTimeAsDatetime * * @throws SQLServerException - * if a database access error occurs + * if a database access error occurs */ public boolean getSendTimeAsDatetime() throws SQLServerException; @@ -256,52 +254,56 @@ public CallableStatement prepareCall(String sql, public void closeUnreferencedPreparedStatementHandles(); /** - * Returns the behavior for a specific connection instance. If false the first execution will call sp_executesql and not prepare a statement, once - * the second execution happens it will call sp_prepexec and actually setup a prepared statement handle. Following executions will call - * sp_execute. This relieves the need for sp_unprepare on prepared statement close if the statement is only executed once. The default for this - * option can be changed by calling setDefaultEnablePrepareOnFirstPreparedStatementCall(). + * Returns the behavior for a specific connection instance. If false the first execution will call sp_executesql and + * not prepare a statement, once the second execution happens it will call sp_prepexec and actually setup a prepared + * statement handle. Following executions will call sp_execute. This relieves the need for sp_unprepare on prepared + * statement close if the statement is only executed once. The default for this option can be changed by calling + * setDefaultEnablePrepareOnFirstPreparedStatementCall(). * * @return Returns the current setting per the description. */ public boolean getEnablePrepareOnFirstPreparedStatementCall(); /** - * Specifies the behavior for a specific connection instance. If value is false the first execution will call sp_executesql and not prepare a - * statement, once the second execution happens it will call sp_prepexec and actually setup a prepared statement handle. Following executions will - * call sp_execute. This relieves the need for sp_unprepare on prepared statement close if the statement is only executed once. + * Sets the behavior for a specific connection instance. If value is false the first execution will call + * sp_executesql and not prepare a statement, once the second execution happens it will call sp_prepexec and + * actually setup a prepared statement handle. Following executions will call sp_execute. This relieves the need for + * sp_unprepare on prepared statement close if the statement is only executed once. * * @param value - * Changes the setting per the description. + * Changes the setting per the description. */ public void setEnablePrepareOnFirstPreparedStatementCall(boolean value); /** - * Returns the behavior for a specific connection instance. This setting controls how many outstanding prepared statement discard actions - * (sp_unprepare) can be outstanding per connection before a call to clean-up the outstanding handles on the server is executed. If the setting is - * {@literal <=} 1, unprepare actions will be executed immedietely on prepared statement close. If it is set to {@literal >} 1, these calls will - * be batched together to avoid overhead of calling sp_unprepare too often. The default for this option can be changed by calling - * getDefaultServerPreparedStatementDiscardThreshold(). + * Returns the behavior for a specific connection instance. This setting controls how many outstanding prepared + * statement discard actions (sp_unprepare) can be outstanding per connection before a call to clean-up the + * outstanding handles on the server is executed. If the setting is {@literal <=} 1, unprepare actions will be + * executed immedietely on prepared statement close. If it is set to {@literal >} 1, these calls will be batched + * together to avoid overhead of calling sp_unprepare too often. The default for this option can be changed by + * calling getDefaultServerPreparedStatementDiscardThreshold(). * * @return Returns the current setting per the description. */ public int getServerPreparedStatementDiscardThreshold(); /** - * Specifies the behavior for a specific connection instance. This setting controls how many outstanding prepared statement discard actions - * (sp_unprepare) can be outstanding per connection before a call to clean-up the outstanding handles on the server is executed. If the setting is - * {@literal <=} 1 unprepare actions will be executed immedietely on prepared statement close. If it is set to {@literal >} 1 these calls will be - * batched together to avoid overhead of calling sp_unprepare too often. + * Sets the behavior for a specific connection instance. This setting controls how many outstanding prepared + * statement discard actions (sp_unprepare) can be outstanding per connection before a call to clean-up the + * outstanding handles on the server is executed. If the setting is {@literal <=} 1 unprepare actions will be + * executed immedietely on prepared statement close. If it is set to {@literal >} 1 these calls will be batched + * together to avoid overhead of calling sp_unprepare too often. * * @param value - * Changes the setting per the description. + * Changes the setting per the description. */ public void setServerPreparedStatementDiscardThreshold(int value); /** - * Specifies the size of the prepared statement cache for this connection. A value less than 1 means no cache. + * Sets the size of the prepared statement cache for this connection. A value less than 1 means no cache. * * @param value - * The new cache size. + * The new cache size. * */ public void setStatementPoolingCacheSize(int value); @@ -314,7 +316,7 @@ public CallableStatement prepareCall(String sql, public int getStatementPoolingCacheSize(); /** - * Whether statement pooling is enabled or not for this connection. + * Returns whether statement pooling is enabled or not for this connection. * * @return Returns the current setting per the description. */ @@ -328,15 +330,15 @@ public CallableStatement prepareCall(String sql, public int getStatementHandleCacheEntryCount(); /** - * Disable/enable statement pooling. + * Sets the value to Disable/enable statement pooling. * * @param value - * true to disable statement pooling, false to enable it. + * true to disable statement pooling, false to enable it. */ public void setDisableStatementPooling(boolean value); /** - * Determine whether statement pooling is disabled. + * Returns the value whether statement pooling is disabled. * * @return true if statement pooling is disabled, false if it is enabled. */ diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerConnection43.java b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerConnection43.java index c7dca8ee1..b17597aa6 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerConnection43.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerConnection43.java @@ -1,57 +1,61 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; import java.sql.SQLException; + /** - * This interface is implemented by {@link SQLServerConnection43} class. + * Provides an interface to the {@link SQLServerConnection43} class. */ public interface ISQLServerConnection43 extends ISQLServerConnection { /** - * Hints to the driver that a request, an independent unit of work, is beginning on this connection. It backs up the values of the connection - * properties that are modifiable through public methods. Each request is independent of all other requests with regard to state local to the - * connection either on the client or the server. Work done between {@code beginRequest}, {@code endRequest} pairs does not depend on any other - * work done on the connection either as part of another request or outside of any request. A request may include multiple transactions. There may - * be dependencies on committed database state as that is not local to the connection. {@code beginRequest} marks the beginning of the work unit. + * Hints to the driver that a request, an independent unit of work, is beginning on this connection. It backs up the + * values of the connection properties that are modifiable through public methods. Each request is independent of + * all other requests with regard to state local to the connection either on the client or the server. Work done + * between {@code beginRequest}, {@code endRequest} pairs does not depend on any other work done on the connection + * either as part of another request or outside of any request. A request may include multiple transactions. There + * may be dependencies on committed database state as that is not local to the connection. {@code beginRequest} + * marks the beginning of the work unit. *

- * Local state is defined as any state associated with a Connection that is local to the current Connection either in the client or the database - * that is not transparently reproducible. + * Local state is defined as any state associated with a Connection that is local to the current Connection either + * in the client or the database that is not transparently reproducible. *

- * Calls to {@code beginRequest} and {@code endRequest} are not nested. Multiple calls to {@code beginRequest} without an intervening call to - * {@code endRequest} is not an error. The first {@code beginRequest} call marks the start of the request and subsequent calls are treated as a - * no-op It is recommended to enclose each unit of work in {@code beginRequest}, {@code endRequest} pairs such that there is no open transaction - * at the beginning or end of the request and no dependency on local state that crosses request boundaries. Committed database state is not local. + * Calls to {@code beginRequest} and {@code endRequest} are not nested. Multiple calls to {@code beginRequest} + * without an intervening call to {@code endRequest} is not an error. The first {@code beginRequest} call marks the + * start of the request and subsequent calls are treated as a no-op It is recommended to enclose each unit of work + * in {@code beginRequest}, {@code endRequest} pairs such that there is no open transaction at the beginning or end + * of the request and no dependency on local state that crosses request boundaries. Committed database state is not + * local. * * This method is to be used by Connection pooling managers. *

- * The pooling manager should call {@code beginRequest} on the underlying connection prior to returning a connection to the caller. + * The pooling manager should call {@code beginRequest} on the underlying connection prior to returning a connection + * to the caller. *

* * @throws SQLException - * if an error occurs + * if an error occurs * @see #endRequest() */ @Override public void beginRequest() throws SQLException; /** - * Hints to the driver that a request, an independent unit of work, has completed. It rolls back the open transactions. Resets the connection - * properties that are modifiable through public methods back to their original values. Calls to {@code beginRequest} and {@code endRequest} are - * not nested. Multiple calls to {@code endRequest} without an intervening call to {@code beginRequest} is not an error. The first - * {@code endRequest} call marks the request completed and subsequent calls are treated as a no-op. If {@code endRequest} is called without an - * initial call to {@code beginRequest} is a no-op. This method is to be used by Connection pooling managers. + * Hints to the driver that a request, an independent unit of work, has completed. It rolls back the open + * transactions. Resets the connection properties that are modifiable through public methods back to their original + * values. Calls to {@code beginRequest} and {@code endRequest} are not nested. Multiple calls to {@code endRequest} + * without an intervening call to {@code beginRequest} is not an error. The first {@code endRequest} call marks the + * request completed and subsequent calls are treated as a no-op. If {@code endRequest} is called without an initial + * call to {@code beginRequest} is a no-op. This method is to be used by Connection pooling managers. *

* * @throws SQLException - * if an error occurs + * if an error occurs * @see #beginRequest() */ @Override diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerDataRecord.java b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerDataRecord.java index a4ee9f7cd..7c45b8449 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerDataRecord.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerDataRecord.java @@ -1,51 +1,45 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; /** - * This interface can be used to create classes that read in data from any - * source (such as a file) and allow a structured type to be sent to SQL Server - * tables. + * Provides an interface to create classes that read in data from any source (such as a file) and allow a structured + * type to be sent to SQL Server tables. */ public interface ISQLServerDataRecord { - /** - * Get the column meta data - * - * @param column - * the first column is 1, the second is 2, and so on - * @return SQLServerMetaData of column - */ - public SQLServerMetaData getColumnMetaData(int column); + /** + * Returns the column meta data. + * + * @param column + * the first column is 1, the second is 2, and so on + * @return SQLServerMetaData of column + */ + public SQLServerMetaData getColumnMetaData(int column); - /** - * Get the column count. - * - * @return Set of ordinals for the columns. - */ - public int getColumnCount(); + /** + * Returns the column count. + * + * @return Set of ordinals for the columns. + */ + public int getColumnCount(); - /** - * Gets the data for the current row as an array of Objects. - * - * Each Object must match the Java language Type that is used to represent - * the indicated JDBC data type for the given column. For more information, - * see 'Understanding the JDBC Driver Data Types' for the appropriate - * mappings. - * - * @return The data for the row. - */ - public Object[] getRowData(); + /** + * Returns the data for the current row as an array of Objects. + * + * Each Object must match the Java language Type that is used to represent the indicated JDBC data type for the + * given column. For more information, see 'Understanding the JDBC Driver Data Types' for the appropriate mappings. + * + * @return The data for the row. + */ + public Object[] getRowData(); - /** - * Advances to the next data row. - * - * @return True if rows are available; false if there are no more rows - */ - public boolean next(); + /** + * Advances to the next data row. + * + * @return True if rows are available; false if there are no more rows + */ + public boolean next(); } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerDataSource.java b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerDataSource.java index 08168cac1..a0aedb4a5 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerDataSource.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerDataSource.java @@ -1,17 +1,16 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; import org.ietf.jgss.GSSCredential; + /** - * A factory to create connections to the data source represented by this object. This interface was added in SQL Server JDBC Driver 3.0. + * Provides a factory to create connections to the data source represented by this object. This interface was added in + * SQL Server JDBC Driver 3.0. * * This interface is implemented by {@link SQLServerDataSource} Class. */ @@ -21,7 +20,7 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * Sets the application intent. * * @param applicationIntent - * A String that contains the application intent. + * A String that contains the application intent. */ public void setApplicationIntent(String applicationIntent); @@ -36,14 +35,15 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * Sets the application name. * * @param applicationName - * A String that contains the name of the application. + * A String that contains the name of the application. */ public void setApplicationName(String applicationName); /** * Returns the application name. * - * @return A String that contains the application name, or "Microsoft JDBC Driver for SQL Server" if no value is set. + * @return A String that contains the application name, or "Microsoft JDBC Driver for SQL Server" if no value is + * set. */ public String getApplicationName(); @@ -51,7 +51,7 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * Sets the database name to connect to. * * @param databaseName - * A String that contains the database name. + * A String that contains the database name. */ public void setDatabaseName(String databaseName); @@ -66,7 +66,7 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * Sets the SQL Server instance name. * * @param instanceName - * A String that contains the instance name. + * A String that contains the instance name. */ public void setInstanceName(String instanceName); @@ -81,7 +81,7 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * Sets a Boolean value that indicates if the integratedSecurity property is enabled. * * @param enable - * true if integratedSecurity is enabled. Otherwise, false. + * true if integratedSecurity is enabled. Otherwise, false. */ public void setIntegratedSecurity(boolean enable); @@ -89,7 +89,7 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * Sets a Boolean value that indicates if the lastUpdateCount property is enabled. * * @param lastUpdateCount - * true if lastUpdateCount is enabled. Otherwise, false. + * true if lastUpdateCount is enabled. Otherwise, false. */ public void setLastUpdateCount(boolean lastUpdateCount); @@ -104,7 +104,8 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * Sets a Boolean value that indicates if the encrypt property is enabled. * * @param encrypt - * true if the Secure Sockets Layer (SSL) encryption is enabled between the client and the SQL Server. Otherwise, false. + * true if the Secure Sockets Layer (SSL) encryption is enabled between the client and the SQL Server. + * Otherwise, false. */ public void setEncrypt(boolean encrypt); @@ -116,11 +117,12 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { public boolean getEncrypt(); /** - * Beginning in version 6.0 of the Microsoft JDBC Driver for SQL Server, a new connection property transparentNetworkIPResolution (TNIR) is added - * for transparent connection to Always On availability groups or to a server which has multiple IP addresses associated. When - * transparentNetworkIPResolution is true, the driver attempts to connect to the first IP address available. If the first attempt fails, the - * driver tries to connect to all IP addresses in parallel until the timeout expires, discarding any pending connection attempts when one of them - * succeeds. + * Sets the value to enable/disable Transparent Netowrk IP Resolution (TNIR). Beginning in version 6.0 of the + * Microsoft JDBC Driver for SQL Server, a new connection property transparentNetworkIPResolution (TNIR) is added + * for transparent connection to Always On availability groups or to a server which has multiple IP addresses + * associated. When transparentNetworkIPResolution is true, the driver attempts to connect to the first IP address + * available. If the first attempt fails, the driver tries to connect to all IP addresses in parallel until the + * timeout expires, discarding any pending connection attempts when one of them succeeds. *

* transparentNetworkIPResolution is ignored if multiSubnetFailover is true *

@@ -129,12 +131,12 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * transparentNetworkIPResolution is ignored if there are more than 64 IP addresses * * @param tnir - * if set to true, the driver attempts to connect to the first IP address available. It is true by default. + * if set to true, the driver attempts to connect to the first IP address available. It is true by default. */ public void setTransparentNetworkIPResolution(boolean tnir); /** - * Retrieves the TransparentNetworkIPResolution value. + * Returns the TransparentNetworkIPResolution value. * * @return if enabled, returns true. Otherwise, false. */ @@ -144,8 +146,8 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * Sets a Boolean value that indicates if the trustServerCertificate property is enabled. * * @param e - * true, if the server Secure Sockets Layer (SSL) certificate should be automatically trusted when the communication layer is encrypted - * using SSL. Otherwise, false. + * true, if the server Secure Sockets Layer (SSL) certificate should be automatically trusted when the + * communication layer is encrypted using SSL. Otherwise, false. */ public void setTrustServerCertificate(boolean e); @@ -157,15 +159,15 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { public boolean getTrustServerCertificate(); /** - * This parameter defines the keystore type for the trustStore. + * Sets the keystore type for the trustStore. * * @param trustStoreType - * A String that contains the trust store type + * A String that contains the trust store type */ public void setTrustStoreType(String trustStoreType); /** - * Returns the keyStore Type for the trustStore + * Returns the keyStore Type for the trustStore. * * @return trustStoreType A String that contains the trust store type */ @@ -175,14 +177,15 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * Sets the path (including file name) to the certificate trustStore file. * * @param trustStore - * A String that contains the path (including file name) to the certificate trustStore file. + * A String that contains the path (including file name) to the certificate trustStore file. */ public void setTrustStore(String trustStore); /** * Returns the path (including file name) to the certificate trustStore file. * - * @return trustStore A String that contains the path (including file name) to the certificate trustStore file, or null if no value is set. + * @return trustStore A String that contains the path (including file name) to the certificate trustStore file, or + * null if no value is set. */ public String getTrustStore(); @@ -190,7 +193,7 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * Sets the password that is used to check the integrity of the trustStore data. * * @param trustStorePassword - * A String that contains the password that is used to check the integrity of the trustStore data. + * A String that contains the password that is used to check the integrity of the trustStore data. */ public void setTrustStorePassword(String trustStorePassword); @@ -198,7 +201,7 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * Sets the host name to be used in validating the SQL Server Secure Sockets Layer (SSL) certificate. * * @param hostName - * A String that contains the host name. + * A String that contains the host name. */ public void setHostNameInCertificate(String hostName); @@ -213,12 +216,13 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * Sets an int value that indicates the number of milliseconds to wait before the database reports a lock time out. * * @param lockTimeout - * An int value that contains the number of milliseconds to wait. + * An int value that contains the number of milliseconds to wait. */ public void setLockTimeout(int lockTimeout); /** - * Returns an int value that indicates the number of milliseconds that the database will wait before reporting a lock time out. + * Returns an int value that indicates the number of milliseconds that the database will wait before reporting a + * lock time out. * * @return An int value that contains the number of milliseconds that the database will wait. */ @@ -228,7 +232,7 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * Sets the password that will be used to connect to SQL Server. * * @param password - * A String that contains the password. + * A String that contains the password. */ public void setPassword(String password); @@ -236,7 +240,7 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * Sets the port number to be used to communicate with SQL Server. * * @param portNumber - * An int value that contains the port number. + * An int value that contains the port number. */ public void setPortNumber(int portNumber); @@ -248,15 +252,17 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { public int getPortNumber(); /** - * Sets the default cursor type that is used for all result sets that are created by using this SQLServerDataSource object. + * Sets the default cursor type that is used for all result sets that are created by using this SQLServerDataSource + * object. * * @param selectMethod - * A String value that contains the default cursor type. + * A String value that contains the default cursor type. */ public void setSelectMethod(String selectMethod); /** - * Returns the default cursor type used for all result sets that are created by using this SQLServerDataSource object. + * Returns the default cursor type used for all result sets that are created by using this SQLServerDataSource + * object. * * @return A String value that contains the default cursor type. */ @@ -266,8 +272,8 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * Sets the response buffering mode for connections created by using this SQLServerDataSource object. * * @param bufferingMode - * A String that contains the buffering and streaming mode. The valid mode can be one of the following case-insensitive Strings: full - * or adaptive. + * A String that contains the buffering and streaming mode. The valid mode can be one of the following + * case-insensitive Strings: full or adaptive. */ public void setResponseBuffering(String bufferingMode); @@ -279,19 +285,20 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { public String getResponseBuffering(); /** - * Modifies the setting of the sendTimeAsDatetime connection property. + * Sets the value to enable/disable the sendTimeAsDatetime connection property. * * @param sendTimeAsDatetime - * A Boolean value. When true, causes java.sql.Time values to be sent to the server as SQL Server datetime types. When false, causes - * java.sql.Time values to be sent to the server as SQL Server time types. + * A Boolean value. When true, causes java.sql.Time values to be sent to the server as SQL Server datetime + * types. When false, causes java.sql.Time values to be sent to the server as SQL Server time types. */ public void setSendTimeAsDatetime(boolean sendTimeAsDatetime); /** - * This method was added in SQL Server JDBC Driver 3.0. Returns the setting of the sendTimeAsDatetime connection property. + * Returns the value of the sendTimeAsDatetime connection property. This method was added in SQL Server JDBC Driver + * 3.0. Returns the setting of the sendTimeAsDatetime connection property. * - * @return true if java.sql.Time values will be sent to the server as a SQL Server datetime type. false if java.sql.Time values will be sent to - * the server as a SQL Server time type. + * @return true if java.sql.Time values will be sent to the server as a SQL Server datetime type. false if + * java.sql.Time values will be sent to the server as a SQL Server time type. */ public boolean getSendTimeAsDatetime(); @@ -299,27 +306,27 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * Sets a boolean value that indicates if sending string parameters to the server in UNICODE format is enabled. * * @param sendStringParametersAsUnicode - * true if string parameters are sent to the server in UNICODE format. Otherwise, false. + * true if string parameters are sent to the server in UNICODE format. Otherwise, false. */ public void setSendStringParametersAsUnicode(boolean sendStringParametersAsUnicode); /** - * Returns a boolean value that indicates if sending string parameters to the server in UNICODE format is enabled. + * Returns whether sending string parameters to the server in UNICODE format is enabled. * * @return true if string parameters are sent to the server in UNICODE format. Otherwise, false. */ public boolean getSendStringParametersAsUnicode(); /** - * Translates the serverName from Unicode to ASCII Compatible Encoding (ACE) + * Sets whether the serverName will be translated from Unicode to ASCII Compatible Encoding (ACE). * * @param serverNameAsACE - * if enabled the servername will be translated to ASCII Compatible Encoding (ACE) + * if enabled the servername will be translated to ASCII Compatible Encoding (ACE) */ public void setServerNameAsACE(boolean serverNameAsACE); /** - * Retrieves if the serverName should be translated from Unicode to ASCII Compatible Encoding (ACE) + * Returns if the serverName should be translated from Unicode to ASCII Compatible Encoding (ACE). * * @return if enabled, will return true. Otherwise, false. */ @@ -329,7 +336,7 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * Sets the name of the computer that is running SQL Server. * * @param serverName - * A String that contains the server name. + * A String that contains the server name. */ public void setServerName(String serverName); @@ -344,7 +351,7 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * Sets the name of the failover server that is used in a database mirroring configuration. * * @param serverName - * A String that contains the failover server name. + * A String that contains the failover server name. */ public void setFailoverPartner(String serverName); @@ -359,7 +366,7 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * Sets the value of the multiSubnetFailover connection property. * * @param multiSubnetFailover - * The new value of the multiSubnetFailover connection property. + * The new value of the multiSubnetFailover connection property. */ public void setMultiSubnetFailover(boolean multiSubnetFailover); @@ -374,7 +381,7 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * Sets the user name that is used to connect the data source. * * @param user - * A String that contains the user name. + * A String that contains the user name. */ public void setUser(String user); @@ -389,7 +396,7 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * Sets the name of the client computer name that is used to connect to the data source. * * @param workstationID - * A String that contains the client computer name. + * A String that contains the client computer name. */ public void setWorkstationID(String workstationID); @@ -401,15 +408,15 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { public String getWorkstationID(); /** - * Sets a Boolean value that indicates if converting SQL states to XOPEN compliant states is enabled. + * Sets whether converting SQL states to XOPEN compliant states is enabled. * * @param xopenStates - * true if converting SQL states to XOPEN compliant states is enabled. Otherwise, false. + * true if converting SQL states to XOPEN compliant states is enabled. Otherwise, false. */ public void setXopenStates(boolean xopenStates); /** - * Returns a boolean value that indicates if converting SQL states to XOPEN compliant states is enabled. + * Returns the value that indicates if converting SQL states to XOPEN compliant states is enabled. * * @return true if converting SQL states to XOPEN compliant states is enabled. Otherwise, false. */ @@ -419,7 +426,7 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * Sets the URL that is used to connect to the data source. * * @param url - * A String that contains the URL. + * A String that contains the URL. */ public void setURL(String url); @@ -434,7 +441,7 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * Sets the description of the data source. * * @param description - * A String that contains the description. + * A String that contains the description. */ public void setDescription(String description); @@ -449,7 +456,7 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * Sets the current network packet size used to communicate with SQL Server, specified in bytes. * * @param packetSize - * An int value containing the network packet size. + * An int value containing the network packet size. */ public void setPacketSize(int packetSize); @@ -461,53 +468,53 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { public int getPacketSize(); /** - * Indicates the kind of integrated security you want your application to use. + * Sets the kind of integrated security you want your application to use. * * @param authenticationScheme - * Values are "JavaKerberos" and the default "NativeAuthentication". + * Values are "JavaKerberos" and the default "NativeAuthentication". */ public void setAuthenticationScheme(String authenticationScheme); /** - * sets the authentication mode + * Sets the authentication mode. * * @param authentication - * the authentication mode + * the authentication mode */ public void setAuthentication(String authentication); /** - * Retrieves the authentication mode + * Returns the authentication mode. * * @return the authentication value */ public String getAuthentication(); /** - * Sets the server spn + * Sets the server spn. * * @param serverSpn - * A String that contains the server spn + * A String that contains the server spn */ public void setServerSpn(String serverSpn); /** - * Returns the server spn + * Returns the server spn. * * @return A String that contains the server spn */ public String getServerSpn(); /** - * sets GSSCredential + * Sets the GSSCredential. * * @param userCredential - * the credential + * the credential */ public void setGSSCredentials(GSSCredential userCredential); /** - * Retrieves the GSSCredential + * Returns the GSSCredential. * * @return GSSCredential */ @@ -517,147 +524,153 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * Sets the access token. * * @param accessToken - * to be set in the string property. + * to be set in the string property. */ public void setAccessToken(String accessToken); /** - * Retrieves the access token. + * Returns the access token. * * @return the access token. */ public String getAccessToken(); /** - * Enables/disables Always Encrypted functionality for the data source object. The default is Disabled. + * Sets the value to enable/disable Always Encrypted functionality for the data source object. The default is + * Disabled. * * @param columnEncryptionSetting - * Enables/disables Always Encrypted functionality for the data source object. The default is Disabled. + * Enables/disables Always Encrypted functionality for the data source object. The default is Disabled. */ public void setColumnEncryptionSetting(String columnEncryptionSetting); /** - * Retrieves the Always Encrypted functionality setting for the data source object. + * Returns the Always Encrypted functionality setting for the data source object. * * @return the Always Encrypted functionality setting for the data source object. */ public String getColumnEncryptionSetting(); /** - * Sets the name that identifies a key store. Only value supported is the "JavaKeyStorePassword" for identifying the Java Key Store. The default - * is null. + * Sets the name that identifies a key store. Only value supported is the "JavaKeyStorePassword" for identifying the + * Java Key Store. The default is null. * * @param keyStoreAuthentication - * the name that identifies a key store. + * the name that identifies a key store. */ public void setKeyStoreAuthentication(String keyStoreAuthentication); /** - * Gets the value of the keyStoreAuthentication setting for the data source object. + * Returns the value of the keyStoreAuthentication setting for the data source object. * * @return the value of the keyStoreAuthentication setting for the data source object. */ public String getKeyStoreAuthentication(); /** - * Sets the password for the Java keystore. Note that, for Java Key Store provider the password for the keystore and the key must be the same. - * Note that, keyStoreAuthentication must be set with "JavaKeyStorePassword". + * Sets the password for the Java keystore. Note that, for Java Key Store provider the password for the keystore and + * the key must be the same. Note that, keyStoreAuthentication must be set with "JavaKeyStorePassword". * * @param keyStoreSecret - * the password to use for the keystore as well as for the key + * the password to use for the keystore as well as for the key */ public void setKeyStoreSecret(String keyStoreSecret); /** - * Sets the location including the file name for the Java keystore. Note that, keyStoreAuthentication must be set with "JavaKeyStorePassword". + * Sets the location including the file name for the Java keystore. Note that, keyStoreAuthentication must be set + * with "JavaKeyStorePassword". * * @param keyStoreLocation - * the location including the file name for the Java keystore. + * the location including the file name for the Java keystore. */ public void setKeyStoreLocation(String keyStoreLocation); /** - * Retrieves the keyStoreLocation for the Java Key Store. + * Returns the keyStoreLocation for the Java Key Store. * * @return the keyStoreLocation for the Java Key Store. */ public String getKeyStoreLocation(); /** - * Setting the query timeout + * Setting the query timeout. * * @param queryTimeout - * The number of seconds to wait before a timeout has occurred on a query. The default value is 0, which means infinite timeout. + * The number of seconds to wait before a timeout has occurred on a query. The default value is 0, which + * means infinite timeout. */ public void setQueryTimeout(int queryTimeout); /** - * Getting the query timeout + * Returns the query timeout. * * @return The number of seconds to wait before a timeout has occurred on a query. */ public int getQueryTimeout(); /** - * Setting the cancel timeout + * Sets the cancel timeout. * * @param cancelQueryTimeout - * The number of seconds to wait before we wait for the query timeout to happen. + * The number of seconds to wait before we wait for the query timeout to happen. */ public void setCancelQueryTimeout(int cancelQueryTimeout); /** - * Getting the cancel timeout + * Returns the cancel timeout. * * @return the number of seconds to wait before we wait for the query timeout to happen. */ public int getCancelQueryTimeout(); /** - * If this configuration is false the first execution of a prepared statement will call sp_executesql and not prepare a statement, once the second - * execution happens it will call sp_prepexec and actually setup a prepared statement handle. Following executions will call sp_execute. This - * relieves the need for sp_unprepare on prepared statement close if the statement is only executed once. + * Sets the value that enables/disables whether the first execution of a prepared statement will call sp_executesql + * and not prepare a statement. If this configuration is false the first execution of a prepared statement will call + * sp_executesql and not prepare a statement, once the second execution happens it will call sp_prepexec and + * actually setup a prepared statement handle. Following executions will call sp_execute. This relieves the need for + * sp_unprepare on prepared statement close if the statement is only executed once. * * @param enablePrepareOnFirstPreparedStatementCall - * Changes the setting per the description. + * Changes the setting per the description. */ public void setEnablePrepareOnFirstPreparedStatementCall(boolean enablePrepareOnFirstPreparedStatementCall); /** - * If this configuration returns false the first execution of a prepared statement will call sp_executesql and not prepare a statement, once the - * second execution happens it will call sp_prepexec and actually setup a prepared statement handle. Following executions will call sp_execute. - * This relieves the need for sp_unprepare on prepared statement close if the statement is only executed once. + * Returns the value that indicates whether the first execution of a prepared statement will call sp_executesql and + * not prepare a statement. If this configuration returns false the first execution of a prepared statement will + * call sp_executesql and not prepare a statement, once the second execution happens it will call sp_prepexec and + * actually setup a prepared statement handle. Following executions will call sp_execute. This relieves the need for + * sp_unprepare on prepared statement close if the statement is only executed once. * * @return Returns the current setting per the description. */ public boolean getEnablePrepareOnFirstPreparedStatementCall(); /** - * This setting controls how many outstanding prepared statement discard actions (sp_unprepare) can be outstanding per connection before a call to - * clean-up the outstanding handles on the server is executed. If the setting is {@literal <=} 1 unprepare actions will be executed immedietely on - * prepared statement close. If it is set to {@literal >} 1 these calls will be batched together to avoid overhead of calling sp_unprepare too - * often. + * Sets the value that controls how many outstanding prepared statement discard actions (sp_unprepare) can be + * outstanding per connection before a call to clean-up the outstanding handles on the server is executed. If the + * setting is {@literal <=} 1 unprepare actions will be executed immedietely on prepared statement close. If it is + * set to {@literal >} 1 these calls will be batched together to avoid overhead of calling sp_unprepare too often. * * @param serverPreparedStatementDiscardThreshold - * Changes the setting per the description. + * Changes the setting per the description. */ public void setServerPreparedStatementDiscardThreshold(int serverPreparedStatementDiscardThreshold); /** - * This setting controls how many outstanding prepared statement discard actions (sp_unprepare) can be outstanding per connection before a call to - * clean-up the outstanding handles on the server is executed. If the setting is {@literal <=} 1 unprepare actions will be executed immedietely on - * prepared statement close. If it is set to {@literal >} 1 these calls will be batched together to avoid overhead of calling sp_unprepare too - * often. + * Returns the value of the setting that controls how many outstanding prepared statement discard actions + * (sp_unprepare) can be outstanding per connection before a call to clean-up the outstanding handles on the server + * is executed. * * @return Returns the current setting per the description. */ public int getServerPreparedStatementDiscardThreshold(); /** - * Specifies the size of the prepared statement cache for this connection. A value less than 1 means no cache. + * Sets the size of the prepared statement cache for this connection. A value less than 1 means no cache. * * @param statementPoolingCacheSize - * Changes the setting per the description. + * Changes the setting per the description. */ public void setStatementPoolingCacheSize(int statementPoolingCacheSize); @@ -669,61 +682,63 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { public int getStatementPoolingCacheSize(); /** - * Disable/enable statement pooling. + * Sets the value to disable/enable statement pooling. * * @param disableStatementPooling - * true to disable statement pooling, false to enable it. + * true to disable statement pooling, false to enable it. */ public void setDisableStatementPooling(boolean disableStatementPooling); /** - * Determine whether statement pooling is disabled. + * Returns whether statement pooling is disabled. * * @return true if statement pooling is disabled, false if it is enabled. */ public boolean getDisableStatementPooling(); /** - * Setting the socket timeout + * Sets the socket timeout value. * * @param socketTimeout - * The number of milliseconds to wait before a timeout is occurred on a socket read or accept. The default value is 0, which means - * infinite timeout. + * The number of milliseconds to wait before a timeout is occurred on a socket read or accept. The default + * value is 0, which means infinite timeout. */ public void setSocketTimeout(int socketTimeout); /** - * Getting the socket timeout + * Returns the socket timeout value. * * @return The number of milliseconds to wait before a timeout is occurred on a socket read or accept. */ public int getSocketTimeout(); /** - * Sets the login configuration file for Kerberos authentication. This overrides the default configuration SQLJDBCDriver + * Sets the login configuration file for Kerberos authentication. This overrides the default configuration + * SQLJDBCDriver * * @param configurationName - * the configuration name + * the configuration name */ public void setJASSConfigurationName(String configurationName); /** - * Retrieves the login configuration file for Kerberos authentication. + * Returns the login configuration file for Kerberos authentication. * * @return login configuration file name */ public String getJASSConfigurationName(); /** - * Enables Fips Mode on the connection For FIPS enabled JVM this property should be true. + * Sets whether Fips Mode should be enabled/disabled on the connection. For FIPS enabled JVM this property should be + * true. * * @param fips - * Boolean property to enable/disable fips + * Boolean property to enable/disable fips */ public void setFIPS(boolean fips); /** - * Retrieves value of connection property "fips" For FIPS enabled JVM this property should be true. + * Returns the value of connection property "fips". For FIPS enabled JVM this property should be true. * * @return fips boolean value */ @@ -735,59 +750,59 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * Acceptable values are: TLS, TLSv1, TLSv1.1, and TLSv1.2. * * @param sslProtocol - * Value for SSL Protocol to be set. + * Value for SSL Protocol to be set. */ public void setSSLProtocol(String sslProtocol); /** - * Retrieves value of connection property 'sslProtocol' + * Returns the value of connection property 'sslProtocol'. * * @return sslProtocol property value */ public String getSSLProtocol(); /** - * Sets the connection property 'trustManagerClass' on the connection + * Sets the connection property 'trustManagerClass' on the connection. * * @param trustManagerClass - * The fully qualified class name of a custom javax.net.ssl.TrustManager. + * The fully qualified class name of a custom javax.net.ssl.TrustManager. */ public void setTrustManagerClass(String trustManagerClass); /** - * Retrieves value for the connection property 'trustManagerClass' + * Returns the value for the connection property 'trustManagerClass'. * * @return trustManagerClass property value */ public String getTrustManagerClass(); /** - * Sets Constructor Arguments to be provided on constructor of 'trustManagerClass' + * Sets Constructor Arguments to be provided on constructor of 'trustManagerClass'. * * @param trustManagerConstructorArg - * 'trustManagerClass' constructor arguments + * 'trustManagerClass' constructor arguments */ public void setTrustManagerConstructorArg(String trustManagerConstructorArg); /** - * Retrieves value for the connection property 'trustManagerConstructorArg' + * Returns the value for the connection property 'trustManagerConstructorArg'. * * @return trustManagerConstructorArg property value */ public String getTrustManagerConstructorArg(); /** - * Getting the use Bulk Copy API for Batch Insert + * Returns whether the use Bulk Copy API is used for Batch Insert. * * @return whether the driver should use Bulk Copy API for Batch Insert operations. */ public boolean getUseBulkCopyForBatchInsert(); /** - * Setting the use Bulk Copy API for Batch Insert + * Sets whether the use Bulk Copy API should be used for Batch Insert. * * @param useBulkCopyForBatchInsert - * indicates whether Bulk Copy API should be used for Batch Insert operations. + * indicates whether Bulk Copy API should be used for Batch Insert operations. */ public void setUseBulkCopyForBatchInsert(boolean useBulkCopyForBatchInsert); } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerPreparedStatement.java b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerPreparedStatement.java index 17fc6b558..187d20821 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerPreparedStatement.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerPreparedStatement.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -13,83 +10,78 @@ import java.sql.ResultSet; import java.sql.SQLType; + /** - * This interface is implemented by {@link SQLServerPreparedStatement} class. + * Provides an interface to the {@link SQLServerPreparedStatement} class. */ public interface ISQLServerPreparedStatement extends java.sql.PreparedStatement, ISQLServerStatement { /** * Sets the designated parameter to the given microsoft.sql.DateTimeOffset value. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the parameter value + * the parameter value * @throws SQLServerException - * if parameterIndex does not correspond to a parameter marker in the SQL statement; if a database access error occurs or this method - * is called on a closed PreparedStatement + * if parameterIndex does not correspond to a parameter marker in the SQL statement; if a database access + * error occurs or this method is called on a closed PreparedStatement */ - public void setDateTimeOffset(int parameterIndex, - microsoft.sql.DateTimeOffset x) throws SQLServerException; + public void setDateTimeOffset(int parameterIndex, microsoft.sql.DateTimeOffset x) throws SQLServerException; /** * Sets the value of the designated parameter with the given object. * - * This method is similar to {@link #setObject(int parameterIndex, Object x, SQLType targetSqlType, int scaleOrLength)}, except that it assumes a - * scale of zero. + * This method is similar to + * {@link #setObject(int parameterIndex, Object x, SQLType targetSqlType, int scaleOrLength)}, except that it + * assumes a scale of zero. *

* The default implementation will throw {@code SQLFeatureNotSupportedException} * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the object containing the input parameter value + * the object containing the input parameter value * @param targetSqlType - * the SQL type to be sent to the database + * the SQL type to be sent to the database * @param precision - * the precision of the column + * the precision of the column * @param scale - * the scale of the column + * the scale of the column * @throws SQLServerException - * if parameterIndex does not correspond to a parameter marker in the SQL statement; if a database access error occurs or this method - * is called on a closed {@code PreparedStatement} + * if parameterIndex does not correspond to a parameter marker in the SQL statement; if a database access + * error occurs or this method is called on a closed {@code PreparedStatement} */ - public void setObject(int parameterIndex, - Object x, - SQLType targetSqlType, - Integer precision, + public void setObject(int parameterIndex, Object x, SQLType targetSqlType, Integer precision, Integer scale) throws SQLServerException; /** * Sets the value of the designated parameter with the given object. * - * This method is similar to {@link #setObject(int parameterIndex, Object x, SQLType targetSqlType, int scaleOrLength)}, except that it assumes a - * scale of zero. + * This method is similar to + * {@link #setObject(int parameterIndex, Object x, SQLType targetSqlType, int scaleOrLength)}, except that it + * assumes a scale of zero. *

* The default implementation will throw {@code SQLFeatureNotSupportedException} * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the object containing the input parameter value + * the object containing the input parameter value * @param targetSqlType - * the SQL type to be sent to the database + * the SQL type to be sent to the database * @param precision - * the precision of the column + * the precision of the column * @param scale - * the scale of the column + * the scale of the column * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. - * @throws SQLServerException - * if parameterIndex does not correspond to a parameter marker in the SQL statement; if a database access error occurs or this method - * is called on a closed {@code PreparedStatement} - */ - public void setObject(int parameterIndex, - Object x, - SQLType targetSqlType, - Integer precision, - Integer scale, + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. + * @throws SQLServerException + * if parameterIndex does not correspond to a parameter marker in the SQL statement; if a database access + * error occurs or this method is called on a closed {@code PreparedStatement} + */ + public void setObject(int parameterIndex, Object x, SQLType targetSqlType, Integer precision, Integer scale, boolean forceEncrypt) throws SQLServerException; /** @@ -97,745 +89,677 @@ public void setObject(int parameterIndex, * * @return Per the description. * @throws SQLServerException - * when an error occurs + * when an error occurs */ public int getPreparedStatementHandle() throws SQLServerException; /** - * Sets the designated parameter to the given java.math.BigDecimal value. The driver converts this to an SQL NUMERIC - * value when it sends it to the database. + * Sets the designated parameter to the given java.math.BigDecimal value. The driver converts this to + * an SQL NUMERIC value when it sends it to the database. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the parameter value + * the parameter value * @param precision - * the precision of the column + * the precision of the column * @param scale - * the scale of the column + * the scale of the column * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setBigDecimal(int parameterIndex, - BigDecimal x, - int precision, - int scale) throws SQLServerException; + public void setBigDecimal(int parameterIndex, BigDecimal x, int precision, int scale) throws SQLServerException; /** - * Sets the designated parameter to the given java.math.BigDecimal value. The driver converts this to an SQL NUMERIC - * value when it sends it to the database. + * Sets the designated parameter to the given java.math.BigDecimal value. The driver converts this to + * an SQL NUMERIC value when it sends it to the database. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the parameter value + * the parameter value * @param precision - * the precision of the column + * the precision of the column * @param scale - * the scale of the column + * the scale of the column * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setBigDecimal(int parameterIndex, - BigDecimal x, - int precision, - int scale, + public void setBigDecimal(int parameterIndex, BigDecimal x, int precision, int scale, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given java.math.BigDecimal value. The driver converts this to an SQL NUMERIC - * value when it sends it to the database. + * Sets the designated parameter to the given java.math.BigDecimal value. The driver converts this to + * an SQL NUMERIC value when it sends it to the database. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the parameter value + * the parameter value * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setMoney(int parameterIndex, - BigDecimal x) throws SQLServerException; + public void setMoney(int parameterIndex, BigDecimal x) throws SQLServerException; /** - * Sets the designated parameter to the given java.math.BigDecimal value. The driver converts this to an SQL NUMERIC - * value when it sends it to the database. + * Sets the designated parameter to the given java.math.BigDecimal value. The driver converts this to + * an SQL NUMERIC value when it sends it to the database. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the parameter value + * the parameter value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setMoney(int parameterIndex, - BigDecimal x, - boolean forceEncrypt) throws SQLServerException; + public void setMoney(int parameterIndex, BigDecimal x, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given java.math.BigDecimal value. The driver converts this to an SQL NUMERIC - * value when it sends it to the database. + * Sets the designated parameter to the given java.math.BigDecimal value. The driver converts this to + * an SQL NUMERIC value when it sends it to the database. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the parameter value + * the parameter value * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setSmallMoney(int parameterIndex, - BigDecimal x) throws SQLServerException; + public void setSmallMoney(int parameterIndex, BigDecimal x) throws SQLServerException; /** - * Sets the designated parameter to the given java.math.BigDecimal value. The driver converts this to an SQL NUMERIC - * value when it sends it to the database. + * Sets the designated parameter to the given java.math.BigDecimal value. The driver converts this to + * an SQL NUMERIC value when it sends it to the database. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the parameter value + * the parameter value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setSmallMoney(int parameterIndex, - BigDecimal x, - boolean forceEncrypt) throws SQLServerException; + public void setSmallMoney(int parameterIndex, BigDecimal x, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given Java boolean value. The driver converts this to an SQL BIT or - * BOOLEAN value when it sends it to the database. + * Sets the designated parameter to the given Java boolean value. The driver converts this to an SQL + * BIT or BOOLEAN value when it sends it to the database. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the parameter value + * the parameter value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setBoolean(int parameterIndex, - boolean x, - boolean forceEncrypt) throws SQLServerException; + public void setBoolean(int parameterIndex, boolean x, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given Java byte value. The driver converts this to an SQL TINYINT value when it - * sends it to the database. + * Sets the designated parameter to the given Java byte value. The driver converts this to an SQL + * TINYINT value when it sends it to the database. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the parameter value + * the parameter value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setByte(int parameterIndex, - byte x, - boolean forceEncrypt) throws SQLServerException; + public void setByte(int parameterIndex, byte x, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given Java array of bytes. The driver converts this to an SQL VARBINARY or - * LONGVARBINARY (depending on the argument's size relative to the driver's limits on VARBINARY values) when it sends it - * to the database. + * Sets the designated parameter to the given Java array of bytes. The driver converts this to an SQL + * VARBINARY or LONGVARBINARY (depending on the argument's size relative to the driver's + * limits on VARBINARY values) when it sends it to the database. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the parameter value + * the parameter value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setBytes(int parameterIndex, - byte x[], - boolean forceEncrypt) throws SQLServerException; + public void setBytes(int parameterIndex, byte x[], boolean forceEncrypt) throws SQLServerException; /** * Sets the designated parameter to the given String. The driver converts this to an SQL GUID * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param guid - * string representation of the uniqueIdentifier value + * string representation of the uniqueIdentifier value * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setUniqueIdentifier(int parameterIndex, - String guid) throws SQLServerException; + public void setUniqueIdentifier(int parameterIndex, String guid) throws SQLServerException; /** * Sets the designated parameter to the given String. The driver converts this to an SQL GUID * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param guid - * string representation of the uniqueIdentifier value + * string representation of the uniqueIdentifier value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setUniqueIdentifier(int parameterIndex, - String guid, - boolean forceEncrypt) throws SQLServerException; + public void setUniqueIdentifier(int parameterIndex, String guid, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given Java double value. The driver converts this to an SQL DOUBLE value when it - * sends it to the database. + * Sets the designated parameter to the given Java double value. The driver converts this to an SQL + * DOUBLE value when it sends it to the database. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the parameter value + * the parameter value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setDouble(int parameterIndex, - double x, - boolean forceEncrypt) throws SQLServerException; + public void setDouble(int parameterIndex, double x, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given Java float value. The driver converts this to an SQL REAL value when it - * sends it to the database. + * Sets the designated parameter to the given Java float value. The driver converts this to an SQL + * REAL value when it sends it to the database. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the parameter value + * the parameter value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setFloat(int parameterIndex, - float x, - boolean forceEncrypt) throws SQLServerException; + public void setFloat(int parameterIndex, float x, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given microsoft.sql.Geometry Class object. The driver converts this to an SQL - * REAL value when it sends it to the database. + * Sets the designated parameter to the given microsoft.sql.Geometry Class object. The driver converts + * this to an SQL REAL value when it sends it to the database. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the parameter value + * the parameter value * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setGeometry(int parameterIndex, - Geometry x) throws SQLServerException; + public void setGeometry(int parameterIndex, Geometry x) throws SQLServerException; /** - * Sets the designated parameter to the given microsoft.sql.Geography Class object. The driver converts this to an SQL - * REAL value when it sends it to the database. + * Sets the designated parameter to the given microsoft.sql.Geography Class object. The driver converts + * this to an SQL REAL value when it sends it to the database. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the parameter value + * the parameter value * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setGeography(int parameterIndex, - Geography x) throws SQLServerException; + public void setGeography(int parameterIndex, Geography x) throws SQLServerException; /** - * Sets the designated parameter to the given Java int value. The driver converts this to an SQL INTEGER value when it - * sends it to the database. + * Sets the designated parameter to the given Java int value. The driver converts this to an SQL + * INTEGER value when it sends it to the database. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param value - * the parameter value + * the parameter value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setInt(int parameterIndex, - int value, - boolean forceEncrypt) throws SQLServerException; + public void setInt(int parameterIndex, int value, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given Java long value. The driver converts this to an SQL BIGINT value when it - * sends it to the database. + * Sets the designated parameter to the given Java long value. The driver converts this to an SQL + * BIGINT value when it sends it to the database. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the parameter value + * the parameter value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setLong(int parameterIndex, - long x, - boolean forceEncrypt) throws SQLServerException; + public void setLong(int parameterIndex, long x, boolean forceEncrypt) throws SQLServerException; /** - *

* Sets the value of the designated parameter with the given object. * *

* The given Java object will be converted to the given targetSqlType before being sent to the database. * - * If the object has a custom mapping (is of a class implementing the interface SQLData), the JDBC driver should call the method - * SQLData.writeSQL to write it to the SQL data stream. If, on the other hand, the object is of a class implementing - * Ref, Blob, Clob, NClob, Struct, java.net.URL, or - * Array, the driver should pass it to the database as a value of the corresponding SQL type. + * If the object has a custom mapping (is of a class implementing the interface SQLData), the JDBC + * driver should call the method SQLData.writeSQL to write it to the SQL data stream. If, on the other + * hand, the object is of a class implementing Ref, Blob, Clob, + * NClob, Struct, java.net.URL, or Array, the driver should pass + * it to the database as a value of the corresponding SQL type. * *

* Note that this method may be used to pass database-specific abstract data types. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the object containing the input parameter value + * the object containing the input parameter value * @param targetSqlType - * the SQL type (as defined in java.sql.Types) to be sent to the database. The scale argument may further qualify this type. + * the SQL type (as defined in java.sql.Types) to be sent to the database. The scale argument may further + * qualify this type. * @param precision - * the precision of the column + * the precision of the column * @param scale - * scale of the column + * scale of the column * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setObject(int parameterIndex, - Object x, - int targetSqlType, - Integer precision, + public void setObject(int parameterIndex, Object x, int targetSqlType, Integer precision, int scale) throws SQLServerException; /** - *

* Sets the value of the designated parameter with the given object. * *

* The given Java object will be converted to the given targetSqlType before being sent to the database. * - * If the object has a custom mapping (is of a class implementing the interface SQLData), the JDBC driver should call the method - * SQLData.writeSQL to write it to the SQL data stream. If, on the other hand, the object is of a class implementing - * Ref, Blob, Clob, NClob, Struct, java.net.URL, or - * Array, the driver should pass it to the database as a value of the corresponding SQL type. + * If the object has a custom mapping (is of a class implementing the interface SQLData), the JDBC + * driver should call the method SQLData.writeSQL to write it to the SQL data stream. If, on the other + * hand, the object is of a class implementing Ref, Blob, Clob, + * NClob, Struct, java.net.URL, or Array, the driver should pass + * it to the database as a value of the corresponding SQL type. * *

* Note that this method may be used to pass database-specific abstract data types. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the object containing the input parameter value + * the object containing the input parameter value * @param targetSqlType - * the SQL type (as defined in java.sql.Types) to be sent to the database. The scale argument may further qualify this type. + * the SQL type (as defined in java.sql.Types) to be sent to the database. The scale argument may further + * qualify this type. * @param precision - * the precision of the column + * the precision of the column * @param scale - * scale of the column + * scale of the column * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setObject(int parameterIndex, - Object x, - int targetSqlType, - Integer precision, - int scale, + public void setObject(int parameterIndex, Object x, int targetSqlType, Integer precision, int scale, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given Java short value. The driver converts this to an SQL SMALLINT value when - * it sends it to the database. + * Sets the designated parameter to the given Java short value. The driver converts this to an SQL + * SMALLINT value when it sends it to the database. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the parameter value + * the parameter value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setShort(int parameterIndex, - short x, - boolean forceEncrypt) throws SQLServerException; + public void setShort(int parameterIndex, short x, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given Java String value. The driver converts this to an SQL VARCHAR or - * LONGVARCHAR value (depending on the argument's size relative to the driver's limits on VARCHAR values) when it sends - * it to the database. + * Sets the designated parameter to the given Java String value. The driver converts this to an SQL + * VARCHAR or LONGVARCHAR value (depending on the argument's size relative to the driver's + * limits on VARCHAR values) when it sends it to the database. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param str - * the parameter value + * the parameter value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setString(int parameterIndex, - String str, - boolean forceEncrypt) throws SQLServerException; + public void setString(int parameterIndex, String str, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given String object. The driver converts this to a SQL NCHAR or - * NVARCHAR or LONGNVARCHAR value (depending on the argument's size relative to the driver's limits on - * NVARCHAR values) when it sends it to the database. + * Sets the designated parameter to the given String object. The driver converts this to a SQL + * NCHAR or NVARCHAR or LONGNVARCHAR value (depending on the argument's size + * relative to the driver's limits on NVARCHAR values) when it sends it to the database. * * @param parameterIndex - * of the first parameter is 1, the second is 2, ... + * of the first parameter is 1, the second is 2, ... * @param value - * the parameter value + * the parameter value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setNString(int parameterIndex, - String value, - boolean forceEncrypt) throws SQLServerException; + public void setNString(int parameterIndex, String value, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given java.sql.Time value + * Sets the designated parameter to the given java.sql.Time value. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the parameter value + * the parameter value * @param scale - * the scale of the column + * the scale of the column * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setTime(int parameterIndex, - java.sql.Time x, - int scale) throws SQLServerException; + public void setTime(int parameterIndex, java.sql.Time x, int scale) throws SQLServerException; /** - * Sets the designated parameter to the given java.sql.Time value + * Sets the designated parameter to the given java.sql.Time value. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the parameter value + * the parameter value * @param scale - * the scale of the column + * the scale of the column * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setTime(int parameterIndex, - java.sql.Time x, - int scale, - boolean forceEncrypt) throws SQLServerException; + public void setTime(int parameterIndex, java.sql.Time x, int scale, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given java.sql.Timestamp value + * Sets the designated parameter to the given java.sql.Timestamp value. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the parameter value + * the parameter value * @param scale - * the scale of the column + * the scale of the column * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setTimestamp(int parameterIndex, - java.sql.Timestamp x, - int scale) throws SQLServerException; + public void setTimestamp(int parameterIndex, java.sql.Timestamp x, int scale) throws SQLServerException; /** - * Sets the designated parameter to the given java.sql.Timestamp value + * Sets the designated parameter to the given java.sql.Timestamp value. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the parameter value + * the parameter value * @param scale - * the scale of the column + * the scale of the column * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setTimestamp(int parameterIndex, - java.sql.Timestamp x, - int scale, + public void setTimestamp(int parameterIndex, java.sql.Timestamp x, int scale, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given microsoft.sql.DatetimeOffset value + * Sets the designated parameter to the given microsoft.sql.DatetimeOffset value. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the parameter value + * the parameter value * @param scale - * the scale of the column + * the scale of the column * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setDateTimeOffset(int parameterIndex, - microsoft.sql.DateTimeOffset x, + public void setDateTimeOffset(int parameterIndex, microsoft.sql.DateTimeOffset x, int scale) throws SQLServerException; /** - * Sets the designated parameter to the given microsoft.sql.DatetimeOffset value + * Sets the designated parameter to the given microsoft.sql.DatetimeOffset value. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the parameter value + * the parameter value * @param scale - * the scale of the column + * the scale of the column * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setDateTimeOffset(int parameterIndex, - microsoft.sql.DateTimeOffset x, - int scale, + public void setDateTimeOffset(int parameterIndex, microsoft.sql.DateTimeOffset x, int scale, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given java.sql.Timestamp value + * Sets the designated parameter to the given java.sql.Timestamp value. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the parameter value + * the parameter value * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setDateTime(int parameterIndex, - java.sql.Timestamp x) throws SQLServerException; + public void setDateTime(int parameterIndex, java.sql.Timestamp x) throws SQLServerException; /** - * Sets the designated parameter to the given java.sql.Timestamp value + * Sets the designated parameter to the given java.sql.Timestamp value. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the parameter value + * the parameter value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setDateTime(int parameterIndex, - java.sql.Timestamp x, - boolean forceEncrypt) throws SQLServerException; + public void setDateTime(int parameterIndex, java.sql.Timestamp x, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given java.sql.Timestamp value + * Sets the designated parameter to the given java.sql.Timestamp value. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the parameter value + * the parameter value * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setSmallDateTime(int parameterIndex, - java.sql.Timestamp x) throws SQLServerException; + public void setSmallDateTime(int parameterIndex, java.sql.Timestamp x) throws SQLServerException; /** - * Sets the designated parameter to the given java.sql.Timestamp value + * Sets the designated parameter to the given java.sql.Timestamp value. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the parameter value + * the parameter value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setSmallDateTime(int parameterIndex, - java.sql.Timestamp x, + public void setSmallDateTime(int parameterIndex, java.sql.Timestamp x, boolean forceEncrypt) throws SQLServerException; /** - * Populates a table valued parameter with a data table + * Sets the data table to populates a table valued parameter. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param tvpName - * the name of the table valued parameter + * the name of the table valued parameter * @param tvpDataTable - * the source datatable object + * the source datatable object * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setStructured(int parameterIndex, - String tvpName, + public void setStructured(int parameterIndex, String tvpName, SQLServerDataTable tvpDataTable) throws SQLServerException; /** - * Populates a table valued parameter with a data table + * Sets the result set to populate a table-valued parameter. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param tvpName - * the name of the table valued parameter + * the name of the table valued parameter * @param tvpResultSet - * the source resultset object + * the source resultset object * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setStructured(int parameterIndex, - String tvpName, - ResultSet tvpResultSet) throws SQLServerException; + public void setStructured(int parameterIndex, String tvpName, ResultSet tvpResultSet) throws SQLServerException; /** - * Populates a table valued parameter with a data table + * Sets the server bulk record to populate a table valued parameter. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param tvpName - * the name of the table valued parameter + * the name of the table valued parameter * @param tvpBulkRecord - * an ISQLServerDataRecord object + * an ISQLServerDataRecord object * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setStructured(int parameterIndex, - String tvpName, + public void setStructured(int parameterIndex, String tvpName, ISQLServerDataRecord tvpBulkRecord) throws SQLServerException; /** - * Sets the designated parameter to the given java.sql.Date value, using the given Calendar object. The driver uses the - * Calendar object to construct an SQL DATE value, which the driver then sends to the database. With a - * Calendar object, the driver can calculate the date taking into account a custom timezone. If no Calendar object is + * Sets the designated parameter to the given java.sql.Date value, using the given + * Calendar object. The driver uses the Calendar object to construct an SQL + * DATE value, which the driver then sends to the database. With a Calendar object, the + * driver can calculate the date taking into account a custom timezone. If no Calendar object is * specified, the driver uses the default timezone, which is that of the virtual machine running the application. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the parameter value + * the parameter value * @param cal - * the Calendar object the driver will use to construct the date + * the Calendar object the driver will use to construct the date * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setDate(int parameterIndex, - java.sql.Date x, - java.util.Calendar cal, + public void setDate(int parameterIndex, java.sql.Date x, java.util.Calendar cal, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given java.sql.Time value. The driver converts this to an SQL TIME value when it - * sends it to the database. + * Sets the designated parameter to the given java.sql.Time value. The driver converts this to an SQL + * TIME value when it sends it to the database. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the parameter value + * the parameter value * @param cal - * the Calendar object the driver will use to construct the date + * the Calendar object the driver will use to construct the date * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setTime(int parameterIndex, - java.sql.Time x, - java.util.Calendar cal, + public void setTime(int parameterIndex, java.sql.Time x, java.util.Calendar cal, boolean forceEncrypt) throws SQLServerException; /** - * Sets the designated parameter to the given java.sql.Timestamp value. The driver converts this to an SQL TIMESTAMP - * value when it sends it to the database. + * Sets the designated parameter to the given java.sql.Timestamp value. The driver converts this to an + * SQL TIMESTAMP value when it sends it to the database. * * @param parameterIndex - * the first parameter is 1, the second is 2, ... + * the first parameter is 1, the second is 2, ... * @param x - * the parameter value + * the parameter value * @param cal - * the Calendar object the driver will use to construct the date + * the Calendar object the driver will use to construct the date * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void setTimestamp(int parameterIndex, - java.sql.Timestamp x, - java.util.Calendar cal, + public void setTimestamp(int parameterIndex, java.sql.Timestamp x, java.util.Calendar cal, boolean forceEncrypt) throws SQLServerException; /** * Returns parameter metadata for the prepared statement. * * @param forceRefresh: - * If true the cache will not be used to retrieve the metadata. + * If true the cache will not be used to retrieve the metadata. * * @return Per the description. * * @throws SQLServerException - * when an error occurs + * when an error occurs */ public ParameterMetaData getParameterMetaData(boolean forceRefresh) throws SQLServerException; diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerResultSet.java b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerResultSet.java index e9fa6ccb6..2ac7bc1b5 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerResultSet.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerResultSet.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -14,8 +11,9 @@ import com.microsoft.sqlserver.jdbc.dataclassification.SensitivityClassification; + /** - * This interface is implemented by {@link SQLServerResultSet} class. + * Provides an interface to the {@link SQLServerResultSet} class. */ public interface ISQLServerResultSet extends java.sql.ResultSet { @@ -31,247 +29,248 @@ public interface ISQLServerResultSet extends java.sql.ResultSet { public static final int CONCUR_SS_OPTIMISTIC_CCVAL = 1010; // CONCUR_UPDATABLE + 2 /** - * Retrieves the value of the designated column in the current row of this ResultSet object as a com.microsoft.sqlserver.jdbc.Geometry object in - * the Java programming language. + * Returns the value of the designated column in the current row of this ResultSet object as a + * com.microsoft.sqlserver.jdbc.Geometry object in the Java programming language. * * @param columnIndex - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @return the column value; if the value is SQL NULL, the value returned is null * @throws SQLServerException - * when an error occurs + * when an error occurs */ public Geometry getGeometry(int columnIndex) throws SQLServerException; /** - * Retrieves the value of the designated column in the current row of this ResultSet object as a com.microsoft.sqlserver.jdbc.Geometry object in - * the Java programming language. + * Returns the value of the designated column in the current row of this ResultSet object as a + * com.microsoft.sqlserver.jdbc.Geometry object in the Java programming language. * * @param columnName - * the name of the column + * the name of the column * @return the column value; if the value is SQL NULL, the value returned is null * @throws SQLServerException - * when an error occurs + * when an error occurs */ public Geometry getGeometry(String columnName) throws SQLServerException; /** - * Retrieves the value of the designated column in the current row of this ResultSet object as a com.microsoft.sqlserver.jdbc.Geography object in - * the Java programming language. + * Returns the value of the designated column in the current row of this ResultSet object as a + * com.microsoft.sqlserver.jdbc.Geography object in the Java programming language. * * @param columnIndex - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @return the column value; if the value is SQL NULL, the value returned is null * @throws SQLServerException - * when an error occurs + * when an error occurs */ public Geography getGeography(int columnIndex) throws SQLServerException; /** - * Retrieves the value of the designated column in the current row of this ResultSet object as a com.microsoft.sqlserver.jdbc.Geography object in - * the Java programming language. + * Returns the value of the designated column in the current row of this ResultSet object as a + * com.microsoft.sqlserver.jdbc.Geography object in the Java programming language. * * @param columnName - * the name of the column + * the name of the column * @return the column value; if the value is SQL NULL, the value returned is null * @throws SQLServerException - * when an error occurs + * when an error occurs */ public Geography getGeography(String columnName) throws SQLServerException; /** - * Retrieves the value of the designated column in the current row of this ResultSet object as a String object in the Java programming language. + * Returns the value of the designated column in the current row of this ResultSet object as a String object in the + * Java programming language. * * @param columnIndex - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @return the column value; if the value is SQL NULL, the value returned is null * @throws SQLServerException - * when an error occurs + * when an error occurs */ public String getUniqueIdentifier(int columnIndex) throws SQLServerException; /** - * Retrieves the value of the designated column in the current row of this ResultSet object as a String object in the Java programming language. + * Returns the value of the designated column in the current row of this ResultSet object as a String object in the + * Java programming language. * * @param columnLabel - * the name of the column + * the name of the column * @return the column value; if the value is SQL NULL, the value returned is null * @throws SQLServerException - * when an error occurs + * when an error occurs */ public String getUniqueIdentifier(String columnLabel) throws SQLServerException; /** - * Retrieves the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp object in the Java programming - * language. + * Returns the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp + * object in the Java programming language. * * @param columnIndex - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @return the column value; if the value is SQL NULL, the value returned is null * @throws SQLServerException - * when an error occurs + * when an error occurs */ public java.sql.Timestamp getDateTime(int columnIndex) throws SQLServerException; /** - * Retrieves the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp object in the Java programming - * language. + * Returns the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp + * object in the Java programming language. * * @param columnName - * is the name of the column + * is the name of the column * @return the column value; if the value is SQL NULL, the value returned is null * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ public java.sql.Timestamp getDateTime(String columnName) throws SQLServerException; /** - * Retrieves the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp object in the Java programming - * language. This method uses the given calendar to construct an appropriate millisecond value for the timestamp if the underlying database does - * not store timezone information. + * Returns the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp + * object in the Java programming language. This method uses the given calendar to construct an appropriate + * millisecond value for the timestamp if the underlying database does not store timezone information. * * @param columnIndex - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param cal - * the java.util.Calendar object to use in constructing the dateTime + * the java.util.Calendar object to use in constructing the dateTime * @return the column value; if the value is SQL NULL, the value returned is null * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public java.sql.Timestamp getDateTime(int columnIndex, - Calendar cal) throws SQLServerException; + public java.sql.Timestamp getDateTime(int columnIndex, Calendar cal) throws SQLServerException; /** - * Retrieves the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp object in the Java programming - * language. This method uses the given calendar to construct an appropriate millisecond value for the timestamp if the underlying database does - * not store timezone information. + * Returns the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp + * object in the Java programming language. This method uses the given calendar to construct an appropriate + * millisecond value for the timestamp if the underlying database does not store timezone information. * * @param colName - * the label for the column specified with the SQL AS clause. If the SQL AS clause was not specified, then the label is the name of the - * column + * the label for the column specified with the SQL AS clause. If the SQL AS clause was not specified, then + * the label is the name of the column * @param cal - * the java.util.Calendar object to use in constructing the dateTime + * the java.util.Calendar object to use in constructing the dateTime * @return the column value; if the value is SQL NULL, the value returned is null * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public java.sql.Timestamp getDateTime(String colName, - Calendar cal) throws SQLServerException; + public java.sql.Timestamp getDateTime(String colName, Calendar cal) throws SQLServerException; /** - * Retrieves the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp object in the Java programming - * language. + * Returns the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp + * object in the Java programming language. * * @param columnIndex - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @return the column value; if the value is SQL NULL, the value returned is null * @throws SQLServerException - * when an error occurs + * when an error occurs */ public java.sql.Timestamp getSmallDateTime(int columnIndex) throws SQLServerException; /** - * Retrieves the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp object in the Java programming - * language. + * Returns the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp + * object in the Java programming language. * * @param columnName - * is the name of a column. + * is the name of a column. * @return the column value; if the value is SQL NULL, the value returned is null * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ public java.sql.Timestamp getSmallDateTime(String columnName) throws SQLServerException; /** - * Retrieves the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp object in the Java programming - * language. + * Returns the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp + * object in the Java programming language. * * @param columnIndex - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param cal - * the java.util.Calendar object to use in constructing the smalldateTime + * the java.util.Calendar object to use in constructing the smalldateTime * @return the column value; if the value is SQL NULL, the value returned is null * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public java.sql.Timestamp getSmallDateTime(int columnIndex, - Calendar cal) throws SQLServerException; + public java.sql.Timestamp getSmallDateTime(int columnIndex, Calendar cal) throws SQLServerException; /** + * Returns the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp + * object in the Java programming language. * * @param colName - * The name of a column + * The name of a column * @param cal - * the java.util.Calendar object to use in constructing the smalldateTime + * the java.util.Calendar object to use in constructing the smalldateTime * @return the column value; if the value is SQL NULL, the value returned is null * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public java.sql.Timestamp getSmallDateTime(String colName, - Calendar cal) throws SQLServerException; + public java.sql.Timestamp getSmallDateTime(String colName, Calendar cal) throws SQLServerException; /** - * Retrieves the value of the designated column as a microsoft.sql.DateTimeOffset object, given a zero-based column ordinal. + * Returns the value of the designated column as a microsoft.sql.DateTimeOffset object, given a zero-based column + * ordinal. * * @param columnIndex - * The zero-based ordinal of a column. + * The zero-based ordinal of a column. * @return A DateTimeOffset Class object. * @throws SQLServerException - * when an error occurs + * when an error occurs */ public microsoft.sql.DateTimeOffset getDateTimeOffset(int columnIndex) throws SQLServerException; /** - * Retrieves the value of the column specified as a microsoft.sql.DateTimeOffset object, given a column name. + * Returns the value of the column specified as a microsoft.sql.DateTimeOffset object, given a column name. * * @param columnName - * The name of a column. + * The name of a column. * @return A DateTimeOffset Class object. * @throws SQLServerException - * when an error occurs + * when an error occurs */ public microsoft.sql.DateTimeOffset getDateTimeOffset(String columnName) throws SQLServerException; /** - * Retrieves the value of the column specified as a java.math.BigDecimal object. + * Returns the value of the column specified as a java.math.BigDecimal object. * * @param columnIndex - * The zero-based ordinal of a column. + * The zero-based ordinal of a column. * @return the column value; if the value is SQL NULL, the value returned is null * @throws SQLServerException - * when an error occurs + * when an error occurs */ public BigDecimal getMoney(int columnIndex) throws SQLServerException; /** - * Retrieves the value of the column specified as a java.math.BigDecimal object. + * Returns the value of the column specified as a java.math.BigDecimal object. * * @param columnName - * is the name of a column. + * is the name of a column. * @return the column value; if the value is SQL NULL, the value returned is null. * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ public BigDecimal getMoney(String columnName) throws SQLServerException; /** - * Retrieves the value of the column specified as a java.math.BigDecimal object. + * Returns the value of the column specified as a java.math.BigDecimal object. * * @param columnIndex - * The zero-based ordinal of a column. + * The zero-based ordinal of a column. * @return the column value; if the value is SQL NULL, the value returned is null * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ public BigDecimal getSmallMoney(int columnIndex) throws SQLServerException; /** - * Retrieves the value of the column specified as a java.math.BigDecimal object. + * Returns the value of the column specified as a java.math.BigDecimal object. * * @param columnName - * is the name of a column. + * is the name of a column. * @return the column value; if the value is SQL NULL, the value returned is null. * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ public BigDecimal getSmallMoney(String columnName) throws SQLServerException; @@ -279,1422 +278,1295 @@ public java.sql.Timestamp getSmallDateTime(String colName, * Updates the value of the column specified to the DateTimeOffset Class value, given a zero-based column ordinal. * * @param index - * The zero-based ordinal of a column. + * The zero-based ordinal of a column. * @param x - * A DateTimeOffset Class object. + * A DateTimeOffset Class object. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateDateTimeOffset(int index, - microsoft.sql.DateTimeOffset x) throws SQLServerException; + public void updateDateTimeOffset(int index, microsoft.sql.DateTimeOffset x) throws SQLServerException; /** * Updates the value of the column specified to the DateTimeOffset Class value, given a column name. * * @param columnName - * The name of a column. + * The name of a column. * @param x - * A DateTimeOffset Class object. + * A DateTimeOffset Class object. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateDateTimeOffset(String columnName, - microsoft.sql.DateTimeOffset x) throws SQLServerException; + public void updateDateTimeOffset(String columnName, microsoft.sql.DateTimeOffset x) throws SQLServerException; /** * Updates the designated column with an {@code Object} value. * - * The updater methods are used to update column values in the current row or the insert row. The updater methods do not update the underlying - * database; instead the {@code updateRow} or {@code insertRow} methods are called to update the database. + * The updater methods are used to update column values in the current row or the insert row. The updater methods do + * not update the underlying database; instead the {@code updateRow} or {@code insertRow} methods are called to + * update the database. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param x - * the new column value + * the new column value * @param precision - * the precision of the column + * the precision of the column * @param scale - * the scale of the column + * the scale of the column * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateObject(int index, - Object x, - int precision, - int scale) throws SQLServerException; + public void updateObject(int index, Object x, int precision, int scale) throws SQLServerException; /** - * Updates the designated column with an Object value. The updater methods are used to update column values in the current row or the insert row. - * The updater methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. If the - * second argument is an InputStream then the stream must contain the number of bytes specified by scaleOrLength. If the second argument is a - * Reader then the reader must contain the number of characters specified by scaleOrLength. If these conditions are not true the driver will - * generate a SQLServerException when the statement is executed. The default implementation will throw SQLFeatureNotSupportedException + * Updates the designated column with an Object value. The updater methods are used to update column values in the + * current row or the insert row. The updater methods do not update the underlying database; instead the updateRow + * or insertRow methods are called to update the database. If the second argument is an InputStream then the stream + * must contain the number of bytes specified by scaleOrLength. If the second argument is a Reader then the reader + * must contain the number of characters specified by scaleOrLength. If these conditions are not true the driver + * will generate a SQLServerException when the statement is executed. The default implementation will throw + * SQLFeatureNotSupportedException * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param obj - * the new column value + * the new column value * @param targetSqlType - * the SQL type to be sent to the database + * the SQL type to be sent to the database * @param scale - * for an object of java.math.BigDecimal , this is the number of digits after the decimal point. For Java Object types InputStream and - * Reader, this is the length of the data in the stream or reader. For all other types, this value will be ignored. + * for an object of java.math.BigDecimal , this is the number of digits after the decimal point. For Java + * Object types InputStream and Reader, this is the length of the data in the stream or reader. For all other + * types, this value will be ignored. * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement.If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement.If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateObject(int index, - Object obj, - SQLType targetSqlType, - int scale, + public void updateObject(int index, Object obj, SQLType targetSqlType, int scale, boolean forceEncrypt) throws SQLServerException; /** * - * Updates the designated column with an Object value. The updater methods are used to update column values in the current row or the insert row. - * The updater methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. If the - * second argument is an InputStream then the stream must contain the number of bytes specified by scaleOrLength. If the second argument is a - * Reader then the reader must contain the number of characters specified by scaleOrLength. If these conditions are not true the driver will - * generate a SQLServerException when the statement is executed. The default implementation will throw SQLFeatureNotSupportedException + * Updates the designated column with an Object value. The updater methods are used to update column values in the + * current row or the insert row. The updater methods do not update the underlying database; instead the updateRow + * or insertRow methods are called to update the database. If the second argument is an InputStream then the stream + * must contain the number of bytes specified by scaleOrLength. If the second argument is a Reader then the reader + * must contain the number of characters specified by scaleOrLength. If these conditions are not true the driver + * will generate a SQLServerException when the statement is executed. The default implementation will throw + * SQLFeatureNotSupportedException. * * @param columnName - * the label for the column specified with the SQL AS clause. If the SQL AS clause was not specified, then the label is the name of the - * column + * the label for the column specified with the SQL AS clause. If the SQL AS clause was not specified, then + * the label is the name of the column * @param obj - * the new column value + * the new column value * @param targetSqlType - * the SQL type to be sent to the database + * the SQL type to be sent to the database * @param scale - * for an object of java.math.BigDecimal , this is the number of digits after the decimal point. For Java Object types InputStream and - * Reader, this is the length of the data in the stream or reader. For all other types, this value will be ignored. + * for an object of java.math.BigDecimal , this is the number of digits after the decimal point. For Java + * Object types InputStream and Reader, this is the length of the data in the stream or reader. For all other + * types, this value will be ignored. * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement.If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement.If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateObject(String columnName, - Object obj, - SQLType targetSqlType, - int scale, + public void updateObject(String columnName, Object obj, SQLType targetSqlType, int scale, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a boolean value. The updater methods are used to update column values in the current row or the - * insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods are - * called to update the database. + * Updates the designated column with a boolean value. The updater methods are used to update column + * values in the current row or the insert row. The updater methods do not update the underlying database; instead + * the updateRow or insertRow methods are called to update the database. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param x - * the new column value + * the new column value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateBoolean(int index, - boolean x, - boolean forceEncrypt) throws SQLServerException; + public void updateBoolean(int index, boolean x, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a byte value. The updater methods are used to update column values in the current row or the - * insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods are - * called to update the database. + * Updates the designated column with a byte value. The updater methods are used to update column + * values in the current row or the insert row. The updater methods do not update the underlying database; instead + * the updateRow or insertRow methods are called to update the database. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param x - * the new column value + * the new column value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateByte(int index, - byte x, - boolean forceEncrypt) throws SQLServerException; + public void updateByte(int index, byte x, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a short value. The updater methods are used to update column values in the current row or the - * insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods are - * called to update the database. + * Updates the designated column with a short value. The updater methods are used to update column + * values in the current row or the insert row. The updater methods do not update the underlying database; instead + * the updateRow or insertRow methods are called to update the database. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param x - * the new column value + * the new column value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateShort(int index, - short x, - boolean forceEncrypt) throws SQLServerException; + public void updateShort(int index, short x, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with an int value. The updater methods are used to update column values in the current row or the - * insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods are - * called to update the database. + * Updates the designated column with an int value. The updater methods are used to update column + * values in the current row or the insert row. The updater methods do not update the underlying database; instead + * the updateRow or insertRow methods are called to update the database. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param x - * the new column value + * the new column value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateInt(int index, - int x, - boolean forceEncrypt) throws SQLServerException; + public void updateInt(int index, int x, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a long value. The updater methods are used to update column values in the current row or the - * insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods are - * called to update the database. + * Updates the designated column with a long value. The updater methods are used to update column + * values in the current row or the insert row. The updater methods do not update the underlying database; instead + * the updateRow or insertRow methods are called to update the database. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param x - * the new column value + * the new column value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateLong(int index, - long x, - boolean forceEncrypt) throws SQLServerException; + public void updateLong(int index, long x, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a float value. The updater methods are used to update column values in the current row or the - * insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods are - * called to update the database. + * Updates the designated column with a float value. The updater methods are used to update column + * values in the current row or the insert row. The updater methods do not update the underlying database; instead + * the updateRow or insertRow methods are called to update the database. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param x - * the new column value + * the new column value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateFloat(int index, - float x, - boolean forceEncrypt) throws SQLServerException; + public void updateFloat(int index, float x, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a double value. The updater methods are used to update column values in the current row or the - * insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods are - * called to update the database. + * Updates the designated column with a double value. The updater methods are used to update column + * values in the current row or the insert row. The updater methods do not update the underlying database; instead + * the updateRow or insertRow methods are called to update the database. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param x - * the new column value + * the new column value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateDouble(int index, - double x, - boolean forceEncrypt) throws SQLServerException; + public void updateDouble(int index, double x, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a money value. The updater methods are used to update column values in the current row or the - * insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods are - * called to update the database. + * Updates the designated column with a money value. The updater methods are used to update column + * values in the current row or the insert row. The updater methods do not update the underlying database; instead + * the updateRow or insertRow methods are called to update the database. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param x - * the new column value + * the new column value * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateMoney(int index, - BigDecimal x) throws SQLServerException; + public void updateMoney(int index, BigDecimal x) throws SQLServerException; /** - * Updates the designated column with a money value. The updater methods are used to update column values in the current row or the - * insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods are - * called to update the database. + * Updates the designated column with a money value. The updater methods are used to update column + * values in the current row or the insert row. The updater methods do not update the underlying database; instead + * the updateRow or insertRow methods are called to update the database. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param x - * the new column value + * the new column value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateMoney(int index, - BigDecimal x, - boolean forceEncrypt) throws SQLServerException; + public void updateMoney(int index, BigDecimal x, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a money value. The updater methods are used to update column values in the current row or the - * insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods are - * called to update the database. + * Updates the designated column with a money value. The updater methods are used to update column + * values in the current row or the insert row. The updater methods do not update the underlying database; instead + * the updateRow or insertRow methods are called to update the database. * * @param columnName - * the column name + * the column name * @param x - * the new column value + * the new column value * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateMoney(String columnName, - BigDecimal x) throws SQLServerException; + public void updateMoney(String columnName, BigDecimal x) throws SQLServerException; /** - * Updates the designated column with a money value. The updater methods are used to update column values in the current row or the - * insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods are - * called to update the database. + * Updates the designated column with a money value. The updater methods are used to update column + * values in the current row or the insert row. The updater methods do not update the underlying database; instead + * the updateRow or insertRow methods are called to update the database. * * @param columnName - * the column name + * the column name * @param x - * the new column value + * the new column value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateMoney(String columnName, - BigDecimal x, - boolean forceEncrypt) throws SQLServerException; + public void updateMoney(String columnName, BigDecimal x, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a smallmoney value. The updater methods are used to update column values in the current row or - * the insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods - * are called to update the database. + * Updates the designated column with a smallmoney value. The updater methods are used to update column + * values in the current row or the insert row. The updater methods do not update the underlying database; instead + * the updateRow or insertRow methods are called to update the database. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param x - * the new column value + * the new column value * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateSmallMoney(int index, - BigDecimal x) throws SQLServerException; + public void updateSmallMoney(int index, BigDecimal x) throws SQLServerException; /** - * Updates the designated column with a smallmoney value. The updater methods are used to update column values in the current row or - * the insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods - * are called to update the database. + * Updates the designated column with a smallmoney value. The updater methods are used to update column + * values in the current row or the insert row. The updater methods do not update the underlying database; instead + * the updateRow or insertRow methods are called to update the database. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param x - * the new column value + * the new column value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateSmallMoney(int index, - BigDecimal x, - boolean forceEncrypt) throws SQLServerException; + public void updateSmallMoney(int index, BigDecimal x, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a smallmoney value. The updater methods are used to update column values in the current row or - * the insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods - * are called to update the database. + * Updates the designated column with a smallmoney value. The updater methods are used to update column + * values in the current row or the insert row. The updater methods do not update the underlying database; instead + * the updateRow or insertRow methods are called to update the database. * * @param columnName - * the column name + * the column name * @param x - * the new column value + * the new column value * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateSmallMoney(String columnName, - BigDecimal x) throws SQLServerException; + public void updateSmallMoney(String columnName, BigDecimal x) throws SQLServerException; /** - * Updates the designated column with a smallmoney value. The updater methods are used to update column values in the current row or - * the insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods - * are called to update the database. + * Updates the designated column with a smallmoney value. The updater methods are used to update column + * values in the current row or the insert row. The updater methods do not update the underlying database; instead + * the updateRow or insertRow methods are called to update the database. * * @param columnName - * the column name + * the column name * @param x - * the new column value + * the new column value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateSmallMoney(String columnName, - BigDecimal x, - boolean forceEncrypt) throws SQLServerException; + public void updateSmallMoney(String columnName, BigDecimal x, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a java.math.BigDecimal value. The updater methods are used to update column values in the - * current row or the insert row. The updater methods do not update the underlying database; instead the updateRow or - * insertRow methods are called to update the database. + * Updates the designated column with a java.math.BigDecimal value. The updater methods are used to + * update column values in the current row or the insert row. The updater methods do not update the underlying + * database; instead the updateRow or insertRow methods are called to update the database. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param x - * the new column value + * the new column value * @param precision - * the precision of the column + * the precision of the column * @param scale - * the scale of the column + * the scale of the column * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateBigDecimal(int index, - BigDecimal x, - Integer precision, - Integer scale) throws SQLServerException; + public void updateBigDecimal(int index, BigDecimal x, Integer precision, Integer scale) throws SQLServerException; /** - * Updates the designated column with a java.math.BigDecimal value. The updater methods are used to update column values in the - * current row or the insert row. The updater methods do not update the underlying database; instead the updateRow or - * insertRow methods are called to update the database. + * Updates the designated column with a java.math.BigDecimal value. The updater methods are used to + * update column values in the current row or the insert row. The updater methods do not update the underlying + * database; instead the updateRow or insertRow methods are called to update the database. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param x - * the new column value + * the new column value * @param precision - * the precision of the column + * the precision of the column * @param scale - * the scale of the column + * the scale of the column * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateBigDecimal(int index, - BigDecimal x, - Integer precision, - Integer scale, + public void updateBigDecimal(int index, BigDecimal x, Integer precision, Integer scale, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a String value. The updater methods are used to update column values in the current row or the - * insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods are - * called to update the database. + * Updates the designated column with a String value. The updater methods are used to update column + * values in the current row or the insert row. The updater methods do not update the underlying database; instead + * the updateRow or insertRow methods are called to update the database. * * @param columnIndex - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param stringValue - * the new column value + * the new column value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateString(int columnIndex, - String stringValue, - boolean forceEncrypt) throws SQLServerException; + public void updateString(int columnIndex, String stringValue, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a String value. It is intended for use when updating NCHAR,NVARCHAR - * and LONGNVARCHAR columns. The updater methods are used to update column values in the current row or the insert row. The updater - * methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the - * database. + * Updates the designated column with a String value. It is intended for use when updating + * NCHAR,NVARCHAR and LONGNVARCHAR columns. The updater methods are used to + * update column values in the current row or the insert row. The updater methods do not update the underlying + * database; instead the updateRow or insertRow methods are called to update the database. * * @param columnIndex - * the first column is 1, the second 2, ... + * the first column is 1, the second 2, ... * @param nString - * the value for the column to be updated + * the value for the column to be updated * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateNString(int columnIndex, - String nString, - boolean forceEncrypt) throws SQLServerException; + public void updateNString(int columnIndex, String nString, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a String value. It is intended for use when updating NCHAR,NVARCHAR - * and LONGNVARCHAR columns. The updater methods are used to update column values in the current row or the insert row. The updater - * methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the - * database. + * Updates the designated column with a String value. It is intended for use when updating + * NCHAR,NVARCHAR and LONGNVARCHAR columns. The updater methods are used to + * update column values in the current row or the insert row. The updater methods do not update the underlying + * database; instead the updateRow or insertRow methods are called to update the database. * * @param columnLabel - * the label for the column specified with the SQL AS clause. If the SQL AS clause was not specified, then the label is the name of the - * column + * the label for the column specified with the SQL AS clause. If the SQL AS clause was not specified, then + * the label is the name of the column * @param nString - * the value for the column to be updated + * the value for the column to be updated * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateNString(String columnLabel, - String nString, - boolean forceEncrypt) throws SQLServerException; + public void updateNString(String columnLabel, String nString, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a byte array value. The updater methods are used to update column values in the current row or - * the insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods - * are called to update the database. + * Updates the designated column with a byte array value. The updater methods are used to update column + * values in the current row or the insert row. The updater methods do not update the underlying database; instead + * the updateRow or insertRow methods are called to update the database. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param x - * the new column value + * the new column value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateBytes(int index, - byte x[], - boolean forceEncrypt) throws SQLServerException; + public void updateBytes(int index, byte x[], boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a java.sql.Date value. The updater methods are used to update column values in the current row - * or the insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow - * methods are called to update the database. + * Updates the designated column with a java.sql.Date value. The updater methods are used to update + * column values in the current row or the insert row. The updater methods do not update the underlying database; + * instead the updateRow or insertRow methods are called to update the database. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param x - * the new column value + * the new column value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateDate(int index, - java.sql.Date x, - boolean forceEncrypt) throws SQLServerException; + public void updateDate(int index, java.sql.Date x, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a java.sql.Time value. The updater methods are used to update column values in the current row - * or the insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow - * methods are called to update the database. + * Updates the designated column with a java.sql.Time value. The updater methods are used to update + * column values in the current row or the insert row. The updater methods do not update the underlying database; + * instead the updateRow or insertRow methods are called to update the database. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param x - * the new column value + * the new column value * @param scale - * the scale of the column + * the scale of the column * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateTime(int index, - java.sql.Time x, - Integer scale) throws SQLServerException; + public void updateTime(int index, java.sql.Time x, Integer scale) throws SQLServerException; /** - * Updates the designated column with a java.sql.Time value. The updater methods are used to update column values in the current row - * or the insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow - * methods are called to update the database. + * Updates the designated column with a java.sql.Time value. The updater methods are used to update + * column values in the current row or the insert row. The updater methods do not update the underlying database; + * instead the updateRow or insertRow methods are called to update the database. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param x - * the new column value + * the new column value * @param scale - * the scale of the column + * the scale of the column * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateTime(int index, - java.sql.Time x, - Integer scale, - boolean forceEncrypt) throws SQLServerException; + public void updateTime(int index, java.sql.Time x, Integer scale, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to update column values in the current - * row or the insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow - * methods are called to update the database. + * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to + * update column values in the current row or the insert row. The updater methods do not update the underlying + * database; instead the updateRow or insertRow methods are called to update the database. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param x - * the new column value + * the new column value * @param scale - * the scale of the column + * the scale of the column * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateTimestamp(int index, - java.sql.Timestamp x, - int scale) throws SQLServerException; + public void updateTimestamp(int index, java.sql.Timestamp x, int scale) throws SQLServerException; /** - * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to update column values in the current - * row or the insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow - * methods are called to update the database. + * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to + * update column values in the current row or the insert row. The updater methods do not update the underlying + * database; instead the updateRow or insertRow methods are called to update the database. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param x - * the new column value + * the new column value * @param scale - * the scale of the column + * the scale of the column * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateTimestamp(int index, - java.sql.Timestamp x, - int scale, + public void updateTimestamp(int index, java.sql.Timestamp x, int scale, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to update column values in the current - * row or the insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow - * methods are called to update the database. + * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to + * update column values in the current row or the insert row. The updater methods do not update the underlying + * database; instead the updateRow or insertRow methods are called to update the database. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param x - * the new column value + * the new column value * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateDateTime(int index, - java.sql.Timestamp x) throws SQLServerException; + public void updateDateTime(int index, java.sql.Timestamp x) throws SQLServerException; /** - * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to update column values in the current - * row or the insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow - * methods are called to update the database. + * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to + * update column values in the current row or the insert row. The updater methods do not update the underlying + * database; instead the updateRow or insertRow methods are called to update the database. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param x - * the new column value + * the new column value * @param scale - * the scale of the column + * the scale of the column * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateDateTime(int index, - java.sql.Timestamp x, - Integer scale) throws SQLServerException; + public void updateDateTime(int index, java.sql.Timestamp x, Integer scale) throws SQLServerException; /** - * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to update column values in the current - * row or the insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow - * methods are called to update the database. + * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to + * update column values in the current row or the insert row. The updater methods do not update the underlying + * database; instead the updateRow or insertRow methods are called to update the database. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param x - * the new column value + * the new column value * @param scale - * the scale of the column + * the scale of the column * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateDateTime(int index, - java.sql.Timestamp x, - Integer scale, + public void updateDateTime(int index, java.sql.Timestamp x, Integer scale, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to update column values in the current - * row or the insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow - * methods are called to update the database. + * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to + * update column values in the current row or the insert row. The updater methods do not update the underlying + * database; instead the updateRow or insertRow methods are called to update the database. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param x - * the new column value + * the new column value * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateSmallDateTime(int index, - java.sql.Timestamp x) throws SQLServerException; + public void updateSmallDateTime(int index, java.sql.Timestamp x) throws SQLServerException; /** - * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to update column values in the current - * row or the insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow - * methods are called to update the database. + * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to + * update column values in the current row or the insert row. The updater methods do not update the underlying + * database; instead the updateRow or insertRow methods are called to update the database. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param x - * the new column value + * the new column value * @param scale - * the scale of the column + * the scale of the column * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateSmallDateTime(int index, - java.sql.Timestamp x, - Integer scale) throws SQLServerException; + public void updateSmallDateTime(int index, java.sql.Timestamp x, Integer scale) throws SQLServerException; /** - * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to update column values in the current - * row or the insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow - * methods are called to update the database. + * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to + * update column values in the current row or the insert row. The updater methods do not update the underlying + * database; instead the updateRow or insertRow methods are called to update the database. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param x - * the new column value + * the new column value * @param scale - * the scale of the column + * the scale of the column * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateSmallDateTime(int index, - java.sql.Timestamp x, - Integer scale, + public void updateSmallDateTime(int index, java.sql.Timestamp x, Integer scale, boolean forceEncrypt) throws SQLServerException; /** * Updates the value of the column specified to the DateTimeOffset Class value, given a zero-based column ordinal. * * @param index - * The zero-based ordinal of a column. + * The zero-based ordinal of a column. * @param x - * A DateTimeOffset Class object. + * A DateTimeOffset Class object. * @param scale - * scale of the column + * scale of the column * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateDateTimeOffset(int index, - microsoft.sql.DateTimeOffset x, + public void updateDateTimeOffset(int index, microsoft.sql.DateTimeOffset x, Integer scale) throws SQLServerException; /** * Updates the value of the column specified to the DateTimeOffset Class value, given a zero-based column ordinal. * * @param index - * The zero-based ordinal of a column. + * The zero-based ordinal of a column. * @param x - * A DateTimeOffset Class object. + * A DateTimeOffset Class object. * @param scale - * scale of the column + * scale of the column * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateDateTimeOffset(int index, - microsoft.sql.DateTimeOffset x, - Integer scale, + public void updateDateTimeOffset(int index, microsoft.sql.DateTimeOffset x, Integer scale, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a String value. The updater methods are used to update column values in the current row or the - * insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods are - * called to update the database. + * Updates the designated column with a String value. The updater methods are used to update column + * values in the current row or the insert row. The updater methods do not update the underlying database; instead + * the updateRow or insertRow methods are called to update the database. * * @param index - * The zero-based ordinal of a column. + * The zero-based ordinal of a column. * @param x - * the new column value + * the new column value * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateUniqueIdentifier(int index, - String x) throws SQLServerException; + public void updateUniqueIdentifier(int index, String x) throws SQLServerException; /** - * Updates the designated column with a String value. The updater methods are used to update column values in the current row or the - * insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods are - * called to update the database. + * Updates the designated column with a String value. The updater methods are used to update column + * values in the current row or the insert row. The updater methods do not update the underlying database; instead + * the updateRow or insertRow methods are called to update the database. * * @param index - * The zero-based ordinal of a column. + * The zero-based ordinal of a column. * @param x - * the new column value + * the new column value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateUniqueIdentifier(int index, - String x, - boolean forceEncrypt) throws SQLServerException; + public void updateUniqueIdentifier(int index, String x, boolean forceEncrypt) throws SQLServerException; /** * Updates the designated column with an {@code Object} value. * - * The updater methods are used to update column values in the current row or the insert row. The updater methods do not update the underlying - * database; instead the {@code updateRow} or {@code insertRow} methods are called to update the database. + * The updater methods are used to update column values in the current row or the insert row. The updater methods do + * not update the underlying database; instead the {@code updateRow} or {@code insertRow} methods are called to + * update the database. * * @param index - * the first column is 1, the second is 2, ... + * the first column is 1, the second is 2, ... * @param x - * the new column value + * the new column value * @param precision - * the precision of the column + * the precision of the column * @param scale - * the scale of the column + * the scale of the column * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateObject(int index, - Object x, - int precision, - int scale, + public void updateObject(int index, Object x, int precision, int scale, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a boolean value. The updater methods are used to update column values in the current row or the - * insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods are - * called to update the database. + * Updates the designated column with a boolean value. The updater methods are used to update column + * values in the current row or the insert row. The updater methods do not update the underlying database; instead + * the updateRow or insertRow methods are called to update the database. * * @param columnName - * the name of the column + * the name of the column * @param x - * the new column value + * the new column value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public void updateBoolean(String columnName, - boolean x, - boolean forceEncrypt) throws SQLServerException; + public void updateBoolean(String columnName, boolean x, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a byte value. The updater methods are used to update column values in the current row or the - * insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods are - * called to update the database. + * Updates the designated column with a byte value. The updater methods are used to update column + * values in the current row or the insert row. The updater methods do not update the underlying database; instead + * the updateRow or insertRow methods are called to update the database. * * * @param columnName - * the name of the column + * the name of the column * @param x - * the new column value + * the new column value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateByte(String columnName, - byte x, - boolean forceEncrypt) throws SQLServerException; + public void updateByte(String columnName, byte x, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a short value. The updater methods are used to update column values in the current row or the - * insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods are - * called to update the database. + * Updates the designated column with a short value. The updater methods are used to update column + * values in the current row or the insert row. The updater methods do not update the underlying database; instead + * the updateRow or insertRow methods are called to update the database. * * @param columnName - * the name of the column + * the name of the column * @param x - * the new column value + * the new column value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateShort(String columnName, - short x, - boolean forceEncrypt) throws SQLServerException; + public void updateShort(String columnName, short x, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with an int value. The updater methods are used to update column values in the current row or the - * insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods are - * called to update the database. + * Updates the designated column with an int value. The updater methods are used to update column + * values in the current row or the insert row. The updater methods do not update the underlying database; instead + * the updateRow or insertRow methods are called to update the database. * * @param columnName - * is the name of the column + * is the name of the column * @param x - * the new column value + * the new column value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateInt(String columnName, - int x, - boolean forceEncrypt) throws SQLServerException; + public void updateInt(String columnName, int x, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a long value. The updater methods are used to update column values in the current row or the - * insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods are - * called to update the database. + * Updates the designated column with a long value. The updater methods are used to update column + * values in the current row or the insert row. The updater methods do not update the underlying database; instead + * the updateRow or insertRow methods are called to update the database. * * @param columnName - * is the name of the column + * is the name of the column * @param x - * the new column value + * the new column value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateLong(String columnName, - long x, - boolean forceEncrypt) throws SQLServerException; + public void updateLong(String columnName, long x, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a float value. The updater methods are used to update column values in the current row or the - * insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods are - * called to update the database. + * Updates the designated column with a float value. The updater methods are used to update column + * values in the current row or the insert row. The updater methods do not update the underlying database; instead + * the updateRow or insertRow methods are called to update the database. * * @param columnName - * is the name of the column + * is the name of the column * @param x - * the new column value + * the new column value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateFloat(String columnName, - float x, - boolean forceEncrypt) throws SQLServerException; + public void updateFloat(String columnName, float x, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a double value. The updater methods are used to update column values in the current row or the - * insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods are - * called to update the database. + * Updates the designated column with a double value. The updater methods are used to update column + * values in the current row or the insert row. The updater methods do not update the underlying database; instead + * the updateRow or insertRow methods are called to update the database. * * @param columnName - * is the name of the column + * is the name of the column * @param x - * the new column value + * the new column value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateDouble(String columnName, - double x, - boolean forceEncrypt) throws SQLServerException; + public void updateDouble(String columnName, double x, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a java.sql.BigDecimal value. The updater methods are used to update column values in the - * current row or the insert row. The updater methods do not update the underlying database; instead the updateRow or - * insertRow methods are called to update the database. + * Updates the designated column with a java.sql.BigDecimal value. The updater methods are used to + * update column values in the current row or the insert row. The updater methods do not update the underlying + * database; instead the updateRow or insertRow methods are called to update the database. * * @param columnName - * is the name of the column + * is the name of the column * @param x - * the new column value + * the new column value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateBigDecimal(String columnName, - BigDecimal x, - boolean forceEncrypt) throws SQLServerException; + public void updateBigDecimal(String columnName, BigDecimal x, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a java.sql.BigDecimal value. The updater methods are used to update column values in the - * current row or the insert row. The updater methods do not update the underlying database; instead the updateRow or - * insertRow methods are called to update the database. + * Updates the designated column with a java.sql.BigDecimal value. The updater methods are used to + * update column values in the current row or the insert row. The updater methods do not update the underlying + * database; instead the updateRow or insertRow methods are called to update the database. * * @param columnName - * is the name of the column and Always Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set - * to false, the driver will not force encryption on parameters. + * is the name of the column and Always Encrypted is enabled on the connection or on the statement. If the + * boolean forceEncrypt is set to false, the driver will not force encryption on parameters. * @param x - * BigDecimal value + * BigDecimal value * @param precision - * the precision of the column + * the precision of the column * @param scale - * the scale of the column + * the scale of the column * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateBigDecimal(String columnName, - BigDecimal x, - Integer precision, + public void updateBigDecimal(String columnName, BigDecimal x, Integer precision, Integer scale) throws SQLServerException; /** - * Updates the designated column with a java.sql.BigDecimal value. The updater methods are used to update column values in the - * current row or the insert row. The updater methods do not update the underlying database; instead the updateRow or - * insertRow methods are called to update the database. + * Updates the designated column with a java.sql.BigDecimal value. The updater methods are used to + * update column values in the current row or the insert row. The updater methods do not update the underlying + * database; instead the updateRow or insertRow methods are called to update the database. * * @param columnName - * is the name of the column and Always Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set - * to false, the driver will not force encryption on parameters. + * is the name of the column and Always Encrypted is enabled on the connection or on the statement. If the + * boolean forceEncrypt is set to false, the driver will not force encryption on parameters. * @param x - * BigDecimal value + * BigDecimal value * @param precision - * the precision of the column + * the precision of the column * @param scale - * the scale of the column + * the scale of the column * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateBigDecimal(String columnName, - BigDecimal x, - Integer precision, - Integer scale, + public void updateBigDecimal(String columnName, BigDecimal x, Integer precision, Integer scale, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a String value. The updater methods are used to update column values in the current row or the - * insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods are - * called to update the database. + * Updates the designated column with a String value. The updater methods are used to update column + * values in the current row or the insert row. The updater methods do not update the underlying database; instead + * the updateRow or insertRow methods are called to update the database. * * @param columnName - * is the name of the column + * is the name of the column * @param x - * the new column value + * the new column value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateString(String columnName, - String x, - boolean forceEncrypt) throws SQLServerException; + public void updateString(String columnName, String x, boolean forceEncrypt) throws SQLServerException; /** * Updates the designated column with a byte array value. * - * The updater methods are used to update column values in the current row or the insert row. The updater methods do not update the underlying - * database; instead the updateRow or insertRow methods are called to update the database. + * The updater methods are used to update column values in the current row or the insert row. The updater methods do + * not update the underlying database; instead the updateRow or insertRow methods are + * called to update the database. * * @param columnName - * is the name of the column + * is the name of the column * @param x - * the new column value + * the new column value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateBytes(String columnName, - byte x[], - boolean forceEncrypt) throws SQLServerException; + public void updateBytes(String columnName, byte x[], boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a java.sql.Date value. The updater methods are used to update column values in the current row - * or the insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow - * methods are called to update the database. + * Updates the designated column with a java.sql.Date value. The updater methods are used to update + * column values in the current row or the insert row. The updater methods do not update the underlying database; + * instead the updateRow or insertRow methods are called to update the database. * * @param columnName - * is the name of the column + * is the name of the column * @param x - * the new column value + * the new column value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateDate(String columnName, - java.sql.Date x, - boolean forceEncrypt) throws SQLServerException; + public void updateDate(String columnName, java.sql.Date x, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a java.sql.Time value. The updater methods are used to update column values in the current row - * or the insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow - * methods are called to update the database. + * Updates the designated column with a java.sql.Time value. The updater methods are used to update + * column values in the current row or the insert row. The updater methods do not update the underlying database; + * instead the updateRow or insertRow methods are called to update the database. * * @param columnName - * is the name of the column + * is the name of the column * @param x - * the new column value + * the new column value * @param scale - * the scale of the column + * the scale of the column * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateTime(String columnName, - java.sql.Time x, - int scale) throws SQLServerException; + public void updateTime(String columnName, java.sql.Time x, int scale) throws SQLServerException; /** - * Updates the designated column with a java.sql.Time value. The updater methods are used to update column values in the current row - * or the insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow - * methods are called to update the database. + * Updates the designated column with a java.sql.Time value. The updater methods are used to update + * column values in the current row or the insert row. The updater methods do not update the underlying database; + * instead the updateRow or insertRow methods are called to update the database. * * @param columnName - * is the name of the column + * is the name of the column * @param x - * the new column value + * the new column value * @param scale - * the scale of the column + * the scale of the column * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateTime(String columnName, - java.sql.Time x, - int scale, + public void updateTime(String columnName, java.sql.Time x, int scale, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to update column values in the current - * row or the insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow - * methods are called to update the database. + * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to + * update column values in the current row or the insert row. The updater methods do not update the underlying + * database; instead the updateRow or insertRow methods are called to update the database. * * @param columnName - * is the name of the column + * is the name of the column * @param x - * the new column value + * the new column value * @param scale - * the scale of the column + * the scale of the column * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateTimestamp(String columnName, - java.sql.Timestamp x, - int scale) throws SQLServerException; + public void updateTimestamp(String columnName, java.sql.Timestamp x, int scale) throws SQLServerException; /** - * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to update column values in the current - * row or the insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow - * methods are called to update the database. + * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to + * update column values in the current row or the insert row. The updater methods do not update the underlying + * database; instead the updateRow or insertRow methods are called to update the database. * * @param columnName - * is the name of the column + * is the name of the column * @param x - * the new column value + * the new column value * @param scale - * the scale of the column + * the scale of the column * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateTimestamp(String columnName, - java.sql.Timestamp x, - int scale, + public void updateTimestamp(String columnName, java.sql.Timestamp x, int scale, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to update column values in the current - * row or the insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow - * methods are called to update the database. + * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to + * update column values in the current row or the insert row. The updater methods do not update the underlying + * database; instead the updateRow or insertRow methods are called to update the database. * * @param columnName - * is the name of the column + * is the name of the column * @param x - * the new column value + * the new column value * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateDateTime(String columnName, - java.sql.Timestamp x) throws SQLServerException; + public void updateDateTime(String columnName, java.sql.Timestamp x) throws SQLServerException; /** - * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to update column values in the current - * row or the insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow - * methods are called to update the database. + * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to + * update column values in the current row or the insert row. The updater methods do not update the underlying + * database; instead the updateRow or insertRow methods are called to update the database. * * @param columnName - * is the name of the column + * is the name of the column * @param x - * the new column value + * the new column value * @param scale - * the scale of the column + * the scale of the column * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateDateTime(String columnName, - java.sql.Timestamp x, - int scale) throws SQLServerException; + public void updateDateTime(String columnName, java.sql.Timestamp x, int scale) throws SQLServerException; /** - * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to update column values in the current - * row or the insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow - * methods are called to update the database. + * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to + * update column values in the current row or the insert row. The updater methods do not update the underlying + * database; instead the updateRow or insertRow methods are called to update the database. * * @param columnName - * is the name of the column + * is the name of the column * @param x - * the new column value + * the new column value * @param scale - * the scale of the column + * the scale of the column * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateDateTime(String columnName, - java.sql.Timestamp x, - int scale, + public void updateDateTime(String columnName, java.sql.Timestamp x, int scale, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to update column values in the current - * row or the insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow - * methods are called to update the database. + * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to + * update column values in the current row or the insert row. The updater methods do not update the underlying + * database; instead the updateRow or insertRow methods are called to update the database. * * @param columnName - * is the name of the column + * is the name of the column * @param x - * the new column value + * the new column value * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateSmallDateTime(String columnName, - java.sql.Timestamp x) throws SQLServerException; + public void updateSmallDateTime(String columnName, java.sql.Timestamp x) throws SQLServerException; /** - * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to update column values in the current - * row or the insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow - * methods are called to update the database. + * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to + * update column values in the current row or the insert row. The updater methods do not update the underlying + * database; instead the updateRow or insertRow methods are called to update the database. * * @param columnName - * is the name of the column + * is the name of the column * @param x - * the new column value + * the new column value * @param scale - * the scale of the column + * the scale of the column * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateSmallDateTime(String columnName, - java.sql.Timestamp x, - int scale) throws SQLServerException; + public void updateSmallDateTime(String columnName, java.sql.Timestamp x, int scale) throws SQLServerException; /** - * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to update column values in the current - * row or the insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow - * methods are called to update the database. + * Updates the designated column with a java.sql.Timestamp value. The updater methods are used to + * update column values in the current row or the insert row. The updater methods do not update the underlying + * database; instead the updateRow or insertRow methods are called to update the database. * * @param columnName - * is the name of the column + * is the name of the column * @param x - * the new column value + * the new column value * @param scale - * the scale of the column + * the scale of the column * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateSmallDateTime(String columnName, - java.sql.Timestamp x, - int scale, + public void updateSmallDateTime(String columnName, java.sql.Timestamp x, int scale, boolean forceEncrypt) throws SQLServerException; /** * Updates the value of the column specified to the DateTimeOffset Class value, given a column name. * * @param columnName - * The name of a column. + * The name of a column. * @param x - * A DateTimeOffset Class object. + * A DateTimeOffset Class object. * @param scale - * the scale of the column + * the scale of the column * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateDateTimeOffset(String columnName, - microsoft.sql.DateTimeOffset x, + public void updateDateTimeOffset(String columnName, microsoft.sql.DateTimeOffset x, int scale) throws SQLServerException; /** * Updates the value of the column specified to the DateTimeOffset Class value, given a column name. * * @param columnName - * The name of a column. + * The name of a column. * @param x - * A DateTimeOffset Class object. + * A DateTimeOffset Class object. * @param scale - * the scale of the column + * the scale of the column * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateDateTimeOffset(String columnName, - microsoft.sql.DateTimeOffset x, - int scale, + public void updateDateTimeOffset(String columnName, microsoft.sql.DateTimeOffset x, int scale, boolean forceEncrypt) throws SQLServerException; /** - * Updates the designated column with a Stringvalue. The updater methods are used to update column values in the current row or the - * insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods are - * called to update the database. + * Updates the designated column with a Stringvalue. The updater methods are used to update column + * values in the current row or the insert row. The updater methods do not update the underlying database; instead + * the updateRow or insertRow methods are called to update the database. * * @param columnName - * The name of a column. + * The name of a column. * @param x - * the new column value + * the new column value * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateUniqueIdentifier(String columnName, - String x) throws SQLServerException; + public void updateUniqueIdentifier(String columnName, String x) throws SQLServerException; /** - * Updates the designated column with a Stringvalue. The updater methods are used to update column values in the current row or the - * insert row. The updater methods do not update the underlying database; instead the updateRow or insertRow methods are - * called to update the database. + * Updates the designated column with a Stringvalue. The updater methods are used to update column + * values in the current row or the insert row. The updater methods do not update the underlying database; instead + * the updateRow or insertRow methods are called to update the database. * * @param columnName - * The name of a column. + * The name of a column. * @param x - * the new column value + * the new column value * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateUniqueIdentifier(String columnName, - String x, - boolean forceEncrypt) throws SQLServerException; + public void updateUniqueIdentifier(String columnName, String x, boolean forceEncrypt) throws SQLServerException; /** * Updates the designated column with an {@code Object} value. * - * The updater methods are used to update column values in the current row or the insert row. The updater methods do not update the underlying - * database; instead the {@code updateRow} or {@code insertRow} methods are called to update the database. + * The updater methods are used to update column values in the current row or the insert row. The updater methods do + * not update the underlying database; instead the {@code updateRow} or {@code insertRow} methods are called to + * update the database. * * @param columnName - * The name of a column. + * The name of a column. * @param x - * the new column value + * the new column value * @param precision - * the precision of the column + * the precision of the column * @param scale - * the scale of the column + * the scale of the column * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateObject(String columnName, - Object x, - int precision, - int scale) throws SQLServerException; + public void updateObject(String columnName, Object x, int precision, int scale) throws SQLServerException; /** * Updates the designated column with an {@code Object} value. * - * The updater methods are used to update column values in the current row or the insert row. The updater methods do not update the underlying - * database; instead the {@code updateRow} or {@code insertRow} methods are called to update the database. + * The updater methods are used to update column values in the current row or the insert row. The updater methods do + * not update the underlying database; instead the {@code updateRow} or {@code insertRow} methods are called to + * update the database. * * @param columnName - * The name of a column. + * The name of a column. * @param x - * the new column value + * the new column value * @param precision - * the precision of the column + * the precision of the column * @param scale - * the scale of the column + * the scale of the column * @param forceEncrypt - * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column is encrypted and Always - * Encrypted is enabled on the connection or on the statement. If the boolean forceEncrypt is set to false, the driver will not force - * encryption on parameters. + * If the boolean forceEncrypt is set to true, the query parameter will only be set if the designation column + * is encrypted and Always Encrypted is enabled on the connection or on the statement. If the boolean + * forceEncrypt is set to false, the driver will not force encryption on parameters. * @throws SQLServerException - * If any errors occur. + * If any errors occur. */ - public void updateObject(String columnName, - Object x, - int precision, - int scale, + public void updateObject(String columnName, Object x, int precision, int scale, boolean forceEncrypt) throws SQLServerException; - + /** - * Exposes Data Classification information for the current ResultSet For SQL Servers that do not support Data Classification or results that do - * not fetch any classified columns, this data can be null + * Returns the Data Classification information for the current ResultSet For SQL Servers that do not support Data + * Classification or results that do not fetch any classified columns, this data can be null. * * @return SensitivityClassification */ diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerResultSetMetaData.java b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerResultSetMetaData.java index 25f88d733..32788d998 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerResultSetMetaData.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerResultSetMetaData.java @@ -1,28 +1,26 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; import java.sql.ResultSetMetaData; + /** - * This interface is implemented by {@link SQLServerResultSetMetaData} class. + * Provides an interface to the{@link SQLServerResultSetMetaData} class. */ public interface ISQLServerResultSetMetaData extends ResultSetMetaData { /** - * Returns true if the column is a SQLServer SparseColumnSet + * Returns if the column is a SQLServer SparseColumnSet. * * @param column - * The column number + * The column number * @return true if a column in a result set is a sparse column set, otherwise false. * @throws SQLServerException - * when an error occurs + * when an error occurs */ public boolean isSparseColumnSet(int column) throws SQLServerException; diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerSavepoint.java b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerSavepoint.java index 4fd4dbb1a..3f97fe79b 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerSavepoint.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerSavepoint.java @@ -1,36 +1,34 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; import java.sql.Savepoint; + /** - * This interface is implemented by {@link SQLServerSavepoint} class. + * Provides an interface to the {@link SQLServerSavepoint} class. */ public interface ISQLServerSavepoint extends Savepoint { /** - * Get the savepoint name + * Returns the savepoint name * * @return the name of savepoint */ public String getSavepointName() throws SQLServerException; /** - * Get the savepoint label + * Returns the savepoint label * * @return the label for Savepoint */ public String getLabel(); /** - * Checks if the savepoint label is null + * Returns if the savepoint label is null * * @return true is the savepoint is named. Otherwise, false. */ diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerStatement.java b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerStatement.java index a1ba642a7..51797677b 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerStatement.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerStatement.java @@ -1,15 +1,12 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; /** - * This interface is implemented by {@link SQLServerStatement} class. + * Provides an interface to the {@link SQLServerStatement} class. */ public interface ISQLServerStatement extends java.sql.Statement { /** @@ -24,39 +21,39 @@ public interface ISQLServerStatement extends java.sql.Statement { * "adaptive" - Data Pipe adaptive buffering * * @param value - * A String that contains the response buffering mode. The valid mode can be one of the following case-insensitive Strings: full or - * adaptive. + * A String that contains the response buffering mode. The valid mode can be one of the following + * case-insensitive Strings: full or adaptive. * @throws SQLServerException - * If there are any errors in setting the response buffering mode. + * If there are any errors in setting the response buffering mode. */ public void setResponseBuffering(String value) throws SQLServerException; /** - * Retrieves the response buffering mode for this SQLServerStatement object. + * Returns the response buffering mode for this SQLServerStatement object. * * @return A String that contains a lower-case full or adaptive. * @throws SQLServerException - * If there are any errors in retrieving the response buffering mode. + * If there are any errors in retrieving the response buffering mode. */ public String getResponseBuffering() throws SQLServerException; /** - * Retrieves the cancelQueryTimeout property set on this SQLServerStatement object. + * Returns the cancelQueryTimeout property set on this SQLServerStatement object. * * @return cancelQueryTimeout Time duration in seconds. * @throws SQLServerException - * if any error occurs + * if any error occurs */ public int getCancelQueryTimeout() throws SQLServerException; /** - * Sets the cancelQueryTimeout property on this SQLServerStatement object to cancel queryTimeout set on Connection or - * Statement level. + * Sets the cancelQueryTimeout property on this SQLServerStatement object to cancel + * queryTimeout set on Connection or Statement level. * * @param seconds - * Time duration in seconds. + * Time duration in seconds. * @throws SQLServerException - * if any error occurs + * if any error occurs */ public void setCancelQueryTimeout(int seconds) throws SQLServerException; } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/InternalSpatialDatatype.java b/src/main/java/com/microsoft/sqlserver/jdbc/InternalSpatialDatatype.java index 003e30f5d..dfbf6af68 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/InternalSpatialDatatype.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/InternalSpatialDatatype.java @@ -1,44 +1,44 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; +/** + * Specifies the spatial data types values + */ public enum InternalSpatialDatatype { - POINT((byte)1, "POINT"), - LINESTRING((byte)2, "LINESTRING"), - POLYGON((byte)3, "POLYGON"), - MULTIPOINT((byte)4, "MULTIPOINT"), - MULTILINESTRING((byte)5, "MULTILINESTRING"), - MULTIPOLYGON((byte)6, "MULTIPOLYGON"), - GEOMETRYCOLLECTION((byte)7, "GEOMETRYCOLLECTION"), - CIRCULARSTRING((byte)8, "CIRCULARSTRING"), - COMPOUNDCURVE((byte)9, "COMPOUNDCURVE"), - CURVEPOLYGON((byte)10, "CURVEPOLYGON"), - FULLGLOBE((byte)11, "FULLGLOBE"), - INVALID_TYPE((byte)0, null); - + POINT((byte) 1, "POINT"), + LINESTRING((byte) 2, "LINESTRING"), + POLYGON((byte) 3, "POLYGON"), + MULTIPOINT((byte) 4, "MULTIPOINT"), + MULTILINESTRING((byte) 5, "MULTILINESTRING"), + MULTIPOLYGON((byte) 6, "MULTIPOLYGON"), + GEOMETRYCOLLECTION((byte) 7, "GEOMETRYCOLLECTION"), + CIRCULARSTRING((byte) 8, "CIRCULARSTRING"), + COMPOUNDCURVE((byte) 9, "COMPOUNDCURVE"), + CURVEPOLYGON((byte) 10, "CURVEPOLYGON"), + FULLGLOBE((byte) 11, "FULLGLOBE"), + INVALID_TYPE((byte) 0, null); + private byte typeCode; private String typeName; - + private InternalSpatialDatatype(byte typeCode, String typeName) { this.typeCode = typeCode; this.typeName = typeName; } - - public byte getTypeCode() { + + byte getTypeCode() { return this.typeCode; } - - public String getTypeName() { + + String getTypeName() { return this.typeName; } - - public static InternalSpatialDatatype valueOf(byte typeCode) { + + static InternalSpatialDatatype valueOf(byte typeCode) { for (InternalSpatialDatatype internalType : values()) { if (internalType.typeCode == typeCode) { return internalType; diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/JaasConfiguration.java b/src/main/java/com/microsoft/sqlserver/jdbc/JaasConfiguration.java index 6443724fd..2f8dda592 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/JaasConfiguration.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/JaasConfiguration.java @@ -1,71 +1,72 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ -package com.microsoft.sqlserver.jdbc; - -import java.util.HashMap; -import java.util.Map; - -import javax.security.auth.login.AppConfigurationEntry; -import javax.security.auth.login.Configuration; - -/** - * This class overrides JAAS Configuration and always provide a configuration is not defined for default configuration. - */ -public class JaasConfiguration extends Configuration { - - private final Configuration delegate; - private AppConfigurationEntry[] defaultValue; - - private static AppConfigurationEntry[] generateDefaultConfiguration() { - if (Util.isIBM()) { - Map confDetailsWithoutPassword = new HashMap<>(); - confDetailsWithoutPassword.put("useDefaultCcache", "true"); - Map confDetailsWithPassword = new HashMap<>(); - // We generated a two configurations fallback that is suitable for password and password-less authentication - // See https://www.ibm.com/support/knowledgecenter/SSYKE2_8.0.0/com.ibm.java.security.component.80.doc/security-component/jgssDocs/jaas_login_user.html - final String ibmLoginModule = "com.ibm.security.auth.module.Krb5LoginModule"; - return new AppConfigurationEntry[] { - new AppConfigurationEntry(ibmLoginModule, AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT, confDetailsWithoutPassword), - new AppConfigurationEntry(ibmLoginModule, AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT, confDetailsWithPassword)}; - } - else { - Map confDetails = new HashMap<>(); - confDetails.put("useTicketCache", "true"); - return new AppConfigurationEntry[] {new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule", - AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, confDetails)}; - } - } - - /** - * Package protected constructor. - * - * @param delegate - * a possibly null delegate - */ - JaasConfiguration(Configuration delegate) { - this.delegate = delegate; - this.defaultValue = generateDefaultConfiguration(); - } - - @Override - public AppConfigurationEntry[] getAppConfigurationEntry(String name) { - AppConfigurationEntry[] conf = delegate == null ? null : delegate.getAppConfigurationEntry(name); - // We return our configuration only if user requested default one - // In case where user did request another JAAS Configuration name, we expect he knows what he is doing. - if (conf == null && name.equals(SQLServerDriverStringProperty.JAAS_CONFIG_NAME.getDefaultValue())) { - return defaultValue; - } - return conf; - } - - @Override - public void refresh() { - if (null != delegate) - delegate.refresh(); - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package com.microsoft.sqlserver.jdbc; + +import java.util.HashMap; +import java.util.Map; + +import javax.security.auth.login.AppConfigurationEntry; +import javax.security.auth.login.Configuration; + + +/** + * Overrides JAAS Configuration and always provide a configuration is not defined for default configuration. + */ +public class JaasConfiguration extends Configuration { + + private final Configuration delegate; + private AppConfigurationEntry[] defaultValue; + + private static AppConfigurationEntry[] generateDefaultConfiguration() { + if (Util.isIBM()) { + Map confDetailsWithoutPassword = new HashMap<>(); + confDetailsWithoutPassword.put("useDefaultCcache", "true"); + Map confDetailsWithPassword = new HashMap<>(); + // We generated a two configurations fallback that is suitable for password and password-less authentication + // See + // https://www.ibm.com/support/knowledgecenter/SSYKE2_8.0.0/com.ibm.java.security.component.80.doc/security-component/jgssDocs/jaas_login_user.html + final String ibmLoginModule = "com.ibm.security.auth.module.Krb5LoginModule"; + return new AppConfigurationEntry[] { + new AppConfigurationEntry(ibmLoginModule, AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT, + confDetailsWithoutPassword), + new AppConfigurationEntry(ibmLoginModule, AppConfigurationEntry.LoginModuleControlFlag.SUFFICIENT, + confDetailsWithPassword)}; + } else { + Map confDetails = new HashMap<>(); + confDetails.put("useTicketCache", "true"); + return new AppConfigurationEntry[] { + new AppConfigurationEntry("com.sun.security.auth.module.Krb5LoginModule", + AppConfigurationEntry.LoginModuleControlFlag.REQUIRED, confDetails)}; + } + } + + /** + * Package protected constructor. + * + * @param delegate + * a possibly null delegate + */ + JaasConfiguration(Configuration delegate) { + this.delegate = delegate; + this.defaultValue = generateDefaultConfiguration(); + } + + @Override + public AppConfigurationEntry[] getAppConfigurationEntry(String name) { + AppConfigurationEntry[] conf = delegate == null ? null : delegate.getAppConfigurationEntry(name); + // We return our configuration only if user requested default one + // In case where user did request another JAAS Configuration name, we expect he knows what he is doing. + if (conf == null && name.equals(SQLServerDriverStringProperty.JAAS_CONFIG_NAME.getDefaultValue())) { + return defaultValue; + } + return conf; + } + + @Override + public void refresh() { + if (null != delegate) + delegate.refresh(); + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/KerbAuthentication.java b/src/main/java/com/microsoft/sqlserver/jdbc/KerbAuthentication.java index d3707c2fe..47c95e9de 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/KerbAuthentication.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/KerbAuthentication.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -37,6 +34,7 @@ import com.microsoft.sqlserver.jdbc.dns.DNSKerberosLocator; + /** * KerbAuthentication for int auth. */ @@ -70,14 +68,15 @@ private void intAuthInit() throws SQLServerException { GSSName remotePeerName = manager.createName(spn, null); if (null != peerCredentials) { - peerContext = manager.createContext(remotePeerName, kerberos, peerCredentials, GSSContext.DEFAULT_LIFETIME); + peerContext = manager.createContext(remotePeerName, kerberos, peerCredentials, + GSSContext.DEFAULT_LIFETIME); peerContext.requestCredDeleg(false); peerContext.requestMutualAuth(true); peerContext.requestInteg(true); - } - else { - String configName = con.activeConnectionProperties.getProperty(SQLServerDriverStringProperty.JAAS_CONFIG_NAME.toString(), - SQLServerDriverStringProperty.JAAS_CONFIG_NAME.getDefaultValue()); + } else { + String configName = con.activeConnectionProperties.getProperty( + SQLServerDriverStringProperty.JAAS_CONFIG_NAME.toString(), + SQLServerDriverStringProperty.JAAS_CONFIG_NAME.getDefaultValue()); Subject currentSubject; KerbCallback callback = new KerbCallback(con); try { @@ -89,24 +88,27 @@ private void intAuthInit() throws SQLServerException { // per documentation LoginContext will instantiate a new subject. currentSubject = lc.getSubject(); } - } - catch (LoginException le) { + } catch (LoginException le) { if (authLogger.isLoggable(Level.FINE)) { - authLogger.fine(toString() + "Failed to login using Kerberos due to " + le.getClass().getName() + ":" + le.getMessage()); + authLogger.fine(toString() + "Failed to login using Kerberos due to " + le.getClass().getName() + + ":" + le.getMessage()); } try { // Not very clean since it raises an Exception, but we are sure we are cleaning well everything - con.terminate(SQLServerException.DRIVER_ERROR_NONE, SQLServerException.getErrString("R_integratedAuthenticationFailed"), le); + con.terminate(SQLServerException.DRIVER_ERROR_NONE, + SQLServerException.getErrString("R_integratedAuthenticationFailed"), le); } catch (SQLServerException alwaysTriggered) { - String message = MessageFormat.format(SQLServerException.getErrString("R_kerberosLoginFailed"), - alwaysTriggered.getMessage(), le.getClass().getName(), le.getMessage()); + String message = MessageFormat.format(SQLServerException.getErrString("R_kerberosLoginFailed"), + alwaysTriggered.getMessage(), le.getClass().getName(), le.getMessage()); if (callback.getUsernameRequested() != null) { - message = MessageFormat.format(SQLServerException.getErrString("R_kerberosLoginFailedForUsername"), - callback.getUsernameRequested(), message); + message = MessageFormat.format( + SQLServerException.getErrString("R_kerberosLoginFailedForUsername"), + callback.getUsernameRequested(), message); } // By throwing Exception with LOGON_FAILED -> we avoid looping for connection // In this case, authentication will never work anyway -> fail fast - throw new SQLServerException(message, alwaysTriggered.getSQLState(), SQLServerException.LOGON_FAILED, le); + throw new SQLServerException(message, alwaysTriggered.getSQLState(), + SQLServerException.LOGON_FAILED, le); } return; } @@ -118,8 +120,9 @@ private void intAuthInit() throws SQLServerException { if (authLogger.isLoggable(Level.FINER)) { authLogger.finer(toString() + " creating security context"); } - - peerContext = manager.createContext(remotePeerName, kerberos, peerCredentials, GSSContext.DEFAULT_LIFETIME); + + peerContext = manager.createContext(remotePeerName, kerberos, peerCredentials, + GSSContext.DEFAULT_LIFETIME); // The following flags should be inline with our native implementation. peerContext.requestCredDeleg(true); peerContext.requestMutualAuth(true); @@ -129,18 +132,18 @@ private void intAuthInit() throws SQLServerException { catch (GSSException ge) { authLogger.finer(toString() + "initAuthInit failed GSSException:-" + ge); - con.terminate(SQLServerException.DRIVER_ERROR_NONE, SQLServerException.getErrString("R_integratedAuthenticationFailed"), ge); - } - catch (PrivilegedActionException ge) { + con.terminate(SQLServerException.DRIVER_ERROR_NONE, + SQLServerException.getErrString("R_integratedAuthenticationFailed"), ge); + } catch (PrivilegedActionException ge) { authLogger.finer(toString() + "initAuthInit failed privileged exception:-" + ge); - con.terminate(SQLServerException.DRIVER_ERROR_NONE, SQLServerException.getErrString("R_integratedAuthenticationFailed"), ge); + con.terminate(SQLServerException.DRIVER_ERROR_NONE, + SQLServerException.getErrString("R_integratedAuthenticationFailed"), ge); } } // We have to do a privileged action to create the credential of the user in the current context - private static GSSCredential getClientCredential(final Subject subject, - final GSSManager MANAGER, + private static GSSCredential getClientCredential(final Subject subject, final GSSManager MANAGER, final Oid kerboid) throws PrivilegedActionException { final PrivilegedExceptionAction action = new PrivilegedExceptionAction() { public GSSCredential run() throws GSSException { @@ -149,14 +152,13 @@ public GSSCredential run() throws GSSException { } }; // TO support java 5, 6 we have to do this - // The signature for Java 5 returns an object 6 returns GSSCredential, immediate casting throws + // The signature for Java 5 returns an object 6 returns GSSCredential, immediate casting throws // warning in Java 6. Object credential = Subject.doAs(subject, action); return (GSSCredential) credential; } - private byte[] intAuthHandShake(byte[] pin, - boolean[] done) throws SQLServerException { + private byte[] intAuthHandShake(byte[] pin, boolean[] done) throws SQLServerException { try { if (authLogger.isLoggable(Level.FINER)) { authLogger.finer(toString() + " Sending token to server over secure context"); @@ -167,26 +169,25 @@ private byte[] intAuthHandShake(byte[] pin, done[0] = true; if (authLogger.isLoggable(Level.FINER)) authLogger.finer(toString() + "Authentication done."); - } - else if (null == byteToken) { + } else if (null == byteToken) { // The documentation is not clear on when this can happen but it does say this could happen if (authLogger.isLoggable(Level.INFO)) { authLogger.info(toString() + "byteToken is null in initSecContext."); } - con.terminate(SQLServerException.DRIVER_ERROR_NONE, SQLServerException.getErrString("R_integratedAuthenticationFailed")); + con.terminate(SQLServerException.DRIVER_ERROR_NONE, + SQLServerException.getErrString("R_integratedAuthenticationFailed")); } return byteToken; - } - catch (GSSException ge) { + } catch (GSSException ge) { authLogger.finer(toString() + "initSecContext Failed :-" + ge); - con.terminate(SQLServerException.DRIVER_ERROR_NONE, SQLServerException.getErrString("R_integratedAuthenticationFailed"), ge); + con.terminate(SQLServerException.DRIVER_ERROR_NONE, + SQLServerException.getErrString("R_integratedAuthenticationFailed"), ge); } // keep the compiler happy return null; } - private String makeSpn(String server, - int port) throws SQLServerException { + private String makeSpn(String server, int port) throws SQLServerException { if (authLogger.isLoggable(Level.FINER)) { authLogger.finer(toString() + " Server: " + server + " port: " + port); } @@ -195,8 +196,7 @@ private String makeSpn(String server, // FQDN must be provided if (con.serverNameAsACE()) { spn.append(IDN.toASCII(server)); - } - else { + } else { spn.append(server); } spn.append(":"); @@ -209,37 +209,35 @@ private String makeSpn(String server, } // Package visible members below. - KerbAuthentication(SQLServerConnection con, - String address, - int port) throws SQLServerException { + KerbAuthentication(SQLServerConnection con, String address, int port) throws SQLServerException { this.con = con; // Get user provided SPN string; if not provided then build the generic one - String userSuppliedServerSpn = con.activeConnectionProperties.getProperty(SQLServerDriverStringProperty.SERVER_SPN.toString()); + String userSuppliedServerSpn = con.activeConnectionProperties + .getProperty(SQLServerDriverStringProperty.SERVER_SPN.toString()); String spn; if (null != userSuppliedServerSpn) { // serverNameAsACE is true, translate the user supplied serverSPN to ASCII if (con.serverNameAsACE()) { int slashPos = userSuppliedServerSpn.indexOf("/"); - spn = userSuppliedServerSpn.substring(0, slashPos + 1) + IDN.toASCII(userSuppliedServerSpn.substring(slashPos + 1)); - } - else { + spn = userSuppliedServerSpn.substring(0, slashPos + 1) + + IDN.toASCII(userSuppliedServerSpn.substring(slashPos + 1)); + } else { spn = userSuppliedServerSpn; } - } - else { + } else { spn = makeSpn(address, port); } this.spn = enrichSpnWithRealm(spn, null == userSuppliedServerSpn); - if (!this.spn.equals(spn) && authLogger.isLoggable(Level.FINER)){ + if (!this.spn.equals(spn) && authLogger.isLoggable(Level.FINER)) { authLogger.finer(toString() + "SPN enriched: " + spn + " := " + this.spn); } - } + } - private static final Pattern SPN_PATTERN = Pattern.compile("MSSQLSvc/(.*):([^:@]+)(@.+)?", Pattern.CASE_INSENSITIVE); + private static final Pattern SPN_PATTERN = Pattern.compile("MSSQLSvc/(.*):([^:@]+)(@.+)?", + Pattern.CASE_INSENSITIVE); - private String enrichSpnWithRealm(String spn, - boolean allowHostnameCanonicalization) { + private String enrichSpnWithRealm(String spn, boolean allowHostnameCanonicalization) { if (spn == null) { return spn; } @@ -263,15 +261,13 @@ private String enrichSpnWithRealm(String spn, // Since we have a match, our hostname is the correct one (for instance of server // name was an IP), so we override dnsName as well dnsName = canonicalHostName; - } - catch (UnknownHostException cannotCanonicalize) { + } catch (UnknownHostException cannotCanonicalize) { // ignored, but we are in a bad shape } } if (realm == null) { return spn; - } - else { + } else { StringBuilder sb = new StringBuilder("MSSQLSvc/"); sb.append(dnsName).append(":").append(portOrInstance).append("@").append(realm.toUpperCase(Locale.ENGLISH)); return sb.toString(); @@ -284,7 +280,7 @@ private String enrichSpnWithRealm(String spn, * Find a suitable way of validating a REALM for given JVM. * * @param hostnameToTest - * an example hostname we are gonna use to test our realm validator. + * an example hostname we are gonna use to test our realm validator. * @return a not null realm Validator. */ static RealmValidator getRealmValidator(String hostnameToTest) { @@ -304,8 +300,7 @@ public boolean isRealmValid(String realm) { try { Object ret = getKDCList.invoke(instance, realm); return ret != null; - } - catch (Exception err) { + } catch (Exception err) { return false; } } @@ -319,9 +314,9 @@ public boolean isRealmValid(String realm) { authLogger.fine("Kerberos Realm Validator: Using Built-in Oracle Realm Validation method."); return oracleRealmValidator; } - authLogger.fine("Kerberos Realm Validator: Detected buggy Oracle Realm Validator, using DNSKerberosLocator."); - } - catch (ReflectiveOperationException notTheRightJVMException) { + authLogger + .fine("Kerberos Realm Validator: Detected buggy Oracle Realm Validator, using DNSKerberosLocator."); + } catch (ReflectiveOperationException notTheRightJVMException) { // Ignored, we simply are not using the right JVM authLogger.fine("Kerberos Realm Validator: No Oracle Realm Validator Available, using DNSKerberosLocator."); } @@ -331,8 +326,7 @@ public boolean isRealmValid(String realm) { public boolean isRealmValid(String realm) { try { return DNSKerberosLocator.isRealmValid(realm); - } - catch (NamingException err) { + } catch (NamingException err) { return false; } } @@ -344,13 +338,12 @@ public boolean isRealmValid(String realm) { * Try to find a REALM in the different parts of a host name. * * @param realmValidator - * a function that return true if REALM is valid and exists + * a function that return true if REALM is valid and exists * @param hostname - * the name we are looking a REALM for + * the name we are looking a REALM for * @return the realm if found, null otherwise */ - private String findRealmFromHostname(RealmValidator realmValidator, - String hostname) { + private String findRealmFromHostname(RealmValidator realmValidator, String hostname) { if (hostname == null) { return null; } @@ -386,17 +379,14 @@ interface RealmValidator { * @param ImpersonatedUserCred * @throws SQLServerException */ - KerbAuthentication(SQLServerConnection con, - String address, - int port, - GSSCredential ImpersonatedUserCred, Boolean isUserCreated) throws SQLServerException { + KerbAuthentication(SQLServerConnection con, String address, int port, GSSCredential ImpersonatedUserCred, + Boolean isUserCreated) throws SQLServerException { this(con, address, port); peerCredentials = ImpersonatedUserCred; this.isUserCreatedCredential = (isUserCreated == null ? false : isUserCreated); } - byte[] GenerateClientContext(byte[] pin, - boolean[] done) throws SQLServerException { + byte[] GenerateClientContext(byte[] pin, boolean[] done) throws SQLServerException { if (null == peerContext) { intAuthInit(); } @@ -414,14 +404,14 @@ int ReleaseClientContext() throws SQLServerException { peerContext.dispose(); if (null != lc) lc.logout(); - } - catch (LoginException e) { - // yes we are eating exceptions here but this should not fail in the normal circumstances and we do not want to eat previous + } catch (LoginException e) { + // yes we are eating exceptions here but this should not fail in the normal circumstances and we do not want + // to eat previous // login errors if caused before which is more useful to the user than the cleanup errors. authLogger.fine(toString() + " Release of the credentials failed LoginException: " + e); - } - catch (GSSException e) { - // yes we are eating exceptions here but this should not fail in the normal circumstances and we do not want to eat previous + } catch (GSSException e) { + // yes we are eating exceptions here but this should not fail in the normal circumstances and we do not want + // to eat previous // login errors if caused before which is more useful to the user than the cleanup errors. authLogger.fine(toString() + " Release of the credentials failed GSSException: " + e); } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/KerbCallback.java b/src/main/java/com/microsoft/sqlserver/jdbc/KerbCallback.java index f2e312008..454688591 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/KerbCallback.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/KerbCallback.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -18,6 +15,10 @@ import javax.security.auth.callback.PasswordCallback; import javax.security.auth.callback.UnsupportedCallbackException; + +/** + * Provides implemention of the callback handler for Kerberos. + */ public class KerbCallback implements CallbackHandler { private final SQLServerConnection con; @@ -27,8 +28,7 @@ public class KerbCallback implements CallbackHandler { this.con = con; } - private static String getAnyOf(Callback callback, - Properties properties, + private static String getAnyOf(Callback callback, Properties properties, String... names) throws UnsupportedCallbackException { for (String name : names) { String val = properties.getProperty(name); @@ -36,11 +36,12 @@ private static String getAnyOf(Callback callback, return val; } } - throw new UnsupportedCallbackException(callback, "Cannot get any of properties: " + Arrays.toString(names) + " from con properties"); + throw new UnsupportedCallbackException(callback, + "Cannot get any of properties: " + Arrays.toString(names) + " from con properties"); } /** - * If a name was retrieved By Kerberos, return it. + * Returns if a name was retrieved By Kerberos. * * @return null if callback was not called or username was not provided */ @@ -52,10 +53,12 @@ public String getUsernameRequested() { public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { for (Callback callback : callbacks) { if (callback instanceof NameCallback) { - usernameRequested = getAnyOf(callback, con.activeConnectionProperties, "user", SQLServerDriverStringProperty.USER.name()); + usernameRequested = getAnyOf(callback, con.activeConnectionProperties, "user", + SQLServerDriverStringProperty.USER.name()); ((NameCallback) callback).setName(usernameRequested); } else if (callback instanceof PasswordCallback) { - String password = getAnyOf(callback, con.activeConnectionProperties, "password", SQLServerDriverStringProperty.PASSWORD.name()); + String password = getAnyOf(callback, con.activeConnectionProperties, "password", + SQLServerDriverStringProperty.PASSWORD.name()); ((PasswordCallback) callback).setPassword(password.toCharArray()); } else { diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/KeyStoreProviderCommon.java b/src/main/java/com/microsoft/sqlserver/jdbc/KeyStoreProviderCommon.java index 8db7b9a61..1da236fcb 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/KeyStoreProviderCommon.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/KeyStoreProviderCommon.java @@ -1,181 +1,176 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.NoSuchAlgorithmException; -import java.security.Signature; -import java.security.SignatureException; -import java.security.cert.X509Certificate; -import java.text.MessageFormat; - -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; - -/** - * - * This class holds information about the certificate - * - */ -class CertificateDetails { - X509Certificate certificate; - Key privateKey; - - CertificateDetails(X509Certificate certificate, - Key privateKey) { - this.certificate = certificate; - this.privateKey = privateKey; - } -} - -class KeyStoreProviderCommon { - - static final String rsaEncryptionAlgorithmWithOAEP = "RSA_OAEP"; - static byte[] version = new byte[] {0x01}; - - static void validateEncryptionAlgorithm(String encryptionAlgorithm, - boolean isEncrypt) throws SQLServerException { - String errString = isEncrypt ? "R_NullKeyEncryptionAlgorithm" : "R_NullKeyEncryptionAlgorithmInternal"; - if (null == encryptionAlgorithm) { - - throw new SQLServerException(null, SQLServerException.getErrString(errString), null, 0, false); - - } - - errString = isEncrypt ? "R_InvalidKeyEncryptionAlgorithm" : "R_InvalidKeyEncryptionAlgorithmInternal"; - if (!rsaEncryptionAlgorithmWithOAEP.equalsIgnoreCase(encryptionAlgorithm.trim())) { - - MessageFormat form = new MessageFormat(SQLServerException.getErrString(errString)); - Object[] msgArgs = {encryptionAlgorithm, rsaEncryptionAlgorithmWithOAEP}; - throw new SQLServerException(form.format(msgArgs), null); - - } - } - - static void validateNonEmptyMasterKeyPath(String masterKeyPath) throws SQLServerException { - if (null == masterKeyPath || masterKeyPath.trim().length() == 0) { - throw new SQLServerException(null, SQLServerException.getErrString("R_InvalidMasterKeyDetails"), null, 0, false); - } - } - - static byte[] decryptColumnEncryptionKey(String masterKeyPath, - String encryptionAlgorithm, - byte[] encryptedColumnEncryptionKey, - CertificateDetails certificateDetails) throws SQLServerException { - if (null == encryptedColumnEncryptionKey) { - - throw new SQLServerException(null, SQLServerException.getErrString("R_NullEncryptedColumnEncryptionKey"), null, 0, false); - - } - else if (0 == encryptedColumnEncryptionKey.length) { - - throw new SQLServerException(null, SQLServerException.getErrString("R_EmptyEncryptedColumnEncryptionKey"), null, 0, false); - - } - - validateEncryptionAlgorithm(encryptionAlgorithm, false); - - int currentIndex = version.length; - int keyPathLength = convertTwoBytesToShort(encryptedColumnEncryptionKey, currentIndex); - // We just read 2 bytes - currentIndex += 2; - - // Get ciphertext length - int cipherTextLength = convertTwoBytesToShort(encryptedColumnEncryptionKey, currentIndex); - currentIndex += 2; - - currentIndex += keyPathLength; - - int signatureLength = encryptedColumnEncryptionKey.length - currentIndex - cipherTextLength; - - // Get ciphertext - byte[] cipherText = new byte[cipherTextLength]; - System.arraycopy(encryptedColumnEncryptionKey, currentIndex, cipherText, 0, cipherTextLength); - currentIndex += cipherTextLength; - - byte[] signature = new byte[signatureLength]; - System.arraycopy(encryptedColumnEncryptionKey, currentIndex, signature, 0, signatureLength); - - byte[] hash = new byte[encryptedColumnEncryptionKey.length - signature.length]; - - System.arraycopy(encryptedColumnEncryptionKey, 0, hash, 0, encryptedColumnEncryptionKey.length - signature.length); - - if (!verifyRSASignature(hash, signature, certificateDetails.certificate, masterKeyPath)) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidCertificateSignature")); - Object[] msgArgs = {masterKeyPath}; - throw new SQLServerException(form.format(msgArgs), null); - } - - byte[] plainCEK = decryptRSAOAEP(cipherText, certificateDetails); - - return plainCEK; - } - - private static byte[] decryptRSAOAEP(byte[] cipherText, - CertificateDetails certificateDetails) throws SQLServerException { - byte[] plainCEK = null; - try { - Cipher rsa = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding"); - rsa.init(Cipher.DECRYPT_MODE, certificateDetails.privateKey); - rsa.update(cipherText); - plainCEK = rsa.doFinal(); - } - catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException e) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_CEKDecryptionFailed")); - Object[] msgArgs = {e.getMessage()}; - throw new SQLServerException(form.format(msgArgs), e); - } - - return plainCEK; - - } - - private static boolean verifyRSASignature(byte[] hash, - byte[] signature, - X509Certificate certificate, - String masterKeyPath) throws SQLServerException { - Signature signVerify; - boolean verificationSucess = false; - try { - signVerify = Signature.getInstance("SHA256withRSA"); - signVerify.initVerify(certificate.getPublicKey()); - signVerify.update(hash); - verificationSucess = signVerify.verify(signature); - } - catch (InvalidKeyException | NoSuchAlgorithmException | SignatureException e) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidCertificateSignature")); - Object[] msgArgs = {masterKeyPath}; - throw new SQLServerException(form.format(msgArgs), e); - } - - return verificationSucess; - - } - - private static short convertTwoBytesToShort(byte[] input, - int index) throws SQLServerException { - - short shortVal; - if (index + 1 >= input.length) { - throw new SQLServerException(null, SQLServerException.getErrString("R_ByteToShortConversion"), null, 0, false); - } - ByteBuffer byteBuffer = ByteBuffer.allocate(2); - byteBuffer.order(ByteOrder.LITTLE_ENDIAN); - byteBuffer.put(input[index]); - byteBuffer.put(input[index + 1]); - shortVal = byteBuffer.getShort(0); - return shortVal; - - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.Signature; +import java.security.SignatureException; +import java.security.cert.X509Certificate; +import java.text.MessageFormat; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; + + +/** + * + * This class holds information about the certificate + * + */ +class CertificateDetails { + X509Certificate certificate; + Key privateKey; + + CertificateDetails(X509Certificate certificate, Key privateKey) { + this.certificate = certificate; + this.privateKey = privateKey; + } +} + + +class KeyStoreProviderCommon { + + static final String rsaEncryptionAlgorithmWithOAEP = "RSA_OAEP"; + static byte[] version = new byte[] {0x01}; + + static void validateEncryptionAlgorithm(String encryptionAlgorithm, boolean isEncrypt) throws SQLServerException { + String errString = isEncrypt ? "R_NullKeyEncryptionAlgorithm" : "R_NullKeyEncryptionAlgorithmInternal"; + if (null == encryptionAlgorithm) { + + throw new SQLServerException(null, SQLServerException.getErrString(errString), null, 0, false); + + } + + errString = isEncrypt ? "R_InvalidKeyEncryptionAlgorithm" : "R_InvalidKeyEncryptionAlgorithmInternal"; + if (!rsaEncryptionAlgorithmWithOAEP.equalsIgnoreCase(encryptionAlgorithm.trim())) { + + MessageFormat form = new MessageFormat(SQLServerException.getErrString(errString)); + Object[] msgArgs = {encryptionAlgorithm, rsaEncryptionAlgorithmWithOAEP}; + throw new SQLServerException(form.format(msgArgs), null); + + } + } + + static void validateNonEmptyMasterKeyPath(String masterKeyPath) throws SQLServerException { + if (null == masterKeyPath || masterKeyPath.trim().length() == 0) { + throw new SQLServerException(null, SQLServerException.getErrString("R_InvalidMasterKeyDetails"), null, 0, + false); + } + } + + static byte[] decryptColumnEncryptionKey(String masterKeyPath, String encryptionAlgorithm, + byte[] encryptedColumnEncryptionKey, CertificateDetails certificateDetails) throws SQLServerException { + if (null == encryptedColumnEncryptionKey) { + + throw new SQLServerException(null, SQLServerException.getErrString("R_NullEncryptedColumnEncryptionKey"), + null, 0, false); + + } else if (0 == encryptedColumnEncryptionKey.length) { + + throw new SQLServerException(null, SQLServerException.getErrString("R_EmptyEncryptedColumnEncryptionKey"), + null, 0, false); + + } + + validateEncryptionAlgorithm(encryptionAlgorithm, false); + + int currentIndex = version.length; + int keyPathLength = convertTwoBytesToShort(encryptedColumnEncryptionKey, currentIndex); + // We just read 2 bytes + currentIndex += 2; + + // Get ciphertext length + int cipherTextLength = convertTwoBytesToShort(encryptedColumnEncryptionKey, currentIndex); + currentIndex += 2; + + currentIndex += keyPathLength; + + int signatureLength = encryptedColumnEncryptionKey.length - currentIndex - cipherTextLength; + + // Get ciphertext + byte[] cipherText = new byte[cipherTextLength]; + System.arraycopy(encryptedColumnEncryptionKey, currentIndex, cipherText, 0, cipherTextLength); + currentIndex += cipherTextLength; + + byte[] signature = new byte[signatureLength]; + System.arraycopy(encryptedColumnEncryptionKey, currentIndex, signature, 0, signatureLength); + + byte[] hash = new byte[encryptedColumnEncryptionKey.length - signature.length]; + + System.arraycopy(encryptedColumnEncryptionKey, 0, hash, 0, + encryptedColumnEncryptionKey.length - signature.length); + + if (!verifyRSASignature(hash, signature, certificateDetails.certificate, masterKeyPath)) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidCertificateSignature")); + Object[] msgArgs = {masterKeyPath}; + throw new SQLServerException(form.format(msgArgs), null); + } + + byte[] plainCEK = decryptRSAOAEP(cipherText, certificateDetails); + + return plainCEK; + } + + private static byte[] decryptRSAOAEP(byte[] cipherText, + CertificateDetails certificateDetails) throws SQLServerException { + byte[] plainCEK = null; + try { + Cipher rsa = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding"); + rsa.init(Cipher.DECRYPT_MODE, certificateDetails.privateKey); + rsa.update(cipherText); + plainCEK = rsa.doFinal(); + } catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException + | BadPaddingException e) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_CEKDecryptionFailed")); + Object[] msgArgs = {e.getMessage()}; + throw new SQLServerException(form.format(msgArgs), e); + } + + return plainCEK; + + } + + private static boolean verifyRSASignature(byte[] hash, byte[] signature, X509Certificate certificate, + String masterKeyPath) throws SQLServerException { + Signature signVerify; + boolean verificationSucess = false; + try { + signVerify = Signature.getInstance("SHA256withRSA"); + signVerify.initVerify(certificate.getPublicKey()); + signVerify.update(hash); + verificationSucess = signVerify.verify(signature); + } catch (InvalidKeyException | NoSuchAlgorithmException | SignatureException e) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidCertificateSignature")); + Object[] msgArgs = {masterKeyPath}; + throw new SQLServerException(form.format(msgArgs), e); + } + + return verificationSucess; + + } + + private static short convertTwoBytesToShort(byte[] input, int index) throws SQLServerException { + + short shortVal; + if (index + 1 >= input.length) { + throw new SQLServerException(null, SQLServerException.getErrString("R_ByteToShortConversion"), null, 0, + false); + } + ByteBuffer byteBuffer = ByteBuffer.allocate(2); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); + byteBuffer.put(input[index]); + byteBuffer.put(input[index + 1]); + shortVal = byteBuffer.getShort(0); + return shortVal; + + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/KeyVaultCredential.java b/src/main/java/com/microsoft/sqlserver/jdbc/KeyVaultCredential.java index 470078242..0c75fae75 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/KeyVaultCredential.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/KeyVaultCredential.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -17,6 +14,7 @@ import com.microsoft.aad.adal4j.ClientCredential; import com.microsoft.azure.keyvault.authentication.KeyVaultCredentials; + /** * * An implementation of ServiceClientCredentials that supports automatic bearer token refresh. @@ -29,8 +27,7 @@ class KeyVaultCredential extends KeyVaultCredentials { String clientKey = null; String accessToken = null; - KeyVaultCredential(String clientId, - String clientKey) { + KeyVaultCredential(String clientId, String clientKey) { this.clientId = clientId; this.clientKey = clientKey; } @@ -39,24 +36,20 @@ class KeyVaultCredential extends KeyVaultCredentials { this.authenticationCallback = authenticationCallback; } - public String doAuthenticate(String authorization, - String resource, - String scope) { + public String doAuthenticate(String authorization, String resource, String scope) { String accessToken; if (null == authenticationCallback) { - AuthenticationResult token = getAccessTokenFromClientCredentials(authorization, resource, clientId, clientKey); + AuthenticationResult token = getAccessTokenFromClientCredentials(authorization, resource, clientId, + clientKey); accessToken = token.getAccessToken(); - } - else { + } else { accessToken = authenticationCallback.getAccessToken(authorization, resource, scope); } return accessToken; } - private static AuthenticationResult getAccessTokenFromClientCredentials(String authorization, - String resource, - String clientId, - String clientKey) { + private static AuthenticationResult getAccessTokenFromClientCredentials(String authorization, String resource, + String clientId, String clientKey) { AuthenticationContext context = null; AuthenticationResult result = null; ExecutorService service = null; @@ -66,11 +59,9 @@ private static AuthenticationResult getAccessTokenFromClientCredentials(String a ClientCredential credentials = new ClientCredential(clientId, clientKey); Future future = context.acquireToken(resource, credentials, null); result = future.get(); - } - catch (Exception e) { + } catch (Exception e) { throw new RuntimeException(e); - } - finally { + } finally { service.shutdown(); } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/PLPInputStream.java b/src/main/java/com/microsoft/sqlserver/jdbc/PLPInputStream.java index 43818afd8..0b4563e0b 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/PLPInputStream.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/PLPInputStream.java @@ -1,526 +1,502 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -import java.io.ByteArrayInputStream; -import java.io.IOException; - -/** - * PLPInputStream is an InputStream implementation that reads from a TDS PLP stream. - * - * Note PLP stands for Partially Length-prefixed Bytes. TDS 7.2 introduced this new streaming format for streaming of large types such as - * varchar(max), nvarchar(max), varbinary(max) and XML. - * - * See TDS specification, 6.3.3 Datatype Dependant Data Streams: Partially Length-prefixed Bytes for more details on the PLP format. - */ - -class PLPInputStream extends BaseInputStream { - static final long PLP_NULL = 0xFFFFFFFFFFFFFFFFL; - static final long UNKNOWN_PLP_LEN = 0xFFFFFFFFFFFFFFFEL; - static final int PLP_TERMINATOR = 0x00000000; - private final static byte[] EMPTY_PLP_BYTES = new byte[0]; - - // Stated length of the PLP stream payload; -1 if unknown length. - int payloadLength; - - private static final int PLP_EOS = -1; - private int currentChunkRemain; - - private int markedChunkRemain; - private int leftOverReadLimit = 0; - - private byte[] oneByteArray = new byte[1]; - - /** - * Non-destructive method for checking whether a PLP value at the current TDSReader location is null. - */ - final static boolean isNull(TDSReader tdsReader) throws SQLServerException { - TDSReaderMark mark = tdsReader.mark(); - //Temporary stream cannot get closes, since it closes the main stream. - try { - return null == PLPInputStream.makeTempStream(tdsReader, false, null); - } - finally { - tdsReader.reset(mark); - } - } - - /** - * Create a new input stream. - * - * @param tdsReader - * TDS reader pointing at the start of the PLP data - * @param discardValue - * boolean to represent if base input stream is adaptive and is streaming - * @param dtv - * DTV implementation for values set from the TDS response stream. - * @return PLPInputStream that is created - * @throws SQLServerException - * when an error occurs - */ - final static PLPInputStream makeTempStream(TDSReader tdsReader, - boolean discardValue, - ServerDTVImpl dtv) throws SQLServerException { - return makeStream(tdsReader, discardValue, discardValue, dtv); - } - - final static PLPInputStream makeStream(TDSReader tdsReader, - InputStreamGetterArgs getterArgs, - ServerDTVImpl dtv) throws SQLServerException { - PLPInputStream is = makeStream(tdsReader, getterArgs.isAdaptive, getterArgs.isStreaming, dtv); - if (null != is) - is.setLoggingInfo(getterArgs.logContext); - return is; - } - - private static PLPInputStream makeStream(TDSReader tdsReader, - boolean isAdaptive, - boolean isStreaming, - ServerDTVImpl dtv) throws SQLServerException { - // Read total length of PLP stream. - long payloadLength = tdsReader.readLong(); - - // If length is PLP_NULL, then return a null PLP value. - if (PLP_NULL == payloadLength) - return null; - - return new PLPInputStream(tdsReader, payloadLength, isAdaptive, isStreaming, dtv); - } - - /** - * Initializes the input stream. - */ - PLPInputStream(TDSReader tdsReader, - long statedPayloadLength, - boolean isAdaptive, - boolean isStreaming, - ServerDTVImpl dtv) throws SQLServerException { - super(tdsReader, isAdaptive, isStreaming, dtv); - this.payloadLength = (UNKNOWN_PLP_LEN != statedPayloadLength) ? ((int) statedPayloadLength) : -1; - this.currentChunkRemain = this.markedChunkRemain = 0; - } - - /** - * Helper function to convert the entire PLP stream into a contiguous byte array. This call is inefficient (in terms of memory usage and run time) - * for very large PLPs. Use it only if a contiguous byte array is required. - */ - byte[] getBytes() throws SQLServerException { - byte[] value; - - // The following 0-byte read just ensures that the number of bytes - // remaining in the current chunk is known. - readBytesInternal(null, 0, 0); - - if (PLP_EOS == currentChunkRemain) { - value = EMPTY_PLP_BYTES; - } - else { - // If the PLP payload length is known, allocate the final byte array now. - // Otherwise, start with the size of the first chunk. Additional chunks - // will cause the array to be reallocated & copied. - value = new byte[(-1 != payloadLength) ? payloadLength : currentChunkRemain]; - - int bytesRead = 0; - while (PLP_EOS != currentChunkRemain) { - // If the current byte array isn't large enough to hold - // the contents of the current chunk, then make it larger. - if (value.length == bytesRead) { - byte[] newValue = new byte[bytesRead + currentChunkRemain]; - System.arraycopy(value, 0, newValue, 0, bytesRead); - value = newValue; - } - - bytesRead += readBytesInternal(value, bytesRead, currentChunkRemain); - } - } - - // Always close the stream after retrieving it - try { - close(); - } - catch (IOException e) { - SQLServerException.makeFromDriverError(null, null, e.getMessage(), null, true); - } - - return value; - } - - /** - * Skips over and discards n bytes of data from this input stream. - * - * @param n - * the number of bytes to be skipped. - * @return the actual number of bytes skipped. - * @exception IOException - * if an I/O error occurs. - */ - public long skip(long n) throws IOException { - checkClosed(); - if (n < 0) - return 0L; - if (n > Integer.MAX_VALUE) - n = Integer.MAX_VALUE; - - long bytesread = readBytes(null, 0, (int) n); - - if (-1 == bytesread) - return 0; - else - return bytesread; - } - - /** - * Returns the number of bytes that can be read (or skipped over) from this input stream without blocking by the next caller of a method for this - * input stream. - * - * @return the actual number of bytes available. - * @exception IOException - * if an I/O error occurs. - */ - public int available() throws IOException { - checkClosed(); - try { - - // The following 0-byte read just ensures that the number of bytes - // remaining in the current chunk is known. - if (0 == currentChunkRemain) - readBytesInternal(null, 0, 0); - - if (PLP_EOS == currentChunkRemain) - return 0; - - // Return the lesser of the number of bytes available for reading - // from the underlying TDSReader and the number of bytes left in - // the current chunk. - int available = tdsReader.available(); - if (available > currentChunkRemain) - available = currentChunkRemain; - - return available; - } - catch (SQLServerException e) { - throw new IOException(e.getMessage()); - } - - } - - /** - * Reads the next byte of data from the input stream. - * - * @return the byte read or -1 meaning no more bytes. - * @exception IOException - * if an I/O error occurs. - */ - public int read() throws IOException { - checkClosed(); - - if (-1 != readBytes(oneByteArray, 0, 1)) - return oneByteArray[0] & 0xFF; - return -1; - } - - /** - * Reads available data into supplied byte array. - * - * @param b - * array of bytes to fill. - * @return the number of bytes read or 0 meaning no bytes read. - * @exception IOException - * if an I/O error occurs. - */ - public int read(byte[] b) throws IOException { - // If b is null, a NullPointerException is thrown. - if (null == b) - throw new NullPointerException(); - - checkClosed(); - - return readBytes(b, 0, b.length); - } - - /** - * Reads available data into supplied byte array. - * - * @param b - * array of bytes to fill. - * @param offset - * the offset into array b where to start writing. - * @param maxBytes - * the max number of bytes to write into b. - * @return the number of bytes read or 0 meaning no bytes read. - * @exception IOException - * if an I/O error occurs. - */ - public int read(byte b[], - int offset, - int maxBytes) throws IOException { - // If b is null, a NullPointerException is thrown. - if (null == b) - throw new NullPointerException(); - - // Verify offset and maxBytes against target buffer if we're reading (as opposed to skipping). - // If offset is negative, or maxBytes is negative, or offset+maxBytes - // is greater than the length of the array b, then an IndexOutOfBoundsException is thrown. - if (offset < 0 || maxBytes < 0 || offset + maxBytes > b.length) - throw new IndexOutOfBoundsException(); - - checkClosed(); - - return readBytes(b, offset, maxBytes); - } - - /** - * Reads available data into supplied byte array b. - * - * @param b - * array of bytes to fill. If b is null, method will skip over data. - * @param offset - * the offset into array b where to start writing. - * @param maxBytes - * the max number of bytes to write into b. - * @return the number of bytes read or 0 meaning no bytes read or -1 meaning EOS. - * @exception IOException - * if an I/O error occurs. - */ - int readBytes(byte[] b, - int offset, - int maxBytes) throws IOException { - // If maxBytes is zero, then no bytes are read and 0 is returned - // This must be done here rather than in readBytesInternal since a 0-byte read - // there may return -1 at EOS. - if (0 == maxBytes) - return 0; - - try { - return readBytesInternal(b, offset, maxBytes); - } - catch (SQLServerException e) { - throw new IOException(e.getMessage()); - } - } - - private int readBytesInternal(byte b[], - int offset, - int maxBytes) throws SQLServerException { - // If we're at EOS, say so. - // Note: For back compat, this special case needs to always be handled - // before checking user-supplied arguments below. - if (PLP_EOS == currentChunkRemain) - return -1; - - // Save off the current TDSReader position, wherever it is, and start reading - // from where we left off last time. - - int bytesRead = 0; - for (;;) { - // Check that we have bytes left to read from the current chunk. - // If not then figure out the size of the next chunk or - // determine that we have reached the end of the stream. - if (0 == currentChunkRemain) { - currentChunkRemain = (int) tdsReader.readUnsignedInt(); - assert currentChunkRemain >= 0; - if (0 == currentChunkRemain) { - currentChunkRemain = PLP_EOS; - break; - } - } - - if (bytesRead == maxBytes) - break; - - // Now we know there are bytes to be read in the current chunk. - // Further limit the max number of bytes we can read to whatever - // remains in the current chunk. - int bytesToRead = maxBytes - bytesRead; - if (bytesToRead > currentChunkRemain) - bytesToRead = currentChunkRemain; - - // Skip/Read as many bytes as we can, given the constraints. - if (null == b) - tdsReader.skip(bytesToRead); - else - tdsReader.readBytes(b, offset + bytesRead, bytesToRead); - - bytesRead += bytesToRead; - currentChunkRemain -= bytesToRead; - } - - if (bytesRead > 0) { - if (isReadLimitSet && leftOverReadLimit > 0) { - leftOverReadLimit = leftOverReadLimit - bytesRead; - if (leftOverReadLimit < 0) - clearCurrentMark(); - } - return bytesRead; - } - - if (PLP_EOS == currentChunkRemain) - return -1; - - return 0; - } - - /** - * Marks the current position in this input stream. - * - * @param readlimit - * the number of bytes to hold (this implementation ignores this). - */ - public void mark(int readLimit) { - // Save off current position and how much of the current chunk remains - // cant throw if the tdsreader is null - if (null != tdsReader && readLimit > 0) { - currentMark = tdsReader.mark(); - markedChunkRemain = currentChunkRemain; - leftOverReadLimit = readLimit; - setReadLimit(readLimit); - } - } - - /** - * Closes the stream releasing all resources held. - * - * @exception IOException - * if an I/O error occurs. - */ - public void close() throws IOException { - if (null == tdsReader) - return; - - while (skip(tdsReader.getConnection().getTDSPacketSize()) != 0) - ; - // Release ref to tdsReader and parentRS here, shut down stream state. - closeHelper(); - } - - /** - * Resets stream to saved mark position. - * - * @exception IOException - * if an I/O error occurs. - */ - public void reset() throws IOException { - resetHelper(); - leftOverReadLimit = readLimit; - currentChunkRemain = markedChunkRemain; - } -} - -/** - * Implements an XML binary stream with BOM header. - * - * Class extends a normal PLPInputStream class and prepends the XML BOM (0xFFFE) token then steps out of the way and forwards the rest of the - * InputStream calls to the super class PLPInputStream. - */ -final class PLPXMLInputStream extends PLPInputStream { - // XML BOM header (the first two header bytes sent to caller). - private final static byte[] xmlBOM = {(byte) 0xFF, (byte) 0xFE}; - private final ByteArrayInputStream bomStream = new ByteArrayInputStream(xmlBOM); - - final static PLPXMLInputStream makeXMLStream(TDSReader tdsReader, - InputStreamGetterArgs getterArgs, - ServerDTVImpl dtv) throws SQLServerException { - // Read total length of PLP stream. - long payloadLength = tdsReader.readLong(); - - // If length is PLP_NULL, then return a null PLP value. - if (PLP_NULL == payloadLength) - return null; - - PLPXMLInputStream is = new PLPXMLInputStream(tdsReader, payloadLength, getterArgs, dtv); - is.setLoggingInfo(getterArgs.logContext); - - return is; - } - - PLPXMLInputStream(TDSReader tdsReader, - long statedPayloadLength, - InputStreamGetterArgs getterArgs, - ServerDTVImpl dtv) throws SQLServerException { - super(tdsReader, statedPayloadLength, getterArgs.isAdaptive, getterArgs.isStreaming, dtv); - } - - public void close() throws IOException { - super.close(); - } - - int readBytes(byte[] b, - int offset, - int maxBytes) throws IOException { - assert offset >= 0; - assert maxBytes >= 0; - // If maxBytes is zero, then no bytes are read and 0 is returned. - if (0 == maxBytes) - return 0; - - int bytesRead = 0; - int xmlBytesRead = 0; - - // Read/Skip BOM bytes first. When all BOM bytes have been consumed ... - if (null == b) { - for (int bomBytesSkipped; bytesRead < maxBytes - && 0 != (bomBytesSkipped = (int) bomStream.skip(((long) maxBytes) - ((long) bytesRead))); bytesRead += bomBytesSkipped) - ; - } - else { - for (int bomBytesRead; bytesRead < maxBytes - && -1 != (bomBytesRead = bomStream.read(b, offset + bytesRead, maxBytes - bytesRead)); bytesRead += bomBytesRead) - ; - } - - // ... then read/skip bytes from the underlying PLPInputStream - for (; bytesRead < maxBytes && -1 != (xmlBytesRead = super.readBytes(b, offset + bytesRead, maxBytes - bytesRead)); bytesRead += xmlBytesRead) - ; - - if (bytesRead > 0) - return bytesRead; - - // No bytes read - should have been EOF since 0-byte reads are handled above - assert -1 == xmlBytesRead; - return -1; - } - - public void mark(int readLimit) { - bomStream.mark(xmlBOM.length); - super.mark(readLimit); - } - - public void reset() throws IOException { - bomStream.reset(); - super.reset(); - } - - /** - * Helper function to convert the entire PLP stream into a contiguous byte array. This call is inefficient (in terms of memory usage and run time) - * for very large PLPs. Use it only if a contiguous byte array is required. - */ - byte[] getBytes() throws SQLServerException { - // Look to see if the BOM has been read - byte[] bom = new byte[2]; - try { - int bytesread = bomStream.read(bom); - byte[] valueWithoutBOM = super.getBytes(); - - if (bytesread > 0) { - assert 2 == bytesread; - byte[] valueWithBOM = new byte[valueWithoutBOM.length + bytesread]; - System.arraycopy(bom, 0, valueWithBOM, 0, bytesread); - System.arraycopy(valueWithoutBOM, 0, valueWithBOM, bytesread, valueWithoutBOM.length); - return valueWithBOM; - } - else - return valueWithoutBOM; - } - catch (IOException e) { - SQLServerException.makeFromDriverError(null, null, e.getMessage(), null, true); - } - - return null; - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +import java.io.ByteArrayInputStream; +import java.io.IOException; + + +/** + * PLPInputStream is an InputStream implementation that reads from a TDS PLP stream. + * + * Note PLP stands for Partially Length-prefixed Bytes. TDS 7.2 introduced this new streaming format for streaming of + * large types such as varchar(max), nvarchar(max), varbinary(max) and XML. + * + * See TDS specification, 6.3.3 Datatype Dependant Data Streams: Partially Length-prefixed Bytes for more details on the + * PLP format. + */ + +class PLPInputStream extends BaseInputStream { + static final long PLP_NULL = 0xFFFFFFFFFFFFFFFFL; + static final long UNKNOWN_PLP_LEN = 0xFFFFFFFFFFFFFFFEL; + static final int PLP_TERMINATOR = 0x00000000; + private final static byte[] EMPTY_PLP_BYTES = new byte[0]; + + // Stated length of the PLP stream payload; -1 if unknown length. + int payloadLength; + + private static final int PLP_EOS = -1; + private int currentChunkRemain; + + private int markedChunkRemain; + private int leftOverReadLimit = 0; + + private byte[] oneByteArray = new byte[1]; + + /** + * Non-destructive method for checking whether a PLP value at the current TDSReader location is null. + */ + final static boolean isNull(TDSReader tdsReader) throws SQLServerException { + TDSReaderMark mark = tdsReader.mark(); + // Temporary stream cannot get closes, since it closes the main stream. + try { + return null == PLPInputStream.makeTempStream(tdsReader, false, null); + } finally { + tdsReader.reset(mark); + } + } + + /** + * Create a new input stream. + * + * @param tdsReader + * TDS reader pointing at the start of the PLP data + * @param discardValue + * boolean to represent if base input stream is adaptive and is streaming + * @param dtv + * DTV implementation for values set from the TDS response stream. + * @return PLPInputStream that is created + * @throws SQLServerException + * when an error occurs + */ + final static PLPInputStream makeTempStream(TDSReader tdsReader, boolean discardValue, + ServerDTVImpl dtv) throws SQLServerException { + return makeStream(tdsReader, discardValue, discardValue, dtv); + } + + final static PLPInputStream makeStream(TDSReader tdsReader, InputStreamGetterArgs getterArgs, + ServerDTVImpl dtv) throws SQLServerException { + PLPInputStream is = makeStream(tdsReader, getterArgs.isAdaptive, getterArgs.isStreaming, dtv); + if (null != is) + is.setLoggingInfo(getterArgs.logContext); + return is; + } + + private static PLPInputStream makeStream(TDSReader tdsReader, boolean isAdaptive, boolean isStreaming, + ServerDTVImpl dtv) throws SQLServerException { + // Read total length of PLP stream. + long payloadLength = tdsReader.readLong(); + + // If length is PLP_NULL, then return a null PLP value. + if (PLP_NULL == payloadLength) + return null; + + return new PLPInputStream(tdsReader, payloadLength, isAdaptive, isStreaming, dtv); + } + + /** + * Initializes the input stream. + */ + PLPInputStream(TDSReader tdsReader, long statedPayloadLength, boolean isAdaptive, boolean isStreaming, + ServerDTVImpl dtv) throws SQLServerException { + super(tdsReader, isAdaptive, isStreaming, dtv); + this.payloadLength = (UNKNOWN_PLP_LEN != statedPayloadLength) ? ((int) statedPayloadLength) : -1; + this.currentChunkRemain = this.markedChunkRemain = 0; + } + + /** + * Helper function to convert the entire PLP stream into a contiguous byte array. This call is inefficient (in terms + * of memory usage and run time) for very large PLPs. Use it only if a contiguous byte array is required. + */ + byte[] getBytes() throws SQLServerException { + byte[] value; + + // The following 0-byte read just ensures that the number of bytes + // remaining in the current chunk is known. + readBytesInternal(null, 0, 0); + + if (PLP_EOS == currentChunkRemain) { + value = EMPTY_PLP_BYTES; + } else { + // If the PLP payload length is known, allocate the final byte array now. + // Otherwise, start with the size of the first chunk. Additional chunks + // will cause the array to be reallocated & copied. + value = new byte[(-1 != payloadLength) ? payloadLength : currentChunkRemain]; + + int bytesRead = 0; + while (PLP_EOS != currentChunkRemain) { + // If the current byte array isn't large enough to hold + // the contents of the current chunk, then make it larger. + if (value.length == bytesRead) { + byte[] newValue = new byte[bytesRead + currentChunkRemain]; + System.arraycopy(value, 0, newValue, 0, bytesRead); + value = newValue; + } + + bytesRead += readBytesInternal(value, bytesRead, currentChunkRemain); + } + } + + // Always close the stream after retrieving it + try { + close(); + } catch (IOException e) { + SQLServerException.makeFromDriverError(null, null, e.getMessage(), null, true); + } + + return value; + } + + /** + * Skips over and discards n bytes of data from this input stream. + * + * @param n + * the number of bytes to be skipped. + * @return the actual number of bytes skipped. + * @exception IOException + * if an I/O error occurs. + */ + public long skip(long n) throws IOException { + checkClosed(); + if (n < 0) + return 0L; + if (n > Integer.MAX_VALUE) + n = Integer.MAX_VALUE; + + long bytesread = readBytes(null, 0, (int) n); + + if (-1 == bytesread) + return 0; + else + return bytesread; + } + + /** + * Returns the number of bytes that can be read (or skipped over) from this input stream without blocking by the + * next caller of a method for this input stream. + * + * @return the actual number of bytes available. + * @exception IOException + * if an I/O error occurs. + */ + public int available() throws IOException { + checkClosed(); + try { + + // The following 0-byte read just ensures that the number of bytes + // remaining in the current chunk is known. + if (0 == currentChunkRemain) + readBytesInternal(null, 0, 0); + + if (PLP_EOS == currentChunkRemain) + return 0; + + // Return the lesser of the number of bytes available for reading + // from the underlying TDSReader and the number of bytes left in + // the current chunk. + int available = tdsReader.available(); + if (available > currentChunkRemain) + available = currentChunkRemain; + + return available; + } catch (SQLServerException e) { + throw new IOException(e.getMessage()); + } + + } + + /** + * Reads the next byte of data from the input stream. + * + * @return the byte read or -1 meaning no more bytes. + * @exception IOException + * if an I/O error occurs. + */ + public int read() throws IOException { + checkClosed(); + + if (-1 != readBytes(oneByteArray, 0, 1)) + return oneByteArray[0] & 0xFF; + return -1; + } + + /** + * Reads available data into supplied byte array. + * + * @param b + * array of bytes to fill. + * @return the number of bytes read or 0 meaning no bytes read. + * @exception IOException + * if an I/O error occurs. + */ + public int read(byte[] b) throws IOException { + // If b is null, a NullPointerException is thrown. + if (null == b) + throw new NullPointerException(); + + checkClosed(); + + return readBytes(b, 0, b.length); + } + + /** + * Reads available data into supplied byte array. + * + * @param b + * array of bytes to fill. + * @param offset + * the offset into array b where to start writing. + * @param maxBytes + * the max number of bytes to write into b. + * @return the number of bytes read or 0 meaning no bytes read. + * @exception IOException + * if an I/O error occurs. + */ + public int read(byte b[], int offset, int maxBytes) throws IOException { + // If b is null, a NullPointerException is thrown. + if (null == b) + throw new NullPointerException(); + + // Verify offset and maxBytes against target buffer if we're reading (as opposed to skipping). + // If offset is negative, or maxBytes is negative, or offset+maxBytes + // is greater than the length of the array b, then an IndexOutOfBoundsException is thrown. + if (offset < 0 || maxBytes < 0 || offset + maxBytes > b.length) + throw new IndexOutOfBoundsException(); + + checkClosed(); + + return readBytes(b, offset, maxBytes); + } + + /** + * Reads available data into supplied byte array b. + * + * @param b + * array of bytes to fill. If b is null, method will skip over data. + * @param offset + * the offset into array b where to start writing. + * @param maxBytes + * the max number of bytes to write into b. + * @return the number of bytes read or 0 meaning no bytes read or -1 meaning EOS. + * @exception IOException + * if an I/O error occurs. + */ + int readBytes(byte[] b, int offset, int maxBytes) throws IOException { + // If maxBytes is zero, then no bytes are read and 0 is returned + // This must be done here rather than in readBytesInternal since a 0-byte read + // there may return -1 at EOS. + if (0 == maxBytes) + return 0; + + try { + return readBytesInternal(b, offset, maxBytes); + } catch (SQLServerException e) { + throw new IOException(e.getMessage()); + } + } + + private int readBytesInternal(byte b[], int offset, int maxBytes) throws SQLServerException { + // If we're at EOS, say so. + // Note: For back compat, this special case needs to always be handled + // before checking user-supplied arguments below. + if (PLP_EOS == currentChunkRemain) + return -1; + + // Save off the current TDSReader position, wherever it is, and start reading + // from where we left off last time. + + int bytesRead = 0; + for (;;) { + // Check that we have bytes left to read from the current chunk. + // If not then figure out the size of the next chunk or + // determine that we have reached the end of the stream. + if (0 == currentChunkRemain) { + currentChunkRemain = (int) tdsReader.readUnsignedInt(); + assert currentChunkRemain >= 0; + if (0 == currentChunkRemain) { + currentChunkRemain = PLP_EOS; + break; + } + } + + if (bytesRead == maxBytes) + break; + + // Now we know there are bytes to be read in the current chunk. + // Further limit the max number of bytes we can read to whatever + // remains in the current chunk. + int bytesToRead = maxBytes - bytesRead; + if (bytesToRead > currentChunkRemain) + bytesToRead = currentChunkRemain; + + // Skip/Read as many bytes as we can, given the constraints. + if (null == b) + tdsReader.skip(bytesToRead); + else + tdsReader.readBytes(b, offset + bytesRead, bytesToRead); + + bytesRead += bytesToRead; + currentChunkRemain -= bytesToRead; + } + + if (bytesRead > 0) { + if (isReadLimitSet && leftOverReadLimit > 0) { + leftOverReadLimit = leftOverReadLimit - bytesRead; + if (leftOverReadLimit < 0) + clearCurrentMark(); + } + return bytesRead; + } + + if (PLP_EOS == currentChunkRemain) + return -1; + + return 0; + } + + /** + * Marks the current position in this input stream. + * + * @param readlimit + * the number of bytes to hold (this implementation ignores this). + */ + public void mark(int readLimit) { + // Save off current position and how much of the current chunk remains + // cant throw if the tdsreader is null + if (null != tdsReader && readLimit > 0) { + currentMark = tdsReader.mark(); + markedChunkRemain = currentChunkRemain; + leftOverReadLimit = readLimit; + setReadLimit(readLimit); + } + } + + /** + * Closes the stream releasing all resources held. + * + * @exception IOException + * if an I/O error occurs. + */ + public void close() throws IOException { + if (null == tdsReader) + return; + + while (skip(tdsReader.getConnection().getTDSPacketSize()) != 0); + // Release ref to tdsReader and parentRS here, shut down stream state. + closeHelper(); + } + + /** + * Resets stream to saved mark position. + * + * @exception IOException + * if an I/O error occurs. + */ + public void reset() throws IOException { + resetHelper(); + leftOverReadLimit = readLimit; + currentChunkRemain = markedChunkRemain; + } +} + + +/** + * Implements an XML binary stream with BOM header. + * + * Class extends a normal PLPInputStream class and prepends the XML BOM (0xFFFE) token then steps out of the way and + * forwards the rest of the InputStream calls to the super class PLPInputStream. + */ +final class PLPXMLInputStream extends PLPInputStream { + // XML BOM header (the first two header bytes sent to caller). + private final static byte[] xmlBOM = {(byte) 0xFF, (byte) 0xFE}; + private final ByteArrayInputStream bomStream = new ByteArrayInputStream(xmlBOM); + + final static PLPXMLInputStream makeXMLStream(TDSReader tdsReader, InputStreamGetterArgs getterArgs, + ServerDTVImpl dtv) throws SQLServerException { + // Read total length of PLP stream. + long payloadLength = tdsReader.readLong(); + + // If length is PLP_NULL, then return a null PLP value. + if (PLP_NULL == payloadLength) + return null; + + PLPXMLInputStream is = new PLPXMLInputStream(tdsReader, payloadLength, getterArgs, dtv); + is.setLoggingInfo(getterArgs.logContext); + + return is; + } + + PLPXMLInputStream(TDSReader tdsReader, long statedPayloadLength, InputStreamGetterArgs getterArgs, + ServerDTVImpl dtv) throws SQLServerException { + super(tdsReader, statedPayloadLength, getterArgs.isAdaptive, getterArgs.isStreaming, dtv); + } + + public void close() throws IOException { + super.close(); + } + + int readBytes(byte[] b, int offset, int maxBytes) throws IOException { + assert offset >= 0; + assert maxBytes >= 0; + // If maxBytes is zero, then no bytes are read and 0 is returned. + if (0 == maxBytes) + return 0; + + int bytesRead = 0; + int xmlBytesRead = 0; + + // Read/Skip BOM bytes first. When all BOM bytes have been consumed ... + if (null == b) { + for (int bomBytesSkipped; + bytesRead < maxBytes + && 0 != (bomBytesSkipped = (int) bomStream.skip(((long) maxBytes) - ((long) bytesRead))); + bytesRead += bomBytesSkipped); + } else { + for (int bomBytesRead; + bytesRead < maxBytes + && -1 != (bomBytesRead = bomStream.read(b, offset + bytesRead, maxBytes - bytesRead)); + bytesRead += bomBytesRead); + } + + // ... then read/skip bytes from the underlying PLPInputStream + for (; bytesRead < maxBytes + && -1 != (xmlBytesRead = super.readBytes(b, offset + bytesRead, maxBytes - bytesRead)); + bytesRead += xmlBytesRead); + + if (bytesRead > 0) + return bytesRead; + + // No bytes read - should have been EOF since 0-byte reads are handled above + assert -1 == xmlBytesRead; + return -1; + } + + public void mark(int readLimit) { + bomStream.mark(xmlBOM.length); + super.mark(readLimit); + } + + public void reset() throws IOException { + bomStream.reset(); + super.reset(); + } + + /** + * Helper function to convert the entire PLP stream into a contiguous byte array. This call is inefficient (in terms + * of memory usage and run time) for very large PLPs. Use it only if a contiguous byte array is required. + */ + byte[] getBytes() throws SQLServerException { + // Look to see if the BOM has been read + byte[] bom = new byte[2]; + try { + int bytesread = bomStream.read(bom); + byte[] valueWithoutBOM = super.getBytes(); + + if (bytesread > 0) { + assert 2 == bytesread; + byte[] valueWithBOM = new byte[valueWithoutBOM.length + bytesread]; + System.arraycopy(bom, 0, valueWithBOM, 0, bytesread); + System.arraycopy(valueWithoutBOM, 0, valueWithBOM, bytesread, valueWithoutBOM.length); + return valueWithBOM; + } else + return valueWithoutBOM; + } catch (IOException e) { + SQLServerException.makeFromDriverError(null, null, e.getMessage(), null, true); + } + + return null; + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/Parameter.java b/src/main/java/com/microsoft/sqlserver/jdbc/Parameter.java index 2a9c757d0..93758a09c 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/Parameter.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/Parameter.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -28,8 +25,9 @@ /** - * Parameter represents a JDBC parameter value that is supplied with a prepared or callable statement or an updatable result set. Parameter is JDBC - * type specific and is capable of representing any Java native type as well as a number of Java object types including binary and character streams. + * Parameter represents a JDBC parameter value that is supplied with a prepared or callable statement or an updatable + * result set. Parameter is JDBC type specific and is capable of representing any Java native type as well as a number + * of Java object types including binary and character streams. */ final class Parameter { @@ -80,8 +78,8 @@ JDBCType getJdbcType() throws SQLServerException { } /** - * Used when sendStringParametersAsUnicode=true to derive the appropriate National Character Set JDBC type corresponding to the specified JDBC - * type. + * Used when sendStringParametersAsUnicode=true to derive the appropriate National Character Set JDBC type + * corresponding to the specified JDBC type. */ private static JDBCType getSSPAUJDBCType(JDBCType jdbcType) { switch (jdbcType) { @@ -101,12 +99,11 @@ private static JDBCType getSSPAUJDBCType(JDBCType jdbcType) { // For parameters whose underlying type is not represented by a JDBC type // the transport type reflects how the value is sent to the // server (e.g. JDBCType.CHAR for GUID parameters). - void registerForOutput(JDBCType jdbcType, - SQLServerConnection con) throws SQLServerException { + void registerForOutput(JDBCType jdbcType, SQLServerConnection con) throws SQLServerException { // DateTimeOffset is not supported with SQL Server versions earlier than Katmai if (JDBCType.DATETIMEOFFSET == jdbcType && !con.isKatmaiOrLater()) { - throw new SQLServerException(SQLServerException.getErrString("R_notSupported"), SQLState.DATA_EXCEPTION_NOT_SPECIFIC, DriverError.NOT_SET, - null); + throw new SQLServerException(SQLServerException.getErrString("R_notSupported"), + SQLState.DATA_EXCEPTION_NOT_SPECIFIC, DriverError.NOT_SET, null); } // sendStringParametersAsUnicode @@ -152,22 +149,18 @@ void setOutScale(int outScale) { private String schemaName; /* - * The different DTVs representing the parameter's value: - * - * getterDTV - The OUT value, if set, of the parameter after execution. This is the value retrieved by CallableStatement getter methods. - * - * registeredOutDTV - The "IN" value corresponding to a SQL NULL with a JDBC type that was passed to the CallableStatement.registerOutParameter - * method. Since SQL Server does not directly support OUT-only parameters (just IN and IN/OUT), the driver sends a null IN value for an OUT - * parameter, unless the application set an input value (setterDTV) as well. - * - * setterDTV - The IN value, if set, of the parameter. This is the value set by PreparedStatement and CallableStatement setter methods. - * - * inputDTV - If set, refers to either setterDTV or registeredOutDTV depending on whether the parameter is IN, IN/OUT, or OUT-only. If cleared - * (i.e. set to null), it means that no value is set for the parameter and that execution of the PreparedStatement or CallableStatement should - * throw a "parameter not set" exception. - * - * Note that if the parameter value is a stream, the driver consumes its contents it at execution and clears inputDTV and setterDTV so that the - * application must reset the parameter prior to the next execution to avoid getting a "parameter not set" exception. + * The different DTVs representing the parameter's value: getterDTV - The OUT value, if set, of the parameter after + * execution. This is the value retrieved by CallableStatement getter methods. registeredOutDTV - The "IN" value + * corresponding to a SQL NULL with a JDBC type that was passed to the CallableStatement.registerOutParameter + * method. Since SQL Server does not directly support OUT-only parameters (just IN and IN/OUT), the driver sends a + * null IN value for an OUT parameter, unless the application set an input value (setterDTV) as well. setterDTV - + * The IN value, if set, of the parameter. This is the value set by PreparedStatement and CallableStatement setter + * methods. inputDTV - If set, refers to either setterDTV or registeredOutDTV depending on whether the parameter is + * IN, IN/OUT, or OUT-only. If cleared (i.e. set to null), it means that no value is set for the parameter and that + * execution of the PreparedStatement or CallableStatement should throw a "parameter not set" exception. Note that + * if the parameter value is a stream, the driver consumes its contents it at execution and clears inputDTV and + * setterDTV so that the application must reset the parameter prior to the next execution to avoid getting a + * "parameter not set" exception. */ private DTV getterDTV; private DTV registeredOutDTV = null; @@ -177,10 +170,11 @@ void setOutScale(int outScale) { /** * Clones this Parameter object for use in a batch. * - * The clone method creates a shallow clone of the Parameter object. That is, the cloned instance references all of the same internal objects and - * state as the original. + * The clone method creates a shallow clone of the Parameter object. That is, the cloned instance references all of + * the same internal objects and state as the original. * - * Note: this method is purposely NOT the Object.clone() method, as that method has specific requirements and semantics that we don't need here. + * Note: this method is purposely NOT the Object.clone() method, as that method has specific requirements and + * semantics that we don't need here. */ final Parameter cloneForBatch() { Parameter clonedParam = new Parameter(shouldHonorAEForParameter); @@ -203,8 +197,7 @@ final Parameter cloneForBatch() { /** * Skip value. */ - final void skipValue(TDSReader tdsReader, - boolean isDiscard) throws SQLServerException { + final void skipValue(TDSReader tdsReader, boolean isDiscard) throws SQLServerException { if (null == getterDTV) getterDTV = new DTV(); @@ -249,26 +242,17 @@ void deriveTypeInfo(TDSReader tdsReader) throws SQLServerException { } } - void setFromReturnStatus(int returnStatus, - SQLServerConnection con) throws SQLServerException { + void setFromReturnStatus(int returnStatus, SQLServerConnection con) throws SQLServerException { if (null == getterDTV) getterDTV = new DTV(); - getterDTV.setValue(null, JDBCType.INTEGER, returnStatus, JavaType.INTEGER, null, null, null, con, getForceEncryption()); + getterDTV.setValue(null, JDBCType.INTEGER, returnStatus, JavaType.INTEGER, null, null, null, con, + getForceEncryption()); } - void setValue(JDBCType jdbcType, - Object value, - JavaType javaType, - StreamSetterArgs streamSetterArgs, - Calendar calendar, - Integer precision, - Integer scale, - SQLServerConnection con, - boolean forceEncrypt, - SQLServerStatementColumnEncryptionSetting stmtColumnEncriptionSetting, - int parameterIndex, - String userSQL, + void setValue(JDBCType jdbcType, Object value, JavaType javaType, StreamSetterArgs streamSetterArgs, + Calendar calendar, Integer precision, Integer scale, SQLServerConnection con, boolean forceEncrypt, + SQLServerStatementColumnEncryptionSetting stmtColumnEncriptionSetting, int parameterIndex, String userSQL, String tvpName) throws SQLServerException { if (shouldHonorAEForParameter) { @@ -288,7 +272,8 @@ void setValue(JDBCType jdbcType, // Also, for setters, we are able to send tinyint to smallint // However, for output parameter, it might cause error. if (!isOutput()) { - if ((JavaType.SHORT == javaType) && ((JDBCType.TINYINT == jdbcType) || (JDBCType.SMALLINT == jdbcType))) { + if ((JavaType.SHORT == javaType) + && ((JDBCType.TINYINT == jdbcType) || (JDBCType.SMALLINT == jdbcType))) { // value falls in the TINYINT range if (((Short) value) >= 0 && ((Short) value) <= 255) { value = ((Short) value).byteValue(); @@ -299,8 +284,10 @@ void setValue(JDBCType jdbcType, else { // This is for cases like setObject(1, Short.valueOf("-1"), java.sql.Types.TINYINT); if (JDBCType.TINYINT == jdbcType) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidDataForAE")); - Object[] msgArgs = {javaType.toString().toLowerCase(Locale.ENGLISH), jdbcType.toString().toLowerCase(Locale.ENGLISH)}; + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_InvalidDataForAE")); + Object[] msgArgs = {javaType.toString().toLowerCase(Locale.ENGLISH), + jdbcType.toString().toLowerCase(Locale.ENGLISH)}; throw new SQLServerException(form.format(msgArgs), null); } } @@ -311,7 +298,8 @@ void setValue(JDBCType jdbcType, // forceEncryption is true, shouldhonorae is false if ((true == forceEncrypt) && (false == Util.shouldHonorAEForParameters(stmtColumnEncriptionSetting, con))) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_ForceEncryptionTrue_HonorAEFalse")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_ForceEncryptionTrue_HonorAEFalse")); Object[] msgArgs = {parameterIndex, userSQL}; SQLServerException.makeFromDriverError(con, this, form.format(msgArgs), null, true); @@ -319,25 +307,21 @@ void setValue(JDBCType jdbcType, // DateTimeOffset is not supported with SQL Server versions earlier than Katmai if ((JDBCType.DATETIMEOFFSET == jdbcType || JavaType.DATETIMEOFFSET == javaType) && !con.isKatmaiOrLater()) { - throw new SQLServerException(SQLServerException.getErrString("R_notSupported"), SQLState.DATA_EXCEPTION_NOT_SPECIFIC, DriverError.NOT_SET, - null); + throw new SQLServerException(SQLServerException.getErrString("R_notSupported"), + SQLState.DATA_EXCEPTION_NOT_SPECIFIC, DriverError.NOT_SET, null); } if (JavaType.TVP == javaType) { TVP tvpValue; if (null == value) { tvpValue = new TVP(tvpName); - } - else if (value instanceof SQLServerDataTable) { + } else if (value instanceof SQLServerDataTable) { tvpValue = new TVP(tvpName, (SQLServerDataTable) value); - } - else if (value instanceof ResultSet) { + } else if (value instanceof ResultSet) { tvpValue = new TVP(tvpName, (ResultSet) value); - } - else if (value instanceof ISQLServerDataRecord) { + } else if (value instanceof ISQLServerDataRecord) { tvpValue = new TVP(tvpName, (ISQLServerDataRecord) value); - } - else { + } else { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_TVPInvalidValue")); Object[] msgArgs = {parameterIndex}; throw new SQLServerException(form.format(msgArgs), null); @@ -376,13 +360,14 @@ else if (value instanceof ISQLServerDataRecord) { // to the server as Unicode rather than MBCS. This is accomplished here by re-tagging // the value with the appropriate corresponding Unicode type. // JavaType.OBJECT == javaType when calling setNull() - if (con.sendStringParametersAsUnicode() - && (JavaType.STRING == javaType || JavaType.READER == javaType || JavaType.CLOB == javaType || JavaType.OBJECT == javaType)) { + if (con.sendStringParametersAsUnicode() && (JavaType.STRING == javaType || JavaType.READER == javaType + || JavaType.CLOB == javaType || JavaType.OBJECT == javaType)) { jdbcType = getSSPAUJDBCType(jdbcType); } DTV newDTV = new DTV(); - newDTV.setValue(con.getDatabaseCollation(), jdbcType, value, javaType, streamSetterArgs, calendar, scale, con, forceEncrypt); + newDTV.setValue(con.getDatabaseCollation(), jdbcType, value, javaType, streamSetterArgs, calendar, scale, con, + forceEncrypt); if (!con.sendStringParametersAsUnicode()) { newDTV.sendStringParametersAsUnicode = false; @@ -403,9 +388,7 @@ boolean isValueGotten() { } - Object getValue(JDBCType jdbcType, - InputStreamGetterArgs getterArgs, - Calendar cal, + Object getValue(JDBCType jdbcType, InputStreamGetterArgs getterArgs, Calendar cal, TDSReader tdsReader) throws SQLServerException { if (null == getterDTV) getterDTV = new DTV(); @@ -415,7 +398,7 @@ Object getValue(JDBCType jdbcType, // statement level), cryptoMeta would be null. return getterDTV.getValue(jdbcType, outScale, getterArgs, cal, typeInfo, cryptoMeta, tdsReader); } - + Object getSetterValue() { return setterDTV.getSetterValue(); } @@ -444,8 +427,7 @@ final class GetTypeDefinitionOp extends DTVExecuteOp { private final Parameter param; private final SQLServerConnection con; - GetTypeDefinitionOp(Parameter param, - SQLServerConnection con) { + GetTypeDefinitionOp(Parameter param, SQLServerConnection con) { this.param = param; this.con = con; } @@ -473,18 +455,18 @@ private void setTypeDefinition(DTV dtv) { if (param.shouldHonorAEForParameter && (null != jdbcTypeSetByUser) && !(null == param.getCryptoMetadata() && param.renewDefinition)) { /* - * This means AE is ON in the connection, and (1) this is either the first round to SQL Server to get encryption meta data, or - * (2) this is the second round of renewing meta data and parameter is encrypted In both of these cases we need to send - * specific type info, otherwise generic type info can be used as before. + * This means AE is ON in the connection, and (1) this is either the first round to SQL Server + * to get encryption meta data, or (2) this is the second round of renewing meta data and + * parameter is encrypted In both of these cases we need to send specific type info, otherwise + * generic type info can be used as before. */ param.typeDefinition = SSType.REAL.toString(); - } - else { + } else { // use FLOAT if column is not encrypted param.typeDefinition = SSType.FLOAT.toString(); } break; - + case FLOAT: case DOUBLE: param.typeDefinition = SSType.FLOAT.toString(); @@ -510,42 +492,46 @@ private void setTypeDefinition(DTV dtv) { if (param.shouldHonorAEForParameter && (null != jdbcTypeSetByUser) && !(null == param.getCryptoMetadata() && param.renewDefinition)) { /* - * This means AE is ON in the connection, and (1) this is either the first round to SQL Server to get encryption meta data, or - * (2) this is the second round of renewing meta data and parameter is encrypted In both of these cases we need to send - * specific type info, otherwise generic type info can be used as before. + * This means AE is ON in the connection, and (1) this is either the first round to SQL Server + * to get encryption meta data, or (2) this is the second round of renewing meta data and + * parameter is encrypted In both of these cases we need to send specific type info, otherwise + * generic type info can be used as before. */ if (0 == valueLength) { - // for prepared statement and callable statement, There are only two cases where valueLength is 0: + // for prepared statement and callable statement, There are only two cases where valueLength + // is 0: // 1. when the parameter is output parameter // 2. for input parameter, the value is null // so, here, if the decimal parameter is encrypted and it is null and it is not outparameter // then we set precision as the default precision instead of max precision if (!isOutput()) { - param.typeDefinition = "decimal(" + SQLServerConnection.defaultDecimalPrecision + ", " + scale + ")"; + param.typeDefinition = "decimal(" + SQLServerConnection.defaultDecimalPrecision + ", " + + scale + ")"; } - } - else { + } else { if (SQLServerConnection.defaultDecimalPrecision >= valueLength) { - param.typeDefinition = "decimal(" + SQLServerConnection.defaultDecimalPrecision + "," + scale + ")"; + param.typeDefinition = "decimal(" + SQLServerConnection.defaultDecimalPrecision + "," + + scale + ")"; if (SQLServerConnection.defaultDecimalPrecision < (valueLength + scale)) { - param.typeDefinition = "decimal(" + (SQLServerConnection.defaultDecimalPrecision + scale) + "," + scale + ")"; + param.typeDefinition = "decimal(" + + (SQLServerConnection.defaultDecimalPrecision + scale) + "," + scale + ")"; } - } - else { - param.typeDefinition = "decimal(" + SQLServerConnection.maxDecimalPrecision + "," + scale + ")"; + } else { + param.typeDefinition = "decimal(" + SQLServerConnection.maxDecimalPrecision + "," + + scale + ")"; } } if (isOutput()) { - param.typeDefinition = "decimal(" + SQLServerConnection.maxDecimalPrecision + ", " + scale + ")"; + param.typeDefinition = "decimal(" + SQLServerConnection.maxDecimalPrecision + ", " + scale + + ")"; } if (userProvidesPrecision) { param.typeDefinition = "decimal(" + valueLength + "," + scale + ")"; } - } - else + } else param.typeDefinition = "decimal(" + SQLServerConnection.maxDecimalPrecision + "," + scale + ")"; break; @@ -556,7 +542,8 @@ private void setTypeDefinition(DTV dtv) { case SMALLMONEY: param.typeDefinition = SSType.MONEY.toString(); - if (param.shouldHonorAEForParameter && !(null == param.getCryptoMetadata() && param.renewDefinition)) { + if (param.shouldHonorAEForParameter + && !(null == param.getCryptoMetadata() && param.renewDefinition)) { param.typeDefinition = SSType.SMALLMONEY.toString(); } @@ -579,24 +566,23 @@ private void setTypeDefinition(DTV dtv) { if (param.shouldHonorAEForParameter && (null != jdbcTypeSetByUser) && !(null == param.getCryptoMetadata() && param.renewDefinition)) { /* - * This means AE is ON in the connection, and (1) this is either the first round to SQL Server to get encryption meta data, or - * (2) this is the second round of renewing meta data and parameter is encrypted In both of these cases we need to send - * specific type info, otherwise generic type info can be used as before. + * This means AE is ON in the connection, and (1) this is either the first round to SQL Server + * to get encryption meta data, or (2) this is the second round of renewing meta data and + * parameter is encrypted In both of these cases we need to send specific type info, otherwise + * generic type info can be used as before. */ if (0 == valueLength) { // Workaround for the issue when inserting empty string and null into encrypted columns param.typeDefinition = "varbinary(1)"; valueLength++; - } - else { + } else { param.typeDefinition = "varbinary(" + valueLength + ")"; } if (JDBCType.LONGVARBINARY == jdbcTypeSetByUser) { param.typeDefinition = VARBINARY_MAX; } - } - else + } else param.typeDefinition = VARBINARY_8K; break; @@ -606,46 +592,52 @@ private void setTypeDefinition(DTV dtv) { break; case TIME: - if (param.shouldHonorAEForParameter && !(null == param.getCryptoMetadata() && param.renewDefinition)) { + if (param.shouldHonorAEForParameter + && !(null == param.getCryptoMetadata() && param.renewDefinition)) { /* - * This means AE is ON in the connection, and (1) this is either the first round to SQL Server to get encryption meta data, or - * (2) this is the second round of renewing meta data and parameter is encrypted In both of these cases we need to send - * specific type info, otherwise generic type info can be used as before. + * This means AE is ON in the connection, and (1) this is either the first round to SQL Server + * to get encryption meta data, or (2) this is the second round of renewing meta data and + * parameter is encrypted In both of these cases we need to send specific type info, otherwise + * generic type info can be used as before. */ if (userProvidesScale) { param.typeDefinition = (SSType.TIME.toString() + "(" + outScale + ")"); + } else { + param.typeDefinition = param.typeDefinition = SSType.TIME.toString() + "(" + valueLength + + ")"; } - else { - param.typeDefinition = param.typeDefinition = SSType.TIME.toString() + "(" + valueLength + ")"; - } - } - else { - param.typeDefinition = con.getSendTimeAsDatetime() ? SSType.DATETIME.toString() : SSType.TIME.toString(); + } else { + param.typeDefinition = con.getSendTimeAsDatetime() ? SSType.DATETIME.toString() + : SSType.TIME.toString(); } break; case TIMESTAMP: // Bind TIMESTAMP values to pre-Katmai servers as DATETIME. Bind TIMESTAMP values to // Katmai and later servers as DATETIME2 to take advantage of increased precision. - if (param.shouldHonorAEForParameter && !(null == param.getCryptoMetadata() && param.renewDefinition)) { + if (param.shouldHonorAEForParameter + && !(null == param.getCryptoMetadata() && param.renewDefinition)) { /* - * This means AE is ON in the connection, and (1) this is either the first round to SQL Server to get encryption meta data, or - * (2) this is the second round of renewing meta data and parameter is encrypted In both of these cases we need to send - * specific type info, otherwise generic type info can be used as before. + * This means AE is ON in the connection, and (1) this is either the first round to SQL Server + * to get encryption meta data, or (2) this is the second round of renewing meta data and + * parameter is encrypted In both of these cases we need to send specific type info, otherwise + * generic type info can be used as before. */ if (userProvidesScale) { - param.typeDefinition = con.isKatmaiOrLater() ? (SSType.DATETIME2.toString() + "(" + outScale + ")") - : (SSType.DATETIME.toString()); + param.typeDefinition = con + .isKatmaiOrLater() ? (SSType.DATETIME2.toString() + "(" + outScale + ")") + : (SSType.DATETIME.toString()); + } else { + param.typeDefinition = con.isKatmaiOrLater() + ? (SSType.DATETIME2.toString() + "(" + + valueLength + ")") + : SSType.DATETIME.toString(); } - else { - param.typeDefinition = con.isKatmaiOrLater() ? (SSType.DATETIME2.toString() + "(" + valueLength + ")") - : SSType.DATETIME.toString(); - } - } - else { - param.typeDefinition = con.isKatmaiOrLater() ? SSType.DATETIME2.toString() : SSType.DATETIME.toString(); + } else { + param.typeDefinition = con.isKatmaiOrLater() ? SSType.DATETIME2.toString() + : SSType.DATETIME.toString(); } break; @@ -653,7 +645,8 @@ private void setTypeDefinition(DTV dtv) { // send as Datetime by default param.typeDefinition = SSType.DATETIME2.toString(); - if (param.shouldHonorAEForParameter && !(null == param.getCryptoMetadata() && param.renewDefinition)) { + if (param.shouldHonorAEForParameter + && !(null == param.getCryptoMetadata() && param.renewDefinition)) { param.typeDefinition = SSType.DATETIME.toString(); } @@ -663,8 +656,7 @@ private void setTypeDefinition(DTV dtv) { if (param.isOutput()) { param.typeDefinition = SSType.DATETIME2.toString() + "(" + outScale + ")"; } - } - else { + } else { // when AE is on, set it to Datetime by default, // However, if column is not encrypted and it is output parameter of stored procedure, // renew it to datetime2(3) @@ -680,7 +672,8 @@ private void setTypeDefinition(DTV dtv) { case SMALLDATETIME: param.typeDefinition = SSType.DATETIME2.toString(); - if (param.shouldHonorAEForParameter && !(null == param.getCryptoMetadata() && param.renewDefinition)) { + if (param.shouldHonorAEForParameter + && !(null == param.getCryptoMetadata() && param.renewDefinition)) { param.typeDefinition = SSType.SMALLDATETIME.toString(); } @@ -689,20 +682,20 @@ private void setTypeDefinition(DTV dtv) { case TIME_WITH_TIMEZONE: case TIMESTAMP_WITH_TIMEZONE: case DATETIMEOFFSET: - if (param.shouldHonorAEForParameter && !(null == param.getCryptoMetadata() && param.renewDefinition)) { + if (param.shouldHonorAEForParameter + && !(null == param.getCryptoMetadata() && param.renewDefinition)) { /* - * This means AE is ON in the connection, and (1) this is either the first round to SQL Server to get encryption meta data, or - * (2) this is the second round of renewing meta data and parameter is encrypted In both of these cases we need to send - * specific type info, otherwise generic type info can be used as before. + * This means AE is ON in the connection, and (1) this is either the first round to SQL Server + * to get encryption meta data, or (2) this is the second round of renewing meta data and + * parameter is encrypted In both of these cases we need to send specific type info, otherwise + * generic type info can be used as before. */ if (userProvidesScale) { param.typeDefinition = SSType.DATETIMEOFFSET.toString() + "(" + outScale + ")"; - } - else { + } else { param.typeDefinition = SSType.DATETIMEOFFSET.toString() + "(" + valueLength + ")"; } - } - else { + } else { param.typeDefinition = SSType.DATETIMEOFFSET.toString(); } break; @@ -722,77 +715,72 @@ private void setTypeDefinition(DTV dtv) { if (param.shouldHonorAEForParameter && (null != jdbcTypeSetByUser) && !(null == param.getCryptoMetadata() && param.renewDefinition)) { /* - * This means AE is ON in the connection, and (1) this is either the first round to SQL Server to get encryption meta data, or - * (2) this is the second round of renewing meta data and parameter is encrypted In both of these cases we need to send - * specific type info, otherwise generic type info can be used as before. + * This means AE is ON in the connection, and (1) this is either the first round to SQL Server + * to get encryption meta data, or (2) this is the second round of renewing meta data and + * parameter is encrypted In both of these cases we need to send specific type info, otherwise + * generic type info can be used as before. */ if (0 == valueLength) { // Workaround for the issue when inserting empty string and null into encrypted columns param.typeDefinition = "varchar(1)"; valueLength++; - } - else { + } else { param.typeDefinition = "varchar(" + valueLength + ")"; if (DataTypes.SHORT_VARTYPE_MAX_BYTES <= valueLength) { param.typeDefinition = VARCHAR_MAX; } } - } - else + } else param.typeDefinition = VARCHAR_8K; break; case LONGNVARCHAR: - if (param.shouldHonorAEForParameter && !(null == param.getCryptoMetadata() && param.renewDefinition)) { + if (param.shouldHonorAEForParameter + && !(null == param.getCryptoMetadata() && param.renewDefinition)) { /* - * This means AE is ON in the connection, and (1) this is either the first round to SQL Server to get encryption meta data, or - * (2) this is the second round of renewing meta data and parameter is encrypted In both of these cases we need to send - * specific type info, otherwise generic type info can be used as before. + * This means AE is ON in the connection, and (1) this is either the first round to SQL Server + * to get encryption meta data, or (2) this is the second round of renewing meta data and + * parameter is encrypted In both of these cases we need to send specific type info, otherwise + * generic type info can be used as before. */ - if ((null != jdbcTypeSetByUser) && ((jdbcTypeSetByUser == JDBCType.VARCHAR) || (jdbcTypeSetByUser == JDBCType.CHAR) - || (jdbcTypeSetByUser == JDBCType.LONGVARCHAR))) { + if ((null != jdbcTypeSetByUser) + && ((jdbcTypeSetByUser == JDBCType.VARCHAR) || (jdbcTypeSetByUser == JDBCType.CHAR) + || (jdbcTypeSetByUser == JDBCType.LONGVARCHAR))) { if (0 == valueLength) { // Workaround for the issue when inserting empty string and null into encrypted columns param.typeDefinition = "varchar(1)"; valueLength++; - } - else if (DataTypes.SHORT_VARTYPE_MAX_BYTES < valueLength) { + } else if (DataTypes.SHORT_VARTYPE_MAX_BYTES < valueLength) { param.typeDefinition = VARCHAR_MAX; - } - else { + } else { param.typeDefinition = "varchar(" + valueLength + ")"; } if (jdbcTypeSetByUser == JDBCType.LONGVARCHAR) { param.typeDefinition = VARCHAR_MAX; } - } - else if ((null != jdbcTypeSetByUser) - && (jdbcTypeSetByUser == JDBCType.NVARCHAR || jdbcTypeSetByUser == JDBCType.LONGNVARCHAR)) { + } else if ((null != jdbcTypeSetByUser) && (jdbcTypeSetByUser == JDBCType.NVARCHAR + || jdbcTypeSetByUser == JDBCType.LONGNVARCHAR)) { if (0 == valueLength) { // Workaround for the issue when inserting empty string and null into encrypted columns param.typeDefinition = "nvarchar(1)"; valueLength++; - } - else if (DataTypes.SHORT_VARTYPE_MAX_CHARS < valueLength) { + } else if (DataTypes.SHORT_VARTYPE_MAX_CHARS < valueLength) { param.typeDefinition = NVARCHAR_MAX; - } - else { + } else { param.typeDefinition = "nvarchar(" + valueLength + ")"; } if (jdbcTypeSetByUser == JDBCType.LONGNVARCHAR) { param.typeDefinition = NVARCHAR_MAX; } - } - else { // used if setNull() is called with java.sql.Types.NCHAR + } else { // used if setNull() is called with java.sql.Types.NCHAR if (0 == valueLength) { // Workaround for the issue when inserting empty string and null into encrypted columns param.typeDefinition = "nvarchar(1)"; valueLength++; - } - else { + } else { param.typeDefinition = "nvarchar(" + valueLength + ")"; if (DataTypes.SHORT_VARTYPE_MAX_BYTES <= valueLength) { @@ -801,8 +789,7 @@ else if (DataTypes.SHORT_VARTYPE_MAX_CHARS < valueLength) { } } break; - } - else + } else param.typeDefinition = NVARCHAR_MAX; break; @@ -818,20 +805,22 @@ else if (DataTypes.SHORT_VARTYPE_MAX_CHARS < valueLength) { if (NVARCHAR_MAX.equals(param.typeDefinition) || NTEXT.equals(param.typeDefinition)) break; - if (param.shouldHonorAEForParameter && !(null == param.getCryptoMetadata() && param.renewDefinition)) { + if (param.shouldHonorAEForParameter + && !(null == param.getCryptoMetadata() && param.renewDefinition)) { /* - * This means AE is ON in the connection, and (1) this is either the first round to SQL Server to get encryption meta data, or - * (2) this is the second round of renewing meta data and parameter is encrypted In both of these cases we need to send - * specific type info, otherwise generic type info can be used as before. + * This means AE is ON in the connection, and (1) this is either the first round to SQL Server + * to get encryption meta data, or (2) this is the second round of renewing meta data and + * parameter is encrypted In both of these cases we need to send specific type info, otherwise + * generic type info can be used as before. */ - if ((null != jdbcTypeSetByUser) && ((jdbcTypeSetByUser == JDBCType.VARCHAR) || (jdbcTypeSetByUser == JDBCType.CHAR) - || (JDBCType.LONGVARCHAR == jdbcTypeSetByUser))) { + if ((null != jdbcTypeSetByUser) + && ((jdbcTypeSetByUser == JDBCType.VARCHAR) || (jdbcTypeSetByUser == JDBCType.CHAR) + || (JDBCType.LONGVARCHAR == jdbcTypeSetByUser))) { if (0 == valueLength) { // Workaround for the issue when inserting empty string and null into encrypted columns param.typeDefinition = "varchar(1)"; valueLength++; - } - else { + } else { param.typeDefinition = "varchar(" + valueLength + ")"; if (DataTypes.SHORT_VARTYPE_MAX_BYTES < valueLength) { @@ -842,15 +831,14 @@ else if (DataTypes.SHORT_VARTYPE_MAX_CHARS < valueLength) { if (JDBCType.LONGVARCHAR == jdbcTypeSetByUser) { param.typeDefinition = VARCHAR_MAX; } - } - else if ((null != jdbcTypeSetByUser) && ((jdbcTypeSetByUser == JDBCType.NVARCHAR) || (jdbcTypeSetByUser == JDBCType.NCHAR) - || (JDBCType.LONGNVARCHAR == jdbcTypeSetByUser))) { + } else if ((null != jdbcTypeSetByUser) + && ((jdbcTypeSetByUser == JDBCType.NVARCHAR) || (jdbcTypeSetByUser == JDBCType.NCHAR) + || (JDBCType.LONGNVARCHAR == jdbcTypeSetByUser))) { if (0 == valueLength) { // Workaround for the issue when inserting empty string and null into encrypted columns param.typeDefinition = "nvarchar(1)"; valueLength++; - } - else { + } else { param.typeDefinition = "nvarchar(" + valueLength + ")"; if (DataTypes.SHORT_VARTYPE_MAX_BYTES <= valueLength) { @@ -861,14 +849,12 @@ else if ((null != jdbcTypeSetByUser) && ((jdbcTypeSetByUser == JDBCType.NVARCHAR if (JDBCType.LONGNVARCHAR == jdbcTypeSetByUser) { param.typeDefinition = NVARCHAR_MAX; } - } - else { // used if setNull() is called with java.sql.Types.NCHAR + } else { // used if setNull() is called with java.sql.Types.NCHAR if (0 == valueLength) { // Workaround for the issue when inserting empty string and null into encrypted columns param.typeDefinition = "nvarchar(1)"; valueLength++; - } - else { + } else { param.typeDefinition = "nvarchar(" + valueLength + ")"; if (DataTypes.SHORT_VARTYPE_MAX_BYTES <= valueLength) { @@ -877,8 +863,7 @@ else if ((null != jdbcTypeSetByUser) && ((jdbcTypeSetByUser == JDBCType.NVARCHAR } } break; - } - else + } else param.typeDefinition = NVARCHAR_4K; break; case SQLXML: @@ -891,8 +876,7 @@ else if ((null != jdbcTypeSetByUser) && ((jdbcTypeSetByUser == JDBCType.NVARCHAR if (null != schema) { param.typeDefinition = "[" + schema + "].[" + param.name + "] READONLY"; - } - else { + } else { param.typeDefinition = "[" + param.name + "] READONLY"; } @@ -901,15 +885,15 @@ else if ((null != jdbcTypeSetByUser) && ((jdbcTypeSetByUser == JDBCType.NVARCHAR case GUID: param.typeDefinition = SSType.GUID.toString(); break; - + case SQL_VARIANT: param.typeDefinition = SSType.SQL_VARIANT.toString(); break; - + case GEOMETRY: param.typeDefinition = SSType.GEOMETRY.toString(); break; - + case GEOGRAPHY: param.typeDefinition = SSType.GEOGRAPHY.toString(); break; @@ -919,98 +903,80 @@ else if ((null != jdbcTypeSetByUser) && ((jdbcTypeSetByUser == JDBCType.NVARCHAR } } - void execute(DTV dtv, - String strValue) throws SQLServerException { + void execute(DTV dtv, String strValue) throws SQLServerException { if (null != strValue && strValue.length() > DataTypes.SHORT_VARTYPE_MAX_CHARS) dtv.setJdbcType(JDBCType.LONGNVARCHAR); setTypeDefinition(dtv); } - void execute(DTV dtv, - Clob clobValue) throws SQLServerException { + void execute(DTV dtv, Clob clobValue) throws SQLServerException { setTypeDefinition(dtv); } - void execute(DTV dtv, - Byte byteValue) throws SQLServerException { + void execute(DTV dtv, Byte byteValue) throws SQLServerException { setTypeDefinition(dtv); } - void execute(DTV dtv, - Integer intValue) throws SQLServerException { + void execute(DTV dtv, Integer intValue) throws SQLServerException { setTypeDefinition(dtv); } - void execute(DTV dtv, - java.sql.Time timeValue) throws SQLServerException { + void execute(DTV dtv, java.sql.Time timeValue) throws SQLServerException { setTypeDefinition(dtv); } - void execute(DTV dtv, - java.sql.Date dateValue) throws SQLServerException { + void execute(DTV dtv, java.sql.Date dateValue) throws SQLServerException { setTypeDefinition(dtv); } - void execute(DTV dtv, - java.sql.Timestamp timestampValue) throws SQLServerException { + void execute(DTV dtv, java.sql.Timestamp timestampValue) throws SQLServerException { setTypeDefinition(dtv); } - void execute(DTV dtv, - java.util.Date utildateValue) throws SQLServerException { + void execute(DTV dtv, java.util.Date utildateValue) throws SQLServerException { setTypeDefinition(dtv); } - void execute(DTV dtv, - java.util.Calendar calendarValue) throws SQLServerException { + void execute(DTV dtv, java.util.Calendar calendarValue) throws SQLServerException { setTypeDefinition(dtv); } - void execute(DTV dtv, - LocalDate localDateValue) throws SQLServerException { + void execute(DTV dtv, LocalDate localDateValue) throws SQLServerException { setTypeDefinition(dtv); } - void execute(DTV dtv, - LocalTime localTimeValue) throws SQLServerException { + void execute(DTV dtv, LocalTime localTimeValue) throws SQLServerException { setTypeDefinition(dtv); } - void execute(DTV dtv, - LocalDateTime localDateTimeValue) throws SQLServerException { + void execute(DTV dtv, LocalDateTime localDateTimeValue) throws SQLServerException { setTypeDefinition(dtv); } - void execute(DTV dtv, - OffsetTime offsetTimeValue) throws SQLServerException { + void execute(DTV dtv, OffsetTime offsetTimeValue) throws SQLServerException { setTypeDefinition(dtv); } - void execute(DTV dtv, - OffsetDateTime OffsetDateTimeValue) throws SQLServerException { + void execute(DTV dtv, OffsetDateTime OffsetDateTimeValue) throws SQLServerException { setTypeDefinition(dtv); } - void execute(DTV dtv, - microsoft.sql.DateTimeOffset dtoValue) throws SQLServerException { + void execute(DTV dtv, microsoft.sql.DateTimeOffset dtoValue) throws SQLServerException { setTypeDefinition(dtv); } - void execute(DTV dtv, - Float floatValue) throws SQLServerException { + void execute(DTV dtv, Float floatValue) throws SQLServerException { scale = 4; setTypeDefinition(dtv); } - void execute(DTV dtv, - Double doubleValue) throws SQLServerException { + void execute(DTV dtv, Double doubleValue) throws SQLServerException { scale = 4; setTypeDefinition(dtv); } - void execute(DTV dtv, - BigDecimal bigDecimalValue) throws SQLServerException { + void execute(DTV dtv, BigDecimal bigDecimalValue) throws SQLServerException { if (null != bigDecimalValue) { scale = bigDecimalValue.scale(); @@ -1026,47 +992,41 @@ void execute(DTV dtv, setTypeDefinition(dtv); } - void execute(DTV dtv, - Long longValue) throws SQLServerException { + void execute(DTV dtv, Long longValue) throws SQLServerException { setTypeDefinition(dtv); } - void execute(DTV dtv, - java.math.BigInteger bigIntegerValue) throws SQLServerException { + void execute(DTV dtv, java.math.BigInteger bigIntegerValue) throws SQLServerException { setTypeDefinition(dtv); } - void execute(DTV dtv, - Short shortValue) throws SQLServerException { + void execute(DTV dtv, Short shortValue) throws SQLServerException { setTypeDefinition(dtv); } - void execute(DTV dtv, - Boolean booleanValue) throws SQLServerException { + void execute(DTV dtv, Boolean booleanValue) throws SQLServerException { setTypeDefinition(dtv); } - void execute(DTV dtv, - byte[] byteArrayValue) throws SQLServerException { + void execute(DTV dtv, byte[] byteArrayValue) throws SQLServerException { if (null != byteArrayValue && byteArrayValue.length > DataTypes.SHORT_VARTYPE_MAX_BYTES) dtv.setJdbcType(dtv.getJdbcType().isBinary() ? JDBCType.LONGVARBINARY : JDBCType.LONGVARCHAR); setTypeDefinition(dtv); } - void execute(DTV dtv, - Blob blobValue) throws SQLServerException { + void execute(DTV dtv, Blob blobValue) throws SQLServerException { setTypeDefinition(dtv); } - void execute(DTV dtv, - InputStream inputStreamValue) throws SQLServerException { + void execute(DTV dtv, InputStream inputStreamValue) throws SQLServerException { StreamSetterArgs streamSetterArgs = dtv.getStreamSetterArgs(); JDBCType jdbcType = dtv.getJdbcType(); // If the JDBC type is currently a "short" type, then figure out if needs to be bumped up to a "long" type - if (JDBCType.CHAR == jdbcType || JDBCType.VARCHAR == jdbcType || JDBCType.BINARY == jdbcType || JDBCType.VARBINARY == jdbcType) { + if (JDBCType.CHAR == jdbcType || JDBCType.VARCHAR == jdbcType || JDBCType.BINARY == jdbcType + || JDBCType.VARBINARY == jdbcType) { // If we know the length is too long for a "short" type, then convert to a "long" type. if (streamSetterArgs.getLength() > DataTypes.SHORT_VARTYPE_MAX_BYTES) dtv.setJdbcType(jdbcType.isBinary() ? JDBCType.LONGVARBINARY : JDBCType.LONGVARCHAR); @@ -1088,8 +1048,7 @@ else if (DataTypes.UNKNOWN_STREAM_LENGTH == streamSetterArgs.getLength()) { bytesRead = 0; bufferedStream.reset(); - } - catch (IOException e) { + } catch (IOException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_errorReadingStream")); Object[] msgArgs = {e.toString()}; SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), "", true); @@ -1097,8 +1056,10 @@ else if (DataTypes.UNKNOWN_STREAM_LENGTH == streamSetterArgs.getLength()) { dtv.setValue(bufferedStream, JavaType.INPUTSTREAM); - // If the stream is longer than what can fit into the "short" type, then use the "long" type instead. - // Otherwise, we know the exact stream length since we reached end of stream before reading SHORT_VARTYPE_MAX_BYTES + 1 + // If the stream is longer than what can fit into the "short" type, then use the "long" type + // instead. + // Otherwise, we know the exact stream length since we reached end of stream before reading + // SHORT_VARTYPE_MAX_BYTES + 1 // bytes. So adjust the setter args to reflect the known length to avoid unnecessarily copying the // stream again in SendByRPCOp. if (bytesRead > DataTypes.SHORT_VARTYPE_MAX_BYTES) @@ -1111,8 +1072,7 @@ else if (DataTypes.UNKNOWN_STREAM_LENGTH == streamSetterArgs.getLength()) { setTypeDefinition(dtv); } - void execute(DTV dtv, - Reader readerValue) throws SQLServerException { + void execute(DTV dtv, Reader readerValue) throws SQLServerException { // If the JDBC type is currently a "short" type, then figure out if needs to be bumped up to a "long" type if (JDBCType.NCHAR == dtv.getJdbcType() || JDBCType.NVARCHAR == dtv.getJdbcType()) { StreamSetterArgs streamSetterArgs = dtv.getStreamSetterArgs(); @@ -1138,8 +1098,7 @@ else if (DataTypes.UNKNOWN_STREAM_LENGTH == streamSetterArgs.getLength()) { charsRead = 0; bufferedReader.reset(); - } - catch (IOException e) { + } catch (IOException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_errorReadingStream")); Object[] msgArgs = {e.toString()}; SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), "", true); @@ -1157,34 +1116,31 @@ else if (DataTypes.UNKNOWN_STREAM_LENGTH == streamSetterArgs.getLength()) { setTypeDefinition(dtv); } - void execute(DTV dtv, - SQLServerSQLXML xmlValue) throws SQLServerException { + void execute(DTV dtv, SQLServerSQLXML xmlValue) throws SQLServerException { setTypeDefinition(dtv); } - void execute(DTV dtv, - com.microsoft.sqlserver.jdbc.TVP tvpValue) throws SQLServerException { + void execute(DTV dtv, com.microsoft.sqlserver.jdbc.TVP tvpValue) throws SQLServerException { setTypeDefinition(dtv); } /* * (non-Javadoc) - * - * @see com.microsoft.sqlserver.jdbc.DTVExecuteOp#execute(com.microsoft.sqlserver.jdbc.DTV, microsoft.sql.SqlVariant) + * @see com.microsoft.sqlserver.jdbc.DTVExecuteOp#execute(com.microsoft.sqlserver.jdbc.DTV, + * microsoft.sql.SqlVariant) */ @Override - void execute(DTV dtv, - SqlVariant SqlVariantValue) throws SQLServerException { + void execute(DTV dtv, SqlVariant SqlVariantValue) throws SQLServerException { setTypeDefinition(dtv); } } /** - * Returns a string used to define the parameter type for the server; null if no value for the parameter has been set or registered. + * Returns a string used to define the parameter type for the server; null if no value for the parameter has been + * set or registered. */ - String getTypeDefinition(SQLServerConnection con, - TDSReader tdsReader) throws SQLServerException { + String getTypeDefinition(SQLServerConnection con, TDSReader tdsReader) throws SQLServerException { if (null == inputDTV) return null; @@ -1192,16 +1148,15 @@ String getTypeDefinition(SQLServerConnection con, return typeDefinition; } - void sendByRPC(TDSWriter tdsWriter, - SQLServerConnection conn) throws SQLServerException { + void sendByRPC(TDSWriter tdsWriter, SQLServerConnection conn) throws SQLServerException { assert null != inputDTV : "Parameter was neither set nor registered"; try { inputDTV.sendCryptoMetaData(this.cryptoMeta, tdsWriter); inputDTV.jdbcTypeSetByUser(getJdbcTypeSetByUser(), getValueLength()); - inputDTV.sendByRPC(name, null, conn.getDatabaseCollation(), valueLength, isOutput() ? outScale : scale, isOutput(), tdsWriter, conn); - } - finally { + inputDTV.sendByRPC(name, null, conn.getDatabaseCollation(), valueLength, isOutput() ? outScale : scale, + isOutput(), tdsWriter, conn); + } finally { // reset the cryptoMeta in IOBuffer inputDTV.sendCryptoMetaData(null, tdsWriter); } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ParameterUtils.java b/src/main/java/com/microsoft/sqlserver/jdbc/ParameterUtils.java index 4cd7f2b84..0dcc60691 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ParameterUtils.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ParameterUtils.java @@ -1,129 +1,126 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -/** - * ParameterUtils provides utility a set of methods to manipulate parameter values. - */ - -final class ParameterUtils { - static byte[] HexToBin(String hexV) throws SQLServerException { - int len = hexV.length(); - char orig[] = hexV.toCharArray(); - if ((len % 2) != 0) - SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_stringNotInHex"), null, false); - byte[] bin = new byte[len / 2]; - for (int i = 0; i < len / 2; i++) { - bin[i] = (byte) ((CharToHex(orig[2 * i]) << 4) + CharToHex(orig[2 * i + 1])); - } - return bin; - } - - // conversion routine valid values 0-9 a-f A-F - // throws exception when failed to convert - // - static byte CharToHex(char CTX) throws SQLServerException { - byte ret = 0; - if (CTX >= 'A' && CTX <= 'F') { - ret = (byte) (CTX - 'A' + 10); - } - else if (CTX >= 'a' && CTX <= 'f') { - ret = (byte) (CTX - 'a' + 10); - } - else if (CTX >= '0' && CTX <= '9') { - ret = (byte) (CTX - '0'); - } - else { - SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_stringNotInHex"), null, false); - } - return ret; - } - - /** - * Locates the first occurrence of [c] in [sql] starting at [offset], where [sql] is a SQL statement string, which may contain any combination of: - * - * - Literals, enclosed in single quotes (') - Literals, enclosed in double quotes (") - Escape sequences, enclosed in square brackets ([]) - - * Escaped escapes or literal delimiters (i.e. '', "", or ]]) in the above - Single-line comments, beginning in -- and continuing to EOL - - * Multi-line comments, enclosed in C-style comment delimiters - * - * and [c] is not contained any of the above. - * - * @param c - * the character to search for - * @param sql - * the SQL string to search in - * @param offset - * the offset into [sql] to start searching from - * @return Offset into [sql] where [c] occurs, or sql.length if [c] is not found. - * @throws SQLServerException - * when [sql] does not follow - */ - @SuppressWarnings({"fallthrough"}) - static int scanSQLForChar(char ch, - String sql, - int offset) { - char chQuote; - char chTmp; - final int len = sql.length(); - - while (offset < len) { - switch (chTmp = sql.charAt(offset++)) { - case '/': - if (offset == len) - break; - - if (sql.charAt(offset) == '*') { // If '/* ... */' comment - while (++offset < len) { // Go thru comment. - if (sql.charAt(offset) == '*' && offset + 1 < len && sql.charAt(offset + 1) == '/') { // If end of comment - offset += 2; - break; - } - } - break; - } - else if (sql.charAt(offset) == '-') - break; - - // Fall through - will fail next if and end up in default case - case '-': - if (sql.charAt(offset) == '-') { // If '-- ... \n' comment - while (++offset < len) { // Go thru comment. - if (sql.charAt(offset) == '\n' || sql.charAt(offset) == '\r') { // If end of comment - offset++; - break; - } - } - break; - } - // Fall through to test character - default: - if (ch == chTmp) - return offset - 1; - break; - - case '[': - chTmp = ']'; - case '\'': - case '"': - chQuote = chTmp; - while (offset < len) { - if (sql.charAt(offset++) == chQuote) { - if (len == offset || sql.charAt(offset) != chQuote) - break; - - ++offset; - } - } - break; - } - } - - return len; - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +/** + * ParameterUtils provides utility a set of methods to manipulate parameter values. + */ + +final class ParameterUtils { + static byte[] HexToBin(String hexV) throws SQLServerException { + int len = hexV.length(); + char orig[] = hexV.toCharArray(); + if ((len % 2) != 0) + SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_stringNotInHex"), + null, false); + byte[] bin = new byte[len / 2]; + for (int i = 0; i < len / 2; i++) { + bin[i] = (byte) ((CharToHex(orig[2 * i]) << 4) + CharToHex(orig[2 * i + 1])); + } + return bin; + } + + // conversion routine valid values 0-9 a-f A-F + // throws exception when failed to convert + // + static byte CharToHex(char CTX) throws SQLServerException { + byte ret = 0; + if (CTX >= 'A' && CTX <= 'F') { + ret = (byte) (CTX - 'A' + 10); + } else if (CTX >= 'a' && CTX <= 'f') { + ret = (byte) (CTX - 'a' + 10); + } else if (CTX >= '0' && CTX <= '9') { + ret = (byte) (CTX - '0'); + } else { + SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_stringNotInHex"), + null, false); + } + return ret; + } + + /** + * Locates the first occurrence of [c] in [sql] starting at [offset], where [sql] is a SQL statement string, which + * may contain any combination of: + * + * - Literals, enclosed in single quotes (') - Literals, enclosed in double quotes (") - Escape sequences, enclosed + * in square brackets ([]) - Escaped escapes or literal delimiters (i.e. '', "", or ]]) in the above - Single-line + * comments, beginning in -- and continuing to EOL - Multi-line comments, enclosed in C-style comment delimiters + * + * and [c] is not contained any of the above. + * + * @param c + * the character to search for + * @param sql + * the SQL string to search in + * @param offset + * the offset into [sql] to start searching from + * @return Offset into [sql] where [c] occurs, or sql.length if [c] is not found. + * @throws SQLServerException + * when [sql] does not follow + */ + @SuppressWarnings({"fallthrough"}) + static int scanSQLForChar(char ch, String sql, int offset) { + char chQuote; + char chTmp; + final int len = sql.length(); + + while (offset < len) { + switch (chTmp = sql.charAt(offset++)) { + case '/': + if (offset == len) + break; + + if (sql.charAt(offset) == '*') { // If '/* ... */' comment + while (++offset < len) { // Go thru comment. + if (sql.charAt(offset) == '*' && offset + 1 < len && sql.charAt(offset + 1) == '/') { // If + // end + // of + // comment + offset += 2; + break; + } + } + break; + } else if (sql.charAt(offset) == '-') + break; + + // Fall through - will fail next if and end up in default case + case '-': + if (sql.charAt(offset) == '-') { // If '-- ... \n' comment + while (++offset < len) { // Go thru comment. + if (sql.charAt(offset) == '\n' || sql.charAt(offset) == '\r') { // If end of comment + offset++; + break; + } + } + break; + } + // Fall through to test character + default: + if (ch == chTmp) + return offset - 1; + break; + + case '[': + chTmp = ']'; + case '\'': + case '"': + chQuote = chTmp; + while (offset < len) { + if (sql.charAt(offset++) == chQuote) { + if (len == offset || sql.charAt(offset) != chQuote) + break; + + ++offset; + } + } + break; + } + } + + return len; + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ParsedSQLMetadata.java b/src/main/java/com/microsoft/sqlserver/jdbc/ParsedSQLMetadata.java index 19c34ebec..b41bbf09f 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ParsedSQLMetadata.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ParsedSQLMetadata.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -14,15 +11,15 @@ final class ParsedSQLCacheItem { /** The SQL text AFTER processing. */ String processedSQL; - int parameterCount; + int[] parameterPositions; String procedureName; - boolean bReturnValueSyntax; - - ParsedSQLCacheItem(String processedSQL, int parameterCount, String procedureName, boolean bReturnValueSyntax) { + boolean bReturnValueSyntax; + + ParsedSQLCacheItem(String processedSQL, int[] parameterPositions, String procedureName, + boolean bReturnValueSyntax) { this.processedSQL = processedSQL; - this.parameterCount = parameterCount; + this.parameterPositions = parameterPositions; this.procedureName = procedureName; this.bReturnValueSyntax = bReturnValueSyntax; } } - diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ReaderInputStream.java b/src/main/java/com/microsoft/sqlserver/jdbc/ReaderInputStream.java index 1a2513816..54df7d76b 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ReaderInputStream.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ReaderInputStream.java @@ -1,272 +1,266 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.nio.Buffer; -import java.nio.ByteBuffer; -import java.nio.CharBuffer; -import java.nio.charset.Charset; -import java.text.MessageFormat; - -/** - * InputStream adapter for Readers. - * - * This class implements an InputStream whose bytes are encoded character values that are read on demand from a wrapped Reader using the suplied - * Charset. - * - * Character values pass through through the following in their transformation to bytes: Reader .. CharBuffer .. Charset (CharsetEncoder) .. - * ByteBuffer .. InputStream - * - * To minimize memory usage, the CharBuffer and ByteBuffer instances used by this class are created on demand when InputStream read methods are - * called. - */ -class ReaderInputStream extends InputStream { - // The Reader that this ReaderInputStream adapts. - private final Reader reader; - - // The character set used to encode character values as - // they are read from the stream. - private final Charset charset; - - // Length of the Reader, if known, in characters - private final long readerLength; - - // Count of characters read from the reader across all calls to encodeChars() - private long readerCharsRead = 0; - - // Flag indicating whether the stream has reached the end of its data - private boolean atEndOfStream = false; - - // Internal character buffer used to transfer character values - // between the Reader and the Charset encoder. - private CharBuffer rawChars = null; - private static final int MAX_CHAR_BUFFER_SIZE = DataTypes.SHORT_VARTYPE_MAX_CHARS; - - // Most recent set of bytes that were encoded from rawChars. - // This value is null initially and when the end of stream is reached. - private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate(0); - private ByteBuffer encodedChars = EMPTY_BUFFER; - - ReaderInputStream(Reader reader, - Charset charset, - long readerLength) { - assert reader != null; - assert charset != null; - assert DataTypes.UNKNOWN_STREAM_LENGTH == readerLength || readerLength >= 0; - - this.reader = reader; - this.charset = charset; - this.readerLength = readerLength; - } - - /** - * Returns the number of bytes that can be read (or skipped over) from this input stream without blocking by the next caller of a method for this - * input stream. - * - * @return - the number of bytes that can be read from this input stream without blocking - * @throws IOException - * - if an I/O error occurs - */ - public int available() throws IOException { - assert null != reader; - assert null != encodedChars; - - // If we know the reader to be empty, then take the short cut - if (0 == readerLength) - return 0; - - // If there are encoded characters remaining in the buffer then that's our best guess. - if (encodedChars.remaining() > 0) - return encodedChars.remaining(); - - // If there are no encoded characters left in the buffer (or the buffer hasn't yet been populated) - // then ask the Reader whether a call to its read() method would block. If reading wouldn't block, - // then there's at least 1 byte that can be encoded, possibly more. - if (reader.ready()) - return 1; - - // If there are no encoded characters, and reading characters from the underlying Reader object - // would block, then nothing (more) can be read from this stream without blocking. - return 0; - } - - private final byte[] oneByte = new byte[1]; - - public int read() throws IOException { - return (-1 == readInternal(oneByte, 0, oneByte.length)) ? -1 : oneByte[0]; - } - - public int read(byte[] b) throws IOException { - return readInternal(b, 0, b.length); - } - - public int read(byte[] b, - int off, - int len) throws IOException { - return readInternal(b, off, len); - } - - private int readInternal(byte[] b, - int off, - int len) throws IOException { - assert null != b; - assert 0 <= off && off <= b.length; - assert 0 <= len && len <= b.length; - assert off <= b.length - len; - - if (0 == len) - return 0; - - int bytesRead = 0; - while (bytesRead < len && encodeChars()) { - // Read the lesser of the number of bytes remaining - // in the encoded character buffer and the number - // of bytes remaining for this read request. - int bytesToRead = encodedChars.remaining(); - if (bytesToRead > len - bytesRead) - bytesToRead = len - bytesRead; - - // We should actually be attempting to read something here, - // or we'll be in an infinite loop... - assert bytesToRead > 0; - - encodedChars.get(b, off + bytesRead, bytesToRead); - bytesRead += bytesToRead; - } - - // Return number of bytes read, which may be less than - // the number of bytes requested, or -1 at end of stream. - return (0 == bytesRead && atEndOfStream) ? -1 : bytesRead; - } - - /** - * Determines whether encoded characters are available, encoding them on demand by reading them from the reader as necessary. - * - * @return true when encoded characters are available - * @return false when no more encoded characters are available (i.e. end of stream) - * @exception IOException - * if an I/O error occurs reading from the reader or encoding the characters - */ - private boolean encodeChars() throws IOException { - // Once at the end of the stream, no more characters can be encoded. - if (atEndOfStream) - return false; - - // Not at end of stream; check whether there are any encoded characters - // remaining in the byte buffer. If there are, don't encode any more - // characters this time. - if (encodedChars.hasRemaining()) - return true; - - // Encoded byte buffer is either exhausted or has never been filled - // (i.e. first time through). In that case, we need to repopulate - // the encoded character buffer by encoding raw characters. - // - // To do that, there needs to be raw characters available to encode. - // If there are no raw characters available (because the raw character - // buffer has been exhausted or never filled), then try to read in - // raw characters from the reader. - if (null == rawChars || !rawChars.hasRemaining()) { - if (null == rawChars) { - assert MAX_CHAR_BUFFER_SIZE <= Integer.MAX_VALUE; - rawChars = CharBuffer.allocate((DataTypes.UNKNOWN_STREAM_LENGTH == readerLength || readerLength > MAX_CHAR_BUFFER_SIZE) - ? MAX_CHAR_BUFFER_SIZE : Math.max((int) readerLength, 1)); - } - else { - // Flip the buffer to be ready for put (reader read) operations. - ((Buffer)rawChars).clear(); - } - - // Try to fill up the raw character buffer by reading available characters - // from the reader into it. - // - // This loop continues until one of the following conditions is satisfied: - // - the raw character buffer has been filled, - // - the reader reaches end-of-stream - // - the reader throws any kind of Exception (driver throws an IOException) - // - the reader violates its interface contract (driver throws an IOException) - while (rawChars.hasRemaining()) { - int lastPosition = ((Buffer)rawChars).position(); - int charsRead = 0; - - // Try reading from the app-supplied Reader - try { - charsRead = reader.read(rawChars); - } - - // Catch any kind of exception and translate it to an IOException. - // The app-supplied reader cannot be trusted just to throw IOExceptions... - catch (Exception e) { - String detailMessage = e.getMessage(); - if (null == detailMessage) - detailMessage = SQLServerException.getErrString("R_streamReadReturnedInvalidValue"); - IOException ioException = new IOException(detailMessage); - ioException.initCause(e); - throw ioException; - } - - if (charsRead < -1 || 0 == charsRead) - throw new IOException(SQLServerException.getErrString("R_streamReadReturnedInvalidValue")); - - if (-1 == charsRead) { - // If the reader violates its interface contract then throw an exception. - if (((Buffer)rawChars).position() != lastPosition) - throw new IOException(SQLServerException.getErrString("R_streamReadReturnedInvalidValue")); - - // Check that the reader has returned exactly the amount of data we expect - if (DataTypes.UNKNOWN_STREAM_LENGTH != readerLength && 0 != readerLength - readerCharsRead) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_mismatchedStreamLength")); - throw new IOException(form.format(new Object[] {readerLength, readerCharsRead})); - } - - // If there are no characters left to encode then we're done. - if (0 == ((Buffer)rawChars).position()) { - rawChars = null; - atEndOfStream = true; - return false; - } - - // Otherwise, we've filled the buffer as much as we can. - break; - } - - assert charsRead > 0; - - // If the reader violates its interface contract then throw an exception. - if (charsRead != ((Buffer)rawChars).position() - lastPosition) - throw new IOException(SQLServerException.getErrString("R_streamReadReturnedInvalidValue")); - - // Check that the reader isn't trying to return more data than we expect - if (DataTypes.UNKNOWN_STREAM_LENGTH != readerLength && charsRead > readerLength - readerCharsRead) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_mismatchedStreamLength")); - throw new IOException(form.format(new Object[] {readerLength, readerCharsRead})); - } - - readerCharsRead += charsRead; - } - - // The raw character buffer may now have characters available for encoding. - // Flip the buffer back to be ready for get (charset encode) operations. - ((Buffer)rawChars).flip(); - } - - // If the raw character buffer remains empty, despite our efforts to (re)populate it, - // then no characters can be encoded at this time. This can happen if the reader reports - // that no characters were ready to be read. - if (!rawChars.hasRemaining()) - return false; - - // Raw characters are now available to be encoded, so encode them. - encodedChars = charset.encode(rawChars); - return true; - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.nio.Buffer; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.text.MessageFormat; + + +/** + * InputStream adapter for Readers. + * + * This class implements an InputStream whose bytes are encoded character values that are read on demand from a wrapped + * Reader using the suplied Charset. + * + * Character values pass through through the following in their transformation to bytes: Reader .. CharBuffer .. Charset + * (CharsetEncoder) .. ByteBuffer .. InputStream + * + * To minimize memory usage, the CharBuffer and ByteBuffer instances used by this class are created on demand when + * InputStream read methods are called. + */ +class ReaderInputStream extends InputStream { + // The Reader that this ReaderInputStream adapts. + private final Reader reader; + + // The character set used to encode character values as + // they are read from the stream. + private final Charset charset; + + // Length of the Reader, if known, in characters + private final long readerLength; + + // Count of characters read from the reader across all calls to encodeChars() + private long readerCharsRead = 0; + + // Flag indicating whether the stream has reached the end of its data + private boolean atEndOfStream = false; + + // Internal character buffer used to transfer character values + // between the Reader and the Charset encoder. + private CharBuffer rawChars = null; + private static final int MAX_CHAR_BUFFER_SIZE = DataTypes.SHORT_VARTYPE_MAX_CHARS; + + // Most recent set of bytes that were encoded from rawChars. + // This value is null initially and when the end of stream is reached. + private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate(0); + private ByteBuffer encodedChars = EMPTY_BUFFER; + + ReaderInputStream(Reader reader, Charset charset, long readerLength) { + assert reader != null; + assert charset != null; + assert DataTypes.UNKNOWN_STREAM_LENGTH == readerLength || readerLength >= 0; + + this.reader = reader; + this.charset = charset; + this.readerLength = readerLength; + } + + /** + * Returns the number of bytes that can be read (or skipped over) from this input stream without blocking by the + * next caller of a method for this input stream. + * + * @return - the number of bytes that can be read from this input stream without blocking + * @throws IOException + * - if an I/O error occurs + */ + public int available() throws IOException { + assert null != reader; + assert null != encodedChars; + + // If we know the reader to be empty, then take the short cut + if (0 == readerLength) + return 0; + + // If there are encoded characters remaining in the buffer then that's our best guess. + if (encodedChars.remaining() > 0) + return encodedChars.remaining(); + + // If there are no encoded characters left in the buffer (or the buffer hasn't yet been populated) + // then ask the Reader whether a call to its read() method would block. If reading wouldn't block, + // then there's at least 1 byte that can be encoded, possibly more. + if (reader.ready()) + return 1; + + // If there are no encoded characters, and reading characters from the underlying Reader object + // would block, then nothing (more) can be read from this stream without blocking. + return 0; + } + + private final byte[] oneByte = new byte[1]; + + public int read() throws IOException { + return (-1 == readInternal(oneByte, 0, oneByte.length)) ? -1 : oneByte[0]; + } + + public int read(byte[] b) throws IOException { + return readInternal(b, 0, b.length); + } + + public int read(byte[] b, int off, int len) throws IOException { + return readInternal(b, off, len); + } + + private int readInternal(byte[] b, int off, int len) throws IOException { + assert null != b; + assert 0 <= off && off <= b.length; + assert 0 <= len && len <= b.length; + assert off <= b.length - len; + + if (0 == len) + return 0; + + int bytesRead = 0; + while (bytesRead < len && encodeChars()) { + // Read the lesser of the number of bytes remaining + // in the encoded character buffer and the number + // of bytes remaining for this read request. + int bytesToRead = encodedChars.remaining(); + if (bytesToRead > len - bytesRead) + bytesToRead = len - bytesRead; + + // We should actually be attempting to read something here, + // or we'll be in an infinite loop... + assert bytesToRead > 0; + + encodedChars.get(b, off + bytesRead, bytesToRead); + bytesRead += bytesToRead; + } + + // Return number of bytes read, which may be less than + // the number of bytes requested, or -1 at end of stream. + return (0 == bytesRead && atEndOfStream) ? -1 : bytesRead; + } + + /** + * Determines whether encoded characters are available, encoding them on demand by reading them from the reader as + * necessary. + * + * @return true when encoded characters are available + * @return false when no more encoded characters are available (i.e. end of stream) + * @exception IOException + * if an I/O error occurs reading from the reader or encoding the characters + */ + private boolean encodeChars() throws IOException { + // Once at the end of the stream, no more characters can be encoded. + if (atEndOfStream) + return false; + + // Not at end of stream; check whether there are any encoded characters + // remaining in the byte buffer. If there are, don't encode any more + // characters this time. + if (encodedChars.hasRemaining()) + return true; + + // Encoded byte buffer is either exhausted or has never been filled + // (i.e. first time through). In that case, we need to repopulate + // the encoded character buffer by encoding raw characters. + // + // To do that, there needs to be raw characters available to encode. + // If there are no raw characters available (because the raw character + // buffer has been exhausted or never filled), then try to read in + // raw characters from the reader. + if (null == rawChars || !rawChars.hasRemaining()) { + if (null == rawChars) { + assert MAX_CHAR_BUFFER_SIZE <= Integer.MAX_VALUE; + rawChars = CharBuffer.allocate((DataTypes.UNKNOWN_STREAM_LENGTH == readerLength + || readerLength > MAX_CHAR_BUFFER_SIZE) ? MAX_CHAR_BUFFER_SIZE + : Math.max((int) readerLength, 1)); + } else { + // Flip the buffer to be ready for put (reader read) operations. + ((Buffer) rawChars).clear(); + } + + // Try to fill up the raw character buffer by reading available characters + // from the reader into it. + // + // This loop continues until one of the following conditions is satisfied: + // - the raw character buffer has been filled, + // - the reader reaches end-of-stream + // - the reader throws any kind of Exception (driver throws an IOException) + // - the reader violates its interface contract (driver throws an IOException) + while (rawChars.hasRemaining()) { + int lastPosition = ((Buffer) rawChars).position(); + int charsRead = 0; + + // Try reading from the app-supplied Reader + try { + charsRead = reader.read(rawChars); + } + + // Catch any kind of exception and translate it to an IOException. + // The app-supplied reader cannot be trusted just to throw IOExceptions... + catch (Exception e) { + String detailMessage = e.getMessage(); + if (null == detailMessage) + detailMessage = SQLServerException.getErrString("R_streamReadReturnedInvalidValue"); + IOException ioException = new IOException(detailMessage); + ioException.initCause(e); + throw ioException; + } + + if (charsRead < -1 || 0 == charsRead) + throw new IOException(SQLServerException.getErrString("R_streamReadReturnedInvalidValue")); + + if (-1 == charsRead) { + // If the reader violates its interface contract then throw an exception. + if (((Buffer) rawChars).position() != lastPosition) + throw new IOException(SQLServerException.getErrString("R_streamReadReturnedInvalidValue")); + + // Check that the reader has returned exactly the amount of data we expect + if (DataTypes.UNKNOWN_STREAM_LENGTH != readerLength && 0 != readerLength - readerCharsRead) { + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_mismatchedStreamLength")); + throw new IOException(form.format(new Object[] {readerLength, readerCharsRead})); + } + + // If there are no characters left to encode then we're done. + if (0 == ((Buffer) rawChars).position()) { + rawChars = null; + atEndOfStream = true; + return false; + } + + // Otherwise, we've filled the buffer as much as we can. + break; + } + + assert charsRead > 0; + + // If the reader violates its interface contract then throw an exception. + if (charsRead != ((Buffer) rawChars).position() - lastPosition) + throw new IOException(SQLServerException.getErrString("R_streamReadReturnedInvalidValue")); + + // Check that the reader isn't trying to return more data than we expect + if (DataTypes.UNKNOWN_STREAM_LENGTH != readerLength && charsRead > readerLength - readerCharsRead) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_mismatchedStreamLength")); + throw new IOException(form.format(new Object[] {readerLength, readerCharsRead})); + } + + readerCharsRead += charsRead; + } + + // The raw character buffer may now have characters available for encoding. + // Flip the buffer back to be ready for get (charset encode) operations. + ((Buffer) rawChars).flip(); + } + + // If the raw character buffer remains empty, despite our efforts to (re)populate it, + // then no characters can be encoded at this time. This can happen if the reader reports + // that no characters were ready to be read. + if (!rawChars.hasRemaining()) + return false; + + // Raw characters are now available to be encoded, so encode them. + encodedChars = charset.encode(rawChars); + return true; + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLCollation.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLCollation.java index 6dcf58cf6..75a1aed72 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLCollation.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLCollation.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -17,41 +14,48 @@ /** - * SQLCollation is helper class used to read TDS collation from a TDS stream. - * Collation is in the following BNF format (see TDS spec for full details): + * SQLCollation is helper class used to read TDS collation from a TDS stream. Collation is in the following BNF format + * (see TDS spec for full details): * - * LCID := 20 * BIT; - * fIgnoreCase := BIT; - * fIgnoreAccent := BIT; - * fIgnoreWidth := BIT; - * fIgnoreKana := BIT; - * fBinary := BIT; - * ColFlags := fIgnoreCase, fIgnoreAccent, fIgnoreWidth, fIgnoreKana, fBinary, FRESERVEDBIT, FRESERVEDBIT, FRESERVEDBIT; - * Version := 4 * BIT; - * SortId := BYTE; + * LCID := 20 * BIT; fIgnoreCase := BIT; fIgnoreAccent := BIT; fIgnoreWidth := BIT; fIgnoreKana := BIT; fBinary := BIT; + * ColFlags := fIgnoreCase, fIgnoreAccent, fIgnoreWidth, fIgnoreKana, fBinary, FRESERVEDBIT, FRESERVEDBIT, FRESERVEDBIT; + * Version := 4 * BIT; SortId := BYTE; * - * COLLATION := LCID, ColFlags, Version, SortId; + * COLLATION := LCID, ColFlags, Version, SortId; * */ -final class SQLCollation implements java.io.Serializable -{ - /** - * - */ - private static final long serialVersionUID = 6748833280721312349L; - - private final int info; // First 4 bytes of TDS collation. - private int langID() { return info & 0x0000FFFF; } - private final int sortId; // 5th byte of TDS collation. +final class SQLCollation implements java.io.Serializable { + /** + * + */ + private static final long serialVersionUID = 6748833280721312349L; + + private final int info; // First 4 bytes of TDS collation. + + private int langID() { + return info & 0x0000FFFF; + } + + private final int sortId; // 5th byte of TDS collation. private final Encoding encoding; private static final int UTF8_IN_TDSCOLLATION = 0x4000000; // Utility methods for getting details of this collation's encoding - final Charset getCharset() throws SQLServerException { return encoding.charset(); } - final boolean supportsAsciiConversion() { return encoding.supportsAsciiConversion(); } - final boolean hasAsciiCompatibleSBCS() { return encoding.hasAsciiCompatibleSBCS(); } + final Charset getCharset() throws SQLServerException { + return encoding.charset(); + } - static final int tdsLength() { return 5; } // Length of collation in TDS (in bytes) + final boolean supportsAsciiConversion() { + return encoding.supportsAsciiConversion(); + } + + final boolean hasAsciiCompatibleSBCS() { + return encoding.hasAsciiCompatibleSBCS(); + } + + static final int tdsLength() { + return 5; + } // Length of collation in TDS (in bytes) /** * Returns the collation info @@ -61,7 +65,7 @@ final class SQLCollation implements java.io.Serializable int getCollationInfo() { return this.info; } - + /** * return sort ID * @@ -70,23 +74,21 @@ int getCollationInfo() { int getCollationSortID() { return this.sortId; } - + /** * Reads TDS collation from TDS buffer into SQLCollation class. + * * @param tdsReader */ - SQLCollation(TDSReader tdsReader) throws UnsupportedEncodingException, SQLServerException - { - /* - * TDS rule for collation: - * COLLATION = LCID ColFlags Version SortId - */ - info = tdsReader.readInt(); // 4 bytes, contains: LCID ColFlags Version + SQLCollation(TDSReader tdsReader) throws UnsupportedEncodingException, SQLServerException { + /* + * TDS rule for collation: COLLATION = LCID ColFlags Version SortId + */ + info = tdsReader.readInt(); // 4 bytes, contains: LCID ColFlags Version sortId = tdsReader.readUnsignedByte(); // 1 byte, contains: SortId if (UTF8_IN_TDSCOLLATION == (info & UTF8_IN_TDSCOLLATION)) { encoding = Encoding.UTF8; - } - else { + } else { // For a SortId==0 collation, the LCID bits correspond to a LocaleId encoding = (0 == sortId) ? encodingFromLCID() : encodingFromSortId(); } @@ -94,12 +96,13 @@ int getCollationSortID() { /** * Writes TDS collation from SQLCollation class into TDS buffer at offset. - * @param tdsWriter TDS writer to write collation to. + * + * @param tdsWriter + * TDS writer to write collation to. */ - void writeCollation(TDSWriter tdsWriter) throws SQLServerException - { - tdsWriter.writeInt(info); - tdsWriter.writeByte((byte) (sortId & 0xFF)); + void writeCollation(TDSWriter tdsWriter) throws SQLServerException { + tdsWriter.writeInt(info); + tdsWriter.writeByte((byte) (sortId & 0xFF)); } /** @@ -109,229 +112,227 @@ void writeCollation(TDSWriter tdsWriter) throws SQLServerException * * The set of locales is derived from the following resources: * - * http://download.microsoft.com/download/9/5/e/95ef66af-9026-4bb0-a41d-a4f81802d92c/[MS-LCID].pdf - * Lists LCID values and their corresponding meanings (in RFC 3066 format). Used to derive the names - * for the various enumeration constants. + * http://download.microsoft.com/download/9/5/e/95ef66af-9026-4bb0-a41d-a4f81802d92c/[MS-LCID].pdf Lists LCID values + * and their corresponding meanings (in RFC 3066 format). Used to derive the names for the various enumeration + * constants. * - * x_rgLocaleMap and x_rgLcidOrdMap in sql\common\include\localemap.h in Katmai source tree - * Collectively, these two tables provide a mapping of collation-version specific encodings - * for every locale supported by SQL Server. Lang IDs are derived from locales' LCIDs. + * x_rgLocaleMap and x_rgLcidOrdMap in sql\common\include\localemap.h in Katmai source tree Collectively, these two + * tables provide a mapping of collation-version specific encodings for every locale supported by SQL Server. Lang + * IDs are derived from locales' LCIDs. */ - enum WindowsLocale - { - ar_SA (0x0401, Encoding.CP1256), - bg_BG (0x0402, Encoding.CP1251), - ca_ES (0x0403, Encoding.CP1252), - zh_TW (0x0404, Encoding.CP950), - cs_CZ (0x0405, Encoding.CP1250), - da_DK (0x0406, Encoding.CP1252), - de_DE (0x0407, Encoding.CP1252), - el_GR (0x0408, Encoding.CP1253), - en_US (0x0409, Encoding.CP1252), - es_ES_tradnl (0x040a, Encoding.CP1252), - fi_FI (0x040b, Encoding.CP1252), - fr_FR (0x040c, Encoding.CP1252), - he_IL (0x040d, Encoding.CP1255), - hu_HU (0x040e, Encoding.CP1250), - is_IS (0x040f, Encoding.CP1252), - it_IT (0x0410, Encoding.CP1252), - ja_JP (0x0411, Encoding.CP932), - ko_KR (0x0412, Encoding.CP949), - nl_NL (0x0413, Encoding.CP1252), - nb_NO (0x0414, Encoding.CP1252), - pl_PL (0x0415, Encoding.CP1250), - pt_BR (0x0416, Encoding.CP1252), - rm_CH (0x0417, Encoding.CP1252), - ro_RO (0x0418, Encoding.CP1250), - ru_RU (0x0419, Encoding.CP1251), - hr_HR (0x041a, Encoding.CP1250), - sk_SK (0x041b, Encoding.CP1250), - sq_AL (0x041c, Encoding.CP1250), - sv_SE (0x041d, Encoding.CP1252), - th_TH (0x041e, Encoding.CP874), - tr_TR (0x041f, Encoding.CP1254), - ur_PK (0x0420, Encoding.CP1256), - id_ID (0x0421, Encoding.CP1252), - uk_UA (0x0422, Encoding.CP1251), - be_BY (0x0423, Encoding.CP1251), - sl_SI (0x0424, Encoding.CP1250), - et_EE (0x0425, Encoding.CP1257), - lv_LV (0x0426, Encoding.CP1257), - lt_LT (0x0427, Encoding.CP1257), - tg_Cyrl_TJ (0x0428, Encoding.CP1251), - fa_IR (0x0429, Encoding.CP1256), - vi_VN (0x042a, Encoding.CP1258), - hy_AM (0x042b, Encoding.CP1252), - az_Latn_AZ (0x042c, Encoding.CP1254), - eu_ES (0x042d, Encoding.CP1252), - wen_DE (0x042e, Encoding.CP1252), - mk_MK (0x042f, Encoding.CP1251), - tn_ZA (0x0432, Encoding.CP1252), - xh_ZA (0x0434, Encoding.CP1252), - zu_ZA (0x0435, Encoding.CP1252), - Af_ZA (0x0436, Encoding.CP1252), - ka_GE (0x0437, Encoding.CP1252), - fo_FO (0x0438, Encoding.CP1252), - hi_IN (0x0439, Encoding.UNICODE), - mt_MT (0x043a, Encoding.UNICODE), - se_NO (0x043b, Encoding.CP1252), - ms_MY (0x043e, Encoding.CP1252), - kk_KZ (0x043f, Encoding.CP1251), - ky_KG (0x0440, Encoding.CP1251), - sw_KE (0x0441, Encoding.CP1252), - tk_TM (0x0442, Encoding.CP1250), - uz_Latn_UZ (0x0443, Encoding.CP1254), - tt_RU (0x0444, Encoding.CP1251), - bn_IN (0x0445, Encoding.UNICODE), - pa_IN (0x0446, Encoding.UNICODE), - gu_IN (0x0447, Encoding.UNICODE), - or_IN (0x0448, Encoding.UNICODE), - ta_IN (0x0449, Encoding.UNICODE), - te_IN (0x044a, Encoding.UNICODE), - kn_IN (0x044b, Encoding.UNICODE), - ml_IN (0x044c, Encoding.UNICODE), - as_IN (0x044d, Encoding.UNICODE), - mr_IN (0x044e, Encoding.UNICODE), - sa_IN (0x044f, Encoding.UNICODE), - mn_MN (0x0450, Encoding.CP1251), - bo_CN (0x0451, Encoding.UNICODE), - cy_GB (0x0452, Encoding.CP1252), - km_KH (0x0453, Encoding.UNICODE), - lo_LA (0x0454, Encoding.UNICODE), - gl_ES (0x0456, Encoding.CP1252), - kok_IN (0x0457, Encoding.UNICODE), - syr_SY (0x045a, Encoding.UNICODE), - si_LK (0x045b, Encoding.UNICODE), - iu_Cans_CA (0x045d, Encoding.CP1252), - am_ET (0x045e, Encoding.CP1252), - ne_NP (0x0461, Encoding.UNICODE), - fy_NL (0x0462, Encoding.CP1252), - ps_AF (0x0463, Encoding.UNICODE), - fil_PH (0x0464, Encoding.CP1252), - dv_MV (0x0465, Encoding.UNICODE), - ha_Latn_NG (0x0468, Encoding.CP1252), - yo_NG (0x046a, Encoding.CP1252), - quz_BO (0x046b, Encoding.CP1252), - nso_ZA (0x046c, Encoding.CP1252), - ba_RU (0x046d, Encoding.CP1251), - lb_LU (0x046e, Encoding.CP1252), - kl_GL (0x046f, Encoding.CP1252), - ig_NG (0x0470, Encoding.CP1252), - ii_CN (0x0478, Encoding.CP1252), - arn_CL (0x047a, Encoding.CP1252), - moh_CA (0x047c, Encoding.CP1252), - br_FR (0x047e, Encoding.CP1252), - ug_CN (0x0480, Encoding.CP1256), - mi_NZ (0x0481, Encoding.UNICODE), - oc_FR (0x0482, Encoding.CP1252), - co_FR (0x0483, Encoding.CP1252), - gsw_FR (0x0484, Encoding.CP1252), - sah_RU (0x0485, Encoding.CP1251), - qut_GT (0x0486, Encoding.CP1252), - rw_RW (0x0487, Encoding.CP1252), - wo_SN (0x0488, Encoding.CP1252), - prs_AF (0x048c, Encoding.CP1256), - ar_IQ (0x0801, Encoding.CP1256), - zh_CN (0x0804, Encoding.CP936), - de_CH (0x0807, Encoding.CP1252), - en_GB (0x0809, Encoding.CP1252), - es_MX (0x080a, Encoding.CP1252), - fr_BE (0x080c, Encoding.CP1252), - it_CH (0x0810, Encoding.CP1252), - nl_BE (0x0813, Encoding.CP1252), - nn_NO (0x0814, Encoding.CP1252), - pt_PT (0x0816, Encoding.CP1252), - sr_Latn_CS (0x081a, Encoding.CP1250), - sv_FI (0x081d, Encoding.CP1252), - Lithuanian_Classic (0x0827, Encoding.CP1257), - az_Cyrl_AZ (0x082c, Encoding.CP1251), - dsb_DE (0x082e, Encoding.CP1252), - se_SE (0x083b, Encoding.CP1252), - ga_IE (0x083c, Encoding.CP1252), - ms_BN (0x083e, Encoding.CP1252), - uz_Cyrl_UZ (0x0843, Encoding.CP1251), - bn_BD (0x0845, Encoding.UNICODE), - mn_Mong_CN (0x0850, Encoding.CP1251), - iu_Latn_CA (0x085d, Encoding.CP1252), - tzm_Latn_DZ (0x085f, Encoding.CP1252), - quz_EC (0x086b, Encoding.CP1252), - ar_EG (0x0c01, Encoding.CP1256), - zh_HK (0x0c04, Encoding.CP950), - de_AT (0x0c07, Encoding.CP1252), - en_AU (0x0c09, Encoding.CP1252), - es_ES (0x0c0a, Encoding.CP1252), - fr_CA (0x0c0c, Encoding.CP1252), - sr_Cyrl_CS (0x0c1a, Encoding.CP1251), - se_FI (0x0c3b, Encoding.CP1252), - quz_PE (0x0c6b, Encoding.CP1252), - ar_LY (0x1001, Encoding.CP1256), - zh_SG (0x1004, Encoding.CP936), - de_LU (0x1007, Encoding.CP1252), - en_CA (0x1009, Encoding.CP1252), - es_GT (0x100a, Encoding.CP1252), - fr_CH (0x100c, Encoding.CP1252), - hr_BA (0x101a, Encoding.CP1250), - smj_NO (0x103b, Encoding.CP1252), - ar_DZ (0x1401, Encoding.CP1256), - zh_MO (0x1404, Encoding.CP950), - de_LI (0x1407, Encoding.CP1252), - en_NZ (0x1409, Encoding.CP1252), - es_CR (0x140a, Encoding.CP1252), - fr_LU (0x140c, Encoding.CP1252), - bs_Latn_BA (0x141a, Encoding.CP1250), - smj_SE (0x143b, Encoding.CP1252), - ar_MA (0x1801, Encoding.CP1256), - en_IE (0x1809, Encoding.CP1252), - es_PA (0x180a, Encoding.CP1252), - fr_MC (0x180c, Encoding.CP1252), - sr_Latn_BA (0x181a, Encoding.CP1250), - sma_NO (0x183b, Encoding.CP1252), - ar_TN (0x1c01, Encoding.CP1256), - en_ZA (0x1c09, Encoding.CP1252), - es_DO (0x1c0a, Encoding.CP1252), - sr_Cyrl_BA (0x1c1a, Encoding.CP1251), - sma_SB (0x1c3b, Encoding.CP1252), - ar_OM (0x2001, Encoding.CP1256), - en_JM (0x2009, Encoding.CP1252), - es_VE (0x200a, Encoding.CP1252), - bs_Cyrl_BA (0x201a, Encoding.CP1251), - sms_FI (0x203b, Encoding.CP1252), - ar_YE (0x2401, Encoding.CP1256), - en_CB (0x2409, Encoding.CP1252), - es_CO (0x240a, Encoding.CP1252), - smn_FI (0x243b, Encoding.CP1252), - ar_SY (0x2801, Encoding.CP1256), - en_BZ (0x2809, Encoding.CP1252), - es_PE (0x280a, Encoding.CP1252), - ar_JO (0x2c01, Encoding.CP1256), - en_TT (0x2c09, Encoding.CP1252), - es_AR (0x2c0a, Encoding.CP1252), - ar_LB (0x3001, Encoding.CP1256), - en_ZW (0x3009, Encoding.CP1252), - es_EC (0x300a, Encoding.CP1252), - ar_KW (0x3401, Encoding.CP1256), - en_PH (0x3409, Encoding.CP1252), - es_CL (0x340a, Encoding.CP1252), - ar_AE (0x3801, Encoding.CP1256), - es_UY (0x380a, Encoding.CP1252), - ar_BH (0x3c01, Encoding.CP1256), - es_PY (0x3c0a, Encoding.CP1252), - ar_QA (0x4001, Encoding.CP1256), - en_IN (0x4009, Encoding.CP1252), - es_BO (0x400a, Encoding.CP1252), - en_MY (0x4409, Encoding.CP1252), - es_SV (0x440a, Encoding.CP1252), - en_SG (0x4809, Encoding.CP1252), - es_HN (0x480a, Encoding.CP1252), - es_NI (0x4c0a, Encoding.CP1252), - es_PR (0x500a, Encoding.CP1252), - es_US (0x540a, Encoding.CP1252); + enum WindowsLocale { + ar_SA(0x0401, Encoding.CP1256), + bg_BG(0x0402, Encoding.CP1251), + ca_ES(0x0403, Encoding.CP1252), + zh_TW(0x0404, Encoding.CP950), + cs_CZ(0x0405, Encoding.CP1250), + da_DK(0x0406, Encoding.CP1252), + de_DE(0x0407, Encoding.CP1252), + el_GR(0x0408, Encoding.CP1253), + en_US(0x0409, Encoding.CP1252), + es_ES_tradnl(0x040a, Encoding.CP1252), + fi_FI(0x040b, Encoding.CP1252), + fr_FR(0x040c, Encoding.CP1252), + he_IL(0x040d, Encoding.CP1255), + hu_HU(0x040e, Encoding.CP1250), + is_IS(0x040f, Encoding.CP1252), + it_IT(0x0410, Encoding.CP1252), + ja_JP(0x0411, Encoding.CP932), + ko_KR(0x0412, Encoding.CP949), + nl_NL(0x0413, Encoding.CP1252), + nb_NO(0x0414, Encoding.CP1252), + pl_PL(0x0415, Encoding.CP1250), + pt_BR(0x0416, Encoding.CP1252), + rm_CH(0x0417, Encoding.CP1252), + ro_RO(0x0418, Encoding.CP1250), + ru_RU(0x0419, Encoding.CP1251), + hr_HR(0x041a, Encoding.CP1250), + sk_SK(0x041b, Encoding.CP1250), + sq_AL(0x041c, Encoding.CP1250), + sv_SE(0x041d, Encoding.CP1252), + th_TH(0x041e, Encoding.CP874), + tr_TR(0x041f, Encoding.CP1254), + ur_PK(0x0420, Encoding.CP1256), + id_ID(0x0421, Encoding.CP1252), + uk_UA(0x0422, Encoding.CP1251), + be_BY(0x0423, Encoding.CP1251), + sl_SI(0x0424, Encoding.CP1250), + et_EE(0x0425, Encoding.CP1257), + lv_LV(0x0426, Encoding.CP1257), + lt_LT(0x0427, Encoding.CP1257), + tg_Cyrl_TJ(0x0428, Encoding.CP1251), + fa_IR(0x0429, Encoding.CP1256), + vi_VN(0x042a, Encoding.CP1258), + hy_AM(0x042b, Encoding.CP1252), + az_Latn_AZ(0x042c, Encoding.CP1254), + eu_ES(0x042d, Encoding.CP1252), + wen_DE(0x042e, Encoding.CP1252), + mk_MK(0x042f, Encoding.CP1251), + tn_ZA(0x0432, Encoding.CP1252), + xh_ZA(0x0434, Encoding.CP1252), + zu_ZA(0x0435, Encoding.CP1252), + Af_ZA(0x0436, Encoding.CP1252), + ka_GE(0x0437, Encoding.CP1252), + fo_FO(0x0438, Encoding.CP1252), + hi_IN(0x0439, Encoding.UNICODE), + mt_MT(0x043a, Encoding.UNICODE), + se_NO(0x043b, Encoding.CP1252), + ms_MY(0x043e, Encoding.CP1252), + kk_KZ(0x043f, Encoding.CP1251), + ky_KG(0x0440, Encoding.CP1251), + sw_KE(0x0441, Encoding.CP1252), + tk_TM(0x0442, Encoding.CP1250), + uz_Latn_UZ(0x0443, Encoding.CP1254), + tt_RU(0x0444, Encoding.CP1251), + bn_IN(0x0445, Encoding.UNICODE), + pa_IN(0x0446, Encoding.UNICODE), + gu_IN(0x0447, Encoding.UNICODE), + or_IN(0x0448, Encoding.UNICODE), + ta_IN(0x0449, Encoding.UNICODE), + te_IN(0x044a, Encoding.UNICODE), + kn_IN(0x044b, Encoding.UNICODE), + ml_IN(0x044c, Encoding.UNICODE), + as_IN(0x044d, Encoding.UNICODE), + mr_IN(0x044e, Encoding.UNICODE), + sa_IN(0x044f, Encoding.UNICODE), + mn_MN(0x0450, Encoding.CP1251), + bo_CN(0x0451, Encoding.UNICODE), + cy_GB(0x0452, Encoding.CP1252), + km_KH(0x0453, Encoding.UNICODE), + lo_LA(0x0454, Encoding.UNICODE), + gl_ES(0x0456, Encoding.CP1252), + kok_IN(0x0457, Encoding.UNICODE), + syr_SY(0x045a, Encoding.UNICODE), + si_LK(0x045b, Encoding.UNICODE), + iu_Cans_CA(0x045d, Encoding.CP1252), + am_ET(0x045e, Encoding.CP1252), + ne_NP(0x0461, Encoding.UNICODE), + fy_NL(0x0462, Encoding.CP1252), + ps_AF(0x0463, Encoding.UNICODE), + fil_PH(0x0464, Encoding.CP1252), + dv_MV(0x0465, Encoding.UNICODE), + ha_Latn_NG(0x0468, Encoding.CP1252), + yo_NG(0x046a, Encoding.CP1252), + quz_BO(0x046b, Encoding.CP1252), + nso_ZA(0x046c, Encoding.CP1252), + ba_RU(0x046d, Encoding.CP1251), + lb_LU(0x046e, Encoding.CP1252), + kl_GL(0x046f, Encoding.CP1252), + ig_NG(0x0470, Encoding.CP1252), + ii_CN(0x0478, Encoding.CP1252), + arn_CL(0x047a, Encoding.CP1252), + moh_CA(0x047c, Encoding.CP1252), + br_FR(0x047e, Encoding.CP1252), + ug_CN(0x0480, Encoding.CP1256), + mi_NZ(0x0481, Encoding.UNICODE), + oc_FR(0x0482, Encoding.CP1252), + co_FR(0x0483, Encoding.CP1252), + gsw_FR(0x0484, Encoding.CP1252), + sah_RU(0x0485, Encoding.CP1251), + qut_GT(0x0486, Encoding.CP1252), + rw_RW(0x0487, Encoding.CP1252), + wo_SN(0x0488, Encoding.CP1252), + prs_AF(0x048c, Encoding.CP1256), + ar_IQ(0x0801, Encoding.CP1256), + zh_CN(0x0804, Encoding.CP936), + de_CH(0x0807, Encoding.CP1252), + en_GB(0x0809, Encoding.CP1252), + es_MX(0x080a, Encoding.CP1252), + fr_BE(0x080c, Encoding.CP1252), + it_CH(0x0810, Encoding.CP1252), + nl_BE(0x0813, Encoding.CP1252), + nn_NO(0x0814, Encoding.CP1252), + pt_PT(0x0816, Encoding.CP1252), + sr_Latn_CS(0x081a, Encoding.CP1250), + sv_FI(0x081d, Encoding.CP1252), + Lithuanian_Classic(0x0827, Encoding.CP1257), + az_Cyrl_AZ(0x082c, Encoding.CP1251), + dsb_DE(0x082e, Encoding.CP1252), + se_SE(0x083b, Encoding.CP1252), + ga_IE(0x083c, Encoding.CP1252), + ms_BN(0x083e, Encoding.CP1252), + uz_Cyrl_UZ(0x0843, Encoding.CP1251), + bn_BD(0x0845, Encoding.UNICODE), + mn_Mong_CN(0x0850, Encoding.CP1251), + iu_Latn_CA(0x085d, Encoding.CP1252), + tzm_Latn_DZ(0x085f, Encoding.CP1252), + quz_EC(0x086b, Encoding.CP1252), + ar_EG(0x0c01, Encoding.CP1256), + zh_HK(0x0c04, Encoding.CP950), + de_AT(0x0c07, Encoding.CP1252), + en_AU(0x0c09, Encoding.CP1252), + es_ES(0x0c0a, Encoding.CP1252), + fr_CA(0x0c0c, Encoding.CP1252), + sr_Cyrl_CS(0x0c1a, Encoding.CP1251), + se_FI(0x0c3b, Encoding.CP1252), + quz_PE(0x0c6b, Encoding.CP1252), + ar_LY(0x1001, Encoding.CP1256), + zh_SG(0x1004, Encoding.CP936), + de_LU(0x1007, Encoding.CP1252), + en_CA(0x1009, Encoding.CP1252), + es_GT(0x100a, Encoding.CP1252), + fr_CH(0x100c, Encoding.CP1252), + hr_BA(0x101a, Encoding.CP1250), + smj_NO(0x103b, Encoding.CP1252), + ar_DZ(0x1401, Encoding.CP1256), + zh_MO(0x1404, Encoding.CP950), + de_LI(0x1407, Encoding.CP1252), + en_NZ(0x1409, Encoding.CP1252), + es_CR(0x140a, Encoding.CP1252), + fr_LU(0x140c, Encoding.CP1252), + bs_Latn_BA(0x141a, Encoding.CP1250), + smj_SE(0x143b, Encoding.CP1252), + ar_MA(0x1801, Encoding.CP1256), + en_IE(0x1809, Encoding.CP1252), + es_PA(0x180a, Encoding.CP1252), + fr_MC(0x180c, Encoding.CP1252), + sr_Latn_BA(0x181a, Encoding.CP1250), + sma_NO(0x183b, Encoding.CP1252), + ar_TN(0x1c01, Encoding.CP1256), + en_ZA(0x1c09, Encoding.CP1252), + es_DO(0x1c0a, Encoding.CP1252), + sr_Cyrl_BA(0x1c1a, Encoding.CP1251), + sma_SB(0x1c3b, Encoding.CP1252), + ar_OM(0x2001, Encoding.CP1256), + en_JM(0x2009, Encoding.CP1252), + es_VE(0x200a, Encoding.CP1252), + bs_Cyrl_BA(0x201a, Encoding.CP1251), + sms_FI(0x203b, Encoding.CP1252), + ar_YE(0x2401, Encoding.CP1256), + en_CB(0x2409, Encoding.CP1252), + es_CO(0x240a, Encoding.CP1252), + smn_FI(0x243b, Encoding.CP1252), + ar_SY(0x2801, Encoding.CP1256), + en_BZ(0x2809, Encoding.CP1252), + es_PE(0x280a, Encoding.CP1252), + ar_JO(0x2c01, Encoding.CP1256), + en_TT(0x2c09, Encoding.CP1252), + es_AR(0x2c0a, Encoding.CP1252), + ar_LB(0x3001, Encoding.CP1256), + en_ZW(0x3009, Encoding.CP1252), + es_EC(0x300a, Encoding.CP1252), + ar_KW(0x3401, Encoding.CP1256), + en_PH(0x3409, Encoding.CP1252), + es_CL(0x340a, Encoding.CP1252), + ar_AE(0x3801, Encoding.CP1256), + es_UY(0x380a, Encoding.CP1252), + ar_BH(0x3c01, Encoding.CP1256), + es_PY(0x3c0a, Encoding.CP1252), + ar_QA(0x4001, Encoding.CP1256), + en_IN(0x4009, Encoding.CP1252), + es_BO(0x400a, Encoding.CP1252), + en_MY(0x4409, Encoding.CP1252), + es_SV(0x440a, Encoding.CP1252), + en_SG(0x4809, Encoding.CP1252), + es_HN(0x480a, Encoding.CP1252), + es_NI(0x4c0a, Encoding.CP1252), + es_PR(0x500a, Encoding.CP1252), + es_US(0x540a, Encoding.CP1252); private final int langID; private final Encoding encoding; - WindowsLocale(int langID, - Encoding encoding) { + WindowsLocale(int langID, Encoding encoding) { this.langID = langID; this.encoding = encoding; } @@ -356,8 +357,7 @@ private Encoding encodingFromLCID() throws UnsupportedEncodingException { try { return locale.getEncoding(); - } - catch (UnsupportedEncodingException inner) { + } catch (UnsupportedEncodingException inner) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_unknownLCID")); Object[] msgArgs = {locale}; UnsupportedEncodingException e = new UnsupportedEncodingException(form.format(msgArgs)); @@ -369,130 +369,129 @@ private Encoding encodingFromLCID() throws UnsupportedEncodingException { /** * Enumeration of original SQL Server sort orders recognized by SQL Server. * - * If SQL collation has a non-zero sortId, then use this enum to determine the encoding. From sql_main\sql\common\src\sqlscol.cpp (SQLServer code - * base). + * If SQL collation has a non-zero sortId, then use this enum to determine the encoding. From + * sql_main\sql\common\src\sqlscol.cpp (SQLServer code base). */ - enum SortOrder - { - BIN_CP437 (30, "SQL_Latin1_General_CP437_BIN", Encoding.CP437), - DICTIONARY_437 (31, "SQL_Latin1_General_CP437_CS_AS", Encoding.CP437), - NOCASE_437 (32, "SQL_Latin1_General_CP437_CI_AS", Encoding.CP437), - NOCASEPREF_437 (33, "SQL_Latin1_General_Pref_CP437_CI_AS", Encoding.CP437), - NOACCENTS_437 (34, "SQL_Latin1_General_CP437_CI_AI", Encoding.CP437), - BIN2_CP437 (35, "SQL_Latin1_General_CP437_BIN2", Encoding.CP437), - - BIN_CP850 (40, "SQL_Latin1_General_CP850_BIN", Encoding.CP850), - DICTIONARY_850 (41, "SQL_Latin1_General_CP850_CS_AS", Encoding.CP850), - NOCASE_850 (42, "SQL_Latin1_General_CP850_CI_AS", Encoding.CP850), - NOCASEPREF_850 (43, "SQL_Latin1_General_Pref_CP850_CI_AS", Encoding.CP850), - NOACCENTS_850 (44, "SQL_Latin1_General_CP850_CI_AI", Encoding.CP850), - BIN2_CP850 (45, "SQL_Latin1_General_CP850_BIN2", Encoding.CP850), - - CASELESS_34 (49, "SQL_1xCompat_CP850_CI_AS", Encoding.CP850), - BIN_ISO_1 (50, "bin_iso_1", Encoding.CP1252), - DICTIONARY_ISO (51, "SQL_Latin1_General_CP1_CS_AS", Encoding.CP1252), - NOCASE_ISO (52, "SQL_Latin1_General_CP1_CI_AS", Encoding.CP1252), - NOCASEPREF_ISO (53, "SQL_Latin1_General_Pref_CP1_CI_AS", Encoding.CP1252), - NOACCENTS_ISO (54, "SQL_Latin1_General_CP1_CI_AI", Encoding.CP1252), - ALT_DICTIONARY (55, "SQL_AltDiction_CP850_CS_AS", Encoding.CP850), - ALT_NOCASEPREF (56, "SQL_AltDiction_Pref_CP850_CI_AS", Encoding.CP850), - ALT_NOACCENTS (57, "SQL_AltDiction_CP850_CI_AI", Encoding.CP850), - SCAND_NOCASEPREF (58, "SQL_Scandinavian_Pref_CP850_CI_AS", Encoding.CP850), - SCAND_DICTIONARY (59, "SQL_Scandinavian_CP850_CS_AS", Encoding.CP850), - SCAND_NOCASE (60, "SQL_Scandinavian_CP850_CI_AS", Encoding.CP850), - ALT_NOCASE (61, "SQL_AltDiction_CP850_CI_AS", Encoding.CP850), - - DICTIONARY_1252 (71, "dictionary_1252", Encoding.CP1252), - NOCASE_1252 (72, "nocase_1252", Encoding.CP1252), - DNK_NOR_DICTIONARY (73, "dnk_nor_dictionary", Encoding.CP1252), - FIN_SWE_DICTIONARY (74, "fin_swe_dictionary", Encoding.CP1252), - ISL_DICTIONARY (75, "isl_dictionary", Encoding.CP1252), - - BIN_CP1250 (80, "bin_cp1250", Encoding.CP1250), - DICTIONARY_1250 (81, "SQL_Latin1_General_CP1250_CS_AS", Encoding.CP1250), - NOCASE_1250 (82, "SQL_Latin1_General_CP1250_CI_AS", Encoding.CP1250), - CSYDIC (83, "SQL_Czech_CP1250_CS_AS", Encoding.CP1250), - CSYNC (84, "SQL_Czech_CP1250_CI_AS", Encoding.CP1250), - HUNDIC (85, "SQL_Hungarian_CP1250_CS_AS", Encoding.CP1250), - HUNNC (86, "SQL_Hungarian_CP1250_CI_AS", Encoding.CP1250), - PLKDIC (87, "SQL_Polish_CP1250_CS_AS", Encoding.CP1250), - PLKNC (88, "SQL_Polish_CP1250_CI_AS", Encoding.CP1250), - ROMDIC (89, "SQL_Romanian_CP1250_CS_AS", Encoding.CP1250), - ROMNC (90, "SQL_Romanian_CP1250_CI_AS", Encoding.CP1250), - SHLDIC (91, "SQL_Croatian_CP1250_CS_AS", Encoding.CP1250), - SHLNC (92, "SQL_Croatian_CP1250_CI_AS", Encoding.CP1250), - SKYDIC (93, "SQL_Slovak_CP1250_CS_AS", Encoding.CP1250), - SKYNC (94, "SQL_Slovak_CP1250_CI_AS", Encoding.CP1250), - SLVDIC (95, "SQL_Slovenian_CP1250_CS_AS", Encoding.CP1250), - SLVNC (96, "SQL_Slovenian_CP1250_CI_AS", Encoding.CP1250), - POLISH_CS (97, "polish_cs", Encoding.CP1250), - POLISH_CI (98, "polish_ci", Encoding.CP1250), - - BIN_CP1251 (104, "bin_cp1251", Encoding.CP1251), - DICTIONARY_1251 (105, "SQL_Latin1_General_CP1251_CS_AS", Encoding.CP1251), - NOCASE_1251 (106, "SQL_Latin1_General_CP1251_CI_AS", Encoding.CP1251), - UKRDIC (107, "SQL_Ukrainian_CP1251_CS_AS", Encoding.CP1251), - UKRNC (108, "SQL_Ukrainian_CP1251_CI_AS", Encoding.CP1251), - - BIN_CP1253 (112, "bin_cp1253", Encoding.CP1253), - DICTIONARY_1253 (113, "SQL_Latin1_General_CP1253_CS_AS", Encoding.CP1253), - NOCASE_1253 (114, "SQL_Latin1_General_CP1253_CI_AS", Encoding.CP1253), - - GREEK_MIXEDDICTIONARY (120, "SQL_MixDiction_CP1253_CS_AS", Encoding.CP1253), - GREEK_ALTDICTIONARY (121, "SQL_AltDiction_CP1253_CS_AS", Encoding.CP1253), - GREEK_ALTDICTIONARY2 (122, "SQL_AltDiction2_CP1253_CS_AS", Encoding.CP1253), - GREEK_NOCASEDICT (124, "SQL_Latin1_General_CP1253_CI_AI", Encoding.CP1253), - BIN_CP1254 (128, "bin_cp1254", Encoding.CP1254), - DICTIONARY_1254 (129, "SQL_Latin1_General_CP1254_CS_AS", Encoding.CP1254), - NOCASE_1254 (130, "SQL_Latin1_General_CP1254_CI_AS", Encoding.CP1254), - - BIN_CP1255 (136, "bin_cp1255", Encoding.CP1255), - DICTIONARY_1255 (137, "SQL_Latin1_General_CP1255_CS_AS", Encoding.CP1255), - NOCASE_1255 (138, "SQL_Latin1_General_CP1255_CI_AS", Encoding.CP1255), - - BIN_CP1256 (144, "bin_cp1256", Encoding.CP1256), - DICTIONARY_1256 (145, "SQL_Latin1_General_CP1256_CS_AS", Encoding.CP1256), - NOCASE_1256 (146, "SQL_Latin1_General_CP1256_CI_AS", Encoding.CP1256), - - BIN_CP1257 (152, "bin_cp1257", Encoding.CP1257), - DICTIONARY_1257 (153, "SQL_Latin1_General_CP1257_CS_AS", Encoding.CP1257), - NOCASE_1257 (154, "SQL_Latin1_General_CP1257_CI_AS", Encoding.CP1257), - ETIDIC (155, "SQL_Estonian_CP1257_CS_AS", Encoding.CP1257), - ETINC (156, "SQL_Estonian_CP1257_CI_AS", Encoding.CP1257), - LVIDIC (157, "SQL_Latvian_CP1257_CS_AS", Encoding.CP1257), - LVINC (158, "SQL_Latvian_CP1257_CI_AS", Encoding.CP1257), - LTHDIC (159, "SQL_Lithuanian_CP1257_CS_AS", Encoding.CP1257), - LTHNC (160, "SQL_Lithuanian_CP1257_CI_AS", Encoding.CP1257), - - DANNO_NOCASEPREF (183, "SQL_Danish_Pref_CP1_CI_AS", Encoding.CP1252), - SVFI1_NOCASEPREF (184, "SQL_SwedishPhone_Pref_CP1_CI_AS", Encoding.CP1252), - SVFI2_NOCASEPREF (185, "SQL_SwedishStd_Pref_CP1_CI_AS", Encoding.CP1252), - ISLAN_NOCASEPREF (186, "SQL_Icelandic_Pref_CP1_CI_AS", Encoding.CP1252), - - BIN_CP932 (192, "bin_cp932", Encoding.CP932), - NLS_CP932 (193, "nls_cp932", Encoding.CP932), - BIN_CP949 (194, "bin_cp949", Encoding.CP949), - NLS_CP949 (195, "nls_cp949", Encoding.CP949), - BIN_CP950 (196, "bin_cp950", Encoding.CP950), - NLS_CP950 (197, "nls_cp950", Encoding.CP950), - BIN_CP936 (198, "bin_cp936", Encoding.CP936), - NLS_CP936 (199, "nls_cp936", Encoding.CP936), - NLS_CP932_CS (200, "nls_cp932_cs", Encoding.CP932), - NLS_CP949_CS (201, "nls_cp949_cs", Encoding.CP949), - NLS_CP950_CS (202, "nls_cp950_cs", Encoding.CP950), - NLS_CP936_CS (203, "nls_cp936_cs", Encoding.CP936), - BIN_CP874 (204, "bin_cp874", Encoding.CP874), - NLS_CP874 (205, "nls_cp874", Encoding.CP874), - NLS_CP874_CS (206, "nls_cp874_cs", Encoding.CP874), - - EBCDIC_037 (210, "SQL_EBCDIC037_CP1_CS_AS", Encoding.CP1252), - EBCDIC_273 (211, "SQL_EBCDIC273_CP1_CS_AS", Encoding.CP1252), - EBCDIC_277 (212, "SQL_EBCDIC277_CP1_CS_AS", Encoding.CP1252), - EBCDIC_278 (213, "SQL_EBCDIC278_CP1_CS_AS", Encoding.CP1252), - EBCDIC_280 (214, "SQL_EBCDIC280_CP1_CS_AS", Encoding.CP1252), - EBCDIC_284 (215, "SQL_EBCDIC284_CP1_CS_AS", Encoding.CP1252), - EBCDIC_285 (216, "SQL_EBCDIC285_CP1_CS_AS", Encoding.CP1252), - EBCDIC_297 (217, "SQL_EBCDIC297_CP1_CS_AS", Encoding.CP1252); + enum SortOrder { + BIN_CP437(30, "SQL_Latin1_General_CP437_BIN", Encoding.CP437), + DICTIONARY_437(31, "SQL_Latin1_General_CP437_CS_AS", Encoding.CP437), + NOCASE_437(32, "SQL_Latin1_General_CP437_CI_AS", Encoding.CP437), + NOCASEPREF_437(33, "SQL_Latin1_General_Pref_CP437_CI_AS", Encoding.CP437), + NOACCENTS_437(34, "SQL_Latin1_General_CP437_CI_AI", Encoding.CP437), + BIN2_CP437(35, "SQL_Latin1_General_CP437_BIN2", Encoding.CP437), + + BIN_CP850(40, "SQL_Latin1_General_CP850_BIN", Encoding.CP850), + DICTIONARY_850(41, "SQL_Latin1_General_CP850_CS_AS", Encoding.CP850), + NOCASE_850(42, "SQL_Latin1_General_CP850_CI_AS", Encoding.CP850), + NOCASEPREF_850(43, "SQL_Latin1_General_Pref_CP850_CI_AS", Encoding.CP850), + NOACCENTS_850(44, "SQL_Latin1_General_CP850_CI_AI", Encoding.CP850), + BIN2_CP850(45, "SQL_Latin1_General_CP850_BIN2", Encoding.CP850), + + CASELESS_34(49, "SQL_1xCompat_CP850_CI_AS", Encoding.CP850), + BIN_ISO_1(50, "bin_iso_1", Encoding.CP1252), + DICTIONARY_ISO(51, "SQL_Latin1_General_CP1_CS_AS", Encoding.CP1252), + NOCASE_ISO(52, "SQL_Latin1_General_CP1_CI_AS", Encoding.CP1252), + NOCASEPREF_ISO(53, "SQL_Latin1_General_Pref_CP1_CI_AS", Encoding.CP1252), + NOACCENTS_ISO(54, "SQL_Latin1_General_CP1_CI_AI", Encoding.CP1252), + ALT_DICTIONARY(55, "SQL_AltDiction_CP850_CS_AS", Encoding.CP850), + ALT_NOCASEPREF(56, "SQL_AltDiction_Pref_CP850_CI_AS", Encoding.CP850), + ALT_NOACCENTS(57, "SQL_AltDiction_CP850_CI_AI", Encoding.CP850), + SCAND_NOCASEPREF(58, "SQL_Scandinavian_Pref_CP850_CI_AS", Encoding.CP850), + SCAND_DICTIONARY(59, "SQL_Scandinavian_CP850_CS_AS", Encoding.CP850), + SCAND_NOCASE(60, "SQL_Scandinavian_CP850_CI_AS", Encoding.CP850), + ALT_NOCASE(61, "SQL_AltDiction_CP850_CI_AS", Encoding.CP850), + + DICTIONARY_1252(71, "dictionary_1252", Encoding.CP1252), + NOCASE_1252(72, "nocase_1252", Encoding.CP1252), + DNK_NOR_DICTIONARY(73, "dnk_nor_dictionary", Encoding.CP1252), + FIN_SWE_DICTIONARY(74, "fin_swe_dictionary", Encoding.CP1252), + ISL_DICTIONARY(75, "isl_dictionary", Encoding.CP1252), + + BIN_CP1250(80, "bin_cp1250", Encoding.CP1250), + DICTIONARY_1250(81, "SQL_Latin1_General_CP1250_CS_AS", Encoding.CP1250), + NOCASE_1250(82, "SQL_Latin1_General_CP1250_CI_AS", Encoding.CP1250), + CSYDIC(83, "SQL_Czech_CP1250_CS_AS", Encoding.CP1250), + CSYNC(84, "SQL_Czech_CP1250_CI_AS", Encoding.CP1250), + HUNDIC(85, "SQL_Hungarian_CP1250_CS_AS", Encoding.CP1250), + HUNNC(86, "SQL_Hungarian_CP1250_CI_AS", Encoding.CP1250), + PLKDIC(87, "SQL_Polish_CP1250_CS_AS", Encoding.CP1250), + PLKNC(88, "SQL_Polish_CP1250_CI_AS", Encoding.CP1250), + ROMDIC(89, "SQL_Romanian_CP1250_CS_AS", Encoding.CP1250), + ROMNC(90, "SQL_Romanian_CP1250_CI_AS", Encoding.CP1250), + SHLDIC(91, "SQL_Croatian_CP1250_CS_AS", Encoding.CP1250), + SHLNC(92, "SQL_Croatian_CP1250_CI_AS", Encoding.CP1250), + SKYDIC(93, "SQL_Slovak_CP1250_CS_AS", Encoding.CP1250), + SKYNC(94, "SQL_Slovak_CP1250_CI_AS", Encoding.CP1250), + SLVDIC(95, "SQL_Slovenian_CP1250_CS_AS", Encoding.CP1250), + SLVNC(96, "SQL_Slovenian_CP1250_CI_AS", Encoding.CP1250), + POLISH_CS(97, "polish_cs", Encoding.CP1250), + POLISH_CI(98, "polish_ci", Encoding.CP1250), + + BIN_CP1251(104, "bin_cp1251", Encoding.CP1251), + DICTIONARY_1251(105, "SQL_Latin1_General_CP1251_CS_AS", Encoding.CP1251), + NOCASE_1251(106, "SQL_Latin1_General_CP1251_CI_AS", Encoding.CP1251), + UKRDIC(107, "SQL_Ukrainian_CP1251_CS_AS", Encoding.CP1251), + UKRNC(108, "SQL_Ukrainian_CP1251_CI_AS", Encoding.CP1251), + + BIN_CP1253(112, "bin_cp1253", Encoding.CP1253), + DICTIONARY_1253(113, "SQL_Latin1_General_CP1253_CS_AS", Encoding.CP1253), + NOCASE_1253(114, "SQL_Latin1_General_CP1253_CI_AS", Encoding.CP1253), + + GREEK_MIXEDDICTIONARY(120, "SQL_MixDiction_CP1253_CS_AS", Encoding.CP1253), + GREEK_ALTDICTIONARY(121, "SQL_AltDiction_CP1253_CS_AS", Encoding.CP1253), + GREEK_ALTDICTIONARY2(122, "SQL_AltDiction2_CP1253_CS_AS", Encoding.CP1253), + GREEK_NOCASEDICT(124, "SQL_Latin1_General_CP1253_CI_AI", Encoding.CP1253), + BIN_CP1254(128, "bin_cp1254", Encoding.CP1254), + DICTIONARY_1254(129, "SQL_Latin1_General_CP1254_CS_AS", Encoding.CP1254), + NOCASE_1254(130, "SQL_Latin1_General_CP1254_CI_AS", Encoding.CP1254), + + BIN_CP1255(136, "bin_cp1255", Encoding.CP1255), + DICTIONARY_1255(137, "SQL_Latin1_General_CP1255_CS_AS", Encoding.CP1255), + NOCASE_1255(138, "SQL_Latin1_General_CP1255_CI_AS", Encoding.CP1255), + + BIN_CP1256(144, "bin_cp1256", Encoding.CP1256), + DICTIONARY_1256(145, "SQL_Latin1_General_CP1256_CS_AS", Encoding.CP1256), + NOCASE_1256(146, "SQL_Latin1_General_CP1256_CI_AS", Encoding.CP1256), + + BIN_CP1257(152, "bin_cp1257", Encoding.CP1257), + DICTIONARY_1257(153, "SQL_Latin1_General_CP1257_CS_AS", Encoding.CP1257), + NOCASE_1257(154, "SQL_Latin1_General_CP1257_CI_AS", Encoding.CP1257), + ETIDIC(155, "SQL_Estonian_CP1257_CS_AS", Encoding.CP1257), + ETINC(156, "SQL_Estonian_CP1257_CI_AS", Encoding.CP1257), + LVIDIC(157, "SQL_Latvian_CP1257_CS_AS", Encoding.CP1257), + LVINC(158, "SQL_Latvian_CP1257_CI_AS", Encoding.CP1257), + LTHDIC(159, "SQL_Lithuanian_CP1257_CS_AS", Encoding.CP1257), + LTHNC(160, "SQL_Lithuanian_CP1257_CI_AS", Encoding.CP1257), + + DANNO_NOCASEPREF(183, "SQL_Danish_Pref_CP1_CI_AS", Encoding.CP1252), + SVFI1_NOCASEPREF(184, "SQL_SwedishPhone_Pref_CP1_CI_AS", Encoding.CP1252), + SVFI2_NOCASEPREF(185, "SQL_SwedishStd_Pref_CP1_CI_AS", Encoding.CP1252), + ISLAN_NOCASEPREF(186, "SQL_Icelandic_Pref_CP1_CI_AS", Encoding.CP1252), + + BIN_CP932(192, "bin_cp932", Encoding.CP932), + NLS_CP932(193, "nls_cp932", Encoding.CP932), + BIN_CP949(194, "bin_cp949", Encoding.CP949), + NLS_CP949(195, "nls_cp949", Encoding.CP949), + BIN_CP950(196, "bin_cp950", Encoding.CP950), + NLS_CP950(197, "nls_cp950", Encoding.CP950), + BIN_CP936(198, "bin_cp936", Encoding.CP936), + NLS_CP936(199, "nls_cp936", Encoding.CP936), + NLS_CP932_CS(200, "nls_cp932_cs", Encoding.CP932), + NLS_CP949_CS(201, "nls_cp949_cs", Encoding.CP949), + NLS_CP950_CS(202, "nls_cp950_cs", Encoding.CP950), + NLS_CP936_CS(203, "nls_cp936_cs", Encoding.CP936), + BIN_CP874(204, "bin_cp874", Encoding.CP874), + NLS_CP874(205, "nls_cp874", Encoding.CP874), + NLS_CP874_CS(206, "nls_cp874_cs", Encoding.CP874), + + EBCDIC_037(210, "SQL_EBCDIC037_CP1_CS_AS", Encoding.CP1252), + EBCDIC_273(211, "SQL_EBCDIC273_CP1_CS_AS", Encoding.CP1252), + EBCDIC_277(212, "SQL_EBCDIC277_CP1_CS_AS", Encoding.CP1252), + EBCDIC_278(213, "SQL_EBCDIC278_CP1_CS_AS", Encoding.CP1252), + EBCDIC_280(214, "SQL_EBCDIC280_CP1_CS_AS", Encoding.CP1252), + EBCDIC_284(215, "SQL_EBCDIC284_CP1_CS_AS", Encoding.CP1252), + EBCDIC_285(216, "SQL_EBCDIC285_CP1_CS_AS", Encoding.CP1252), + EBCDIC_297(217, "SQL_EBCDIC297_CP1_CS_AS", Encoding.CP1252); private final int sortId; private final String name; @@ -502,9 +501,7 @@ final Encoding getEncoding() throws UnsupportedEncodingException { return encoding.checkSupported(); } - SortOrder(int sortId, - String name, - Encoding encoding) { + SortOrder(int sortId, String name, Encoding encoding) { this.sortId = sortId; this.name = name; this.encoding = encoding; @@ -528,8 +525,7 @@ private Encoding encodingFromSortId() throws UnsupportedEncodingException { try { return sortOrder.getEncoding(); - } - catch (UnsupportedEncodingException inner) { + } catch (UnsupportedEncodingException inner) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_unknownSortId")); Object[] msgArgs = {sortOrder}; UnsupportedEncodingException e = new UnsupportedEncodingException(form.format(msgArgs)); @@ -551,32 +547,32 @@ private Encoding encodingFromSortId() throws UnsupportedEncodingException { } } + /** * Enumeration of encodings that are supported by SQL Server (and hopefully the JVM). * - * See, for example, https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html for a complete list of supported encodings with - * their canonical names. + * See, for example, https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html for a complete list + * of supported encodings with their canonical names. */ -enum Encoding -{ - UNICODE ("UTF-16LE", true, false), - UTF8 ("UTF-8", true, false), - CP437 ("Cp437", false, false), - CP850 ("Cp850", false, false), - CP874 ("MS874", true, true), - CP932 ("MS932", true, false), - CP936 ("MS936", true, false), - CP949 ("MS949", true, false), - CP950 ("MS950", true, false), - CP1250 ("Cp1250", true, true), - CP1251 ("Cp1251", true, true), - CP1252 ("Cp1252", true, true), - CP1253 ("Cp1253", true, true), - CP1254 ("Cp1254", true, true), - CP1255 ("Cp1255", true, true), - CP1256 ("Cp1256", true, true), - CP1257 ("Cp1257", true, true), - CP1258 ("Cp1258", true, true); +enum Encoding { + UNICODE("UTF-16LE", true, false), + UTF8("UTF-8", true, false), + CP437("Cp437", false, false), + CP850("Cp850", false, false), + CP874("MS874", true, true), + CP932("MS932", true, false), + CP936("MS936", true, false), + CP949("MS949", true, false), + CP950("MS950", true, false), + CP1250("Cp1250", true, true), + CP1251("Cp1251", true, true), + CP1252("Cp1252", true, true), + CP1253("Cp1253", true, true), + CP1254("Cp1254", true, true), + CP1255("Cp1255", true, true), + CP1256("Cp1256", true, true), + CP1257("Cp1257", true, true), + CP1258("Cp1258", true, true); private final String charsetName; private final boolean supportsAsciiConversion; @@ -584,9 +580,7 @@ enum Encoding private boolean jvmSupportConfirmed = false; private Charset charset; - private Encoding(String charsetName, - boolean supportsAsciiConversion, - boolean hasAsciiCompatibleSBCS) { + private Encoding(String charsetName, boolean supportsAsciiConversion, boolean hasAsciiCompatibleSBCS) { this.charsetName = charsetName; this.supportsAsciiConversion = supportsAsciiConversion; this.hasAsciiCompatibleSBCS = hasAsciiCompatibleSBCS; @@ -614,8 +608,7 @@ final Charset charset() throws SQLServerException { if (charset == null) { charset = Charset.forName(charsetName); } - } - catch (UnsupportedEncodingException e) { + } catch (UnsupportedEncodingException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_codePageNotSupported")); Object[] msgArgs = {charsetName}; throw new SQLServerException(form.format(msgArgs), e); @@ -626,8 +619,9 @@ final Charset charset() throws SQLServerException { /** * Returns true if the collation supports conversion to ascii. * - * Per discussions with richards and michkap on UNICODE alias -> ASCII range is 0x00 to 0x7F. The range of 0x00 to 0x7F of 1250-1258, 874, 932, - * 936, 949, and 950 are identical to ASCII. See also -> http://blogs.msdn.com/michkap/archive/2005/11/23/495193.aspx + * Per discussions with richards and michkap on UNICODE alias -> ASCII range is 0x00 to 0x7F. The range of 0x00 to + * 0x7F of 1250-1258, 874, 932, 936, 949, and 950 are identical to ASCII. See also -> + * http://blogs.msdn.com/michkap/archive/2005/11/23/495193.aspx */ boolean supportsAsciiConversion() { return supportsAsciiConversion; @@ -636,8 +630,9 @@ boolean supportsAsciiConversion() { /** * Returns true if the collation supports conversion to ascii AND it uses a single-byte character set. * - * Per discussions with richards and michkap on UNICODE alias -> ASCII range is 0x00 to 0x7F. The range of 0x00 to 0x7F of 1250-1258 and 874 are - * identical to ASCII for these SBCS character sets. See also -> http://blogs.msdn.com/michkap/archive/2005/11/23/495193.aspx + * Per discussions with richards and michkap on UNICODE alias -> ASCII range is 0x00 to 0x7F. The range of 0x00 to + * 0x7F of 1250-1258 and 874 are identical to ASCII for these SBCS character sets. See also -> + * http://blogs.msdn.com/michkap/archive/2005/11/23/495193.aspx */ boolean hasAsciiCompatibleSBCS() { return hasAsciiCompatibleSBCS; diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLJdbcVersion.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLJdbcVersion.java index 41028eb8e..824dfdf8f 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLJdbcVersion.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLJdbcVersion.java @@ -1,16 +1,13 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; final class SQLJdbcVersion { - static final int major = 6; - static final int minor = 5; - static final int patch = 4; + static final int major = 7; + static final int minor = 0; + static final int patch = 0; static final int build = 0; } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerADAL4JUtils.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerADAL4JUtils.java index a04b98296..f0418a60c 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerADAL4JUtils.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerADAL4JUtils.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -25,37 +22,36 @@ import com.microsoft.sqlserver.jdbc.SQLServerConnection.ActiveDirectoryAuthentication; import com.microsoft.sqlserver.jdbc.SQLServerConnection.SqlFedAuthInfo; + class SQLServerADAL4JUtils { static final private java.util.logging.Logger adal4jLogger = java.util.logging.Logger .getLogger("com.microsoft.sqlserver.jdbc.internals.SQLServerADAL4JUtils"); - static SqlFedAuthToken getSqlFedAuthToken(SqlFedAuthInfo fedAuthInfo, - String user, - String password, + static SqlFedAuthToken getSqlFedAuthToken(SqlFedAuthInfo fedAuthInfo, String user, String password, String authenticationString) throws SQLServerException { ExecutorService executorService = Executors.newFixedThreadPool(1); try { AuthenticationContext context = new AuthenticationContext(fedAuthInfo.stsurl, false, executorService); - Future future = context.acquireToken(fedAuthInfo.spn, ActiveDirectoryAuthentication.JDBC_FEDAUTH_CLIENT_ID, user, - password, null); + Future future = context.acquireToken(fedAuthInfo.spn, + ActiveDirectoryAuthentication.JDBC_FEDAUTH_CLIENT_ID, user, password, null); AuthenticationResult authenticationResult = future.get(); - SqlFedAuthToken fedAuthToken = new SqlFedAuthToken(authenticationResult.getAccessToken(), authenticationResult.getExpiresOnDate()); + SqlFedAuthToken fedAuthToken = new SqlFedAuthToken(authenticationResult.getAccessToken(), + authenticationResult.getExpiresOnDate()); return fedAuthToken; - } - catch (MalformedURLException | InterruptedException e) { + } catch (MalformedURLException | InterruptedException e) { throw new SQLServerException(e.getMessage(), e); - } - catch (ExecutionException e) { + } catch (ExecutionException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_ADALExecution")); Object[] msgArgs = {user, authenticationString}; // the cause error message uses \\n\\r which does not give correct format // change it to \r\n to provide correct format String correctedErrorMessage = e.getCause().getMessage().replaceAll("\\\\r\\\\n", "\r\n"); - AuthenticationException correctedAuthenticationException = new AuthenticationException(correctedErrorMessage); + AuthenticationException correctedAuthenticationException = new AuthenticationException( + correctedErrorMessage); // SQLServerException is caused by ExecutionException, which is caused by // AuthenticationException @@ -63,8 +59,7 @@ static SqlFedAuthToken getSqlFedAuthToken(SqlFedAuthInfo fedAuthInfo, ExecutionException correctedExecutionException = new ExecutionException(correctedAuthenticationException); throw new SQLServerException(form.format(msgArgs), null, 0, correctedExecutionException); - } - finally { + } finally { executorService.shutdown(); } } @@ -84,40 +79,39 @@ static SqlFedAuthToken getSqlFedAuthTokenIntegrated(SqlFedAuthInfo fedAuthInfo, } AuthenticationContext context = new AuthenticationContext(fedAuthInfo.stsurl, false, executorService); - Future future = context.acquireToken(fedAuthInfo.spn, ActiveDirectoryAuthentication.JDBC_FEDAUTH_CLIENT_ID, - username, null, null); + Future future = context.acquireToken(fedAuthInfo.spn, + ActiveDirectoryAuthentication.JDBC_FEDAUTH_CLIENT_ID, username, null, null); AuthenticationResult authenticationResult = future.get(); - SqlFedAuthToken fedAuthToken = new SqlFedAuthToken(authenticationResult.getAccessToken(), authenticationResult.getExpiresOnDate()); + SqlFedAuthToken fedAuthToken = new SqlFedAuthToken(authenticationResult.getAccessToken(), + authenticationResult.getExpiresOnDate()); return fedAuthToken; - } - catch (InterruptedException | IOException e) { + } catch (InterruptedException | IOException e) { throw new SQLServerException(e.getMessage(), e); - } - catch (ExecutionException e) { + } catch (ExecutionException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_ADALExecution")); Object[] msgArgs = {"", authenticationString}; if (null == e.getCause() || null == e.getCause().getMessage()) { // the case when Future's outcome has no AuthenticationResult but exception throw new SQLServerException(form.format(msgArgs), null); - } - else { + } else { // the cause error message uses \\n\\r which does not give correct format // change it to \r\n to provide correct format String correctedErrorMessage = e.getCause().getMessage().replaceAll("\\\\r\\\\n", "\r\n"); - AuthenticationException correctedAuthenticationException = new AuthenticationException(correctedErrorMessage); + AuthenticationException correctedAuthenticationException = new AuthenticationException( + correctedErrorMessage); // SQLServerException is caused by ExecutionException, which is caused by // AuthenticationException // to match the exception tree before error message correction - ExecutionException correctedExecutionException = new ExecutionException(correctedAuthenticationException); + ExecutionException correctedExecutionException = new ExecutionException( + correctedAuthenticationException); throw new SQLServerException(form.format(msgArgs), null, 0, correctedExecutionException); } - } - finally { + } finally { executorService.shutdown(); } } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerAeadAes256CbcHmac256Algorithm.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerAeadAes256CbcHmac256Algorithm.java index 0f45edbec..d32d3806f 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerAeadAes256CbcHmac256Algorithm.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerAeadAes256CbcHmac256Algorithm.java @@ -1,359 +1,353 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.SecureRandom; -import java.text.MessageFormat; - -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.Mac; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.ShortBufferException; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; - -/** - * - * This class implements authenticated encryption with associated data (AEAD_AES_256_CBC_HMAC_SHA256) algorithm specified at - * http://tools.ietf.org/html/draft-mcgrew-aead-aes-cbc-hmac-sha2-05 - * - */ -class SQLServerAeadAes256CbcHmac256Algorithm extends SQLServerEncryptionAlgorithm { - - static final private java.util.logging.Logger aeLogger = java.util.logging.Logger - .getLogger("com.microsoft.sqlserver.jdbc.SQLServerAeadAes256CbcHmac256Algorithm"); - - final static String algorithmName = "AEAD_AES_256_CBC_HMAC_SHA256"; - // Stores column encryption key which includes root key and derived keys - private SQLServerAeadAes256CbcHmac256EncryptionKey columnEncryptionkey; - private byte algorithmVersion; - // This variable indicate whether encryption type is deterministic (if true) - // or random (if false) - private boolean isDeterministic = false; - // Each block in the AES is 128 bits - private int blockSizeInBytes = 16; - private int keySizeInBytes = SQLServerAeadAes256CbcHmac256EncryptionKey.keySize / 8; - private byte[] version = new byte[] {0x01}; - // Added so that java hashing algorithm is similar to c# - private byte[] versionSize = new byte[] {1}; - - /* - * Minimum Length of cipherText without authentication tag. This value is 1 (version byte) + 16 (IV) + 16 (minimum of 1 block of cipher Text) - */ - private int minimumCipherTextLengthInBytesNoAuthenticationTag = 1 + blockSizeInBytes + blockSizeInBytes; - - /* - * Minimum Length of cipherText. This value is 1 (version byte) + 32 (authentication tag) + 16 (IV) + 16 (minimum of 1 block of cipher Text) - */ - private int minimumCipherTextLengthInBytesWithAuthenticationTag = minimumCipherTextLengthInBytesNoAuthenticationTag + keySizeInBytes; - - /** - * Initializes a new instance of SQLServerAeadAes256CbcHmac256Algorithm with a given key, encryption type and algorithm version - * - * @param columnEncryptionkey - * Root encryption key from which three other keys will be derived - * @param encryptionType - * Encryption Type, accepted values are Deterministic and Randomized. - * @param algorithmVersion - * Algorithm version - */ - SQLServerAeadAes256CbcHmac256Algorithm(SQLServerAeadAes256CbcHmac256EncryptionKey columnEncryptionkey, - SQLServerEncryptionType encryptionType, - byte algorithmVersion) { - this.columnEncryptionkey = columnEncryptionkey; - - if (encryptionType == SQLServerEncryptionType.Deterministic) { - this.isDeterministic = true; - } - this.algorithmVersion = algorithmVersion; - version[0] = algorithmVersion; - } - - @Override - byte[] encryptData(byte[] plainText) throws SQLServerException { - // hasAuthenticationTag is true for this algorithm - return encryptData(plainText, true); - } - - /** - * Performs encryption of plain text - * - * @param plainText - * text to be encrypted - * @param hasAuthenticationTag - * specify if encryption needs authentication - * @return cipher text - * @throws SQLServerException - */ - protected byte[] encryptData(byte[] plainText, - boolean hasAuthenticationTag) throws SQLServerException { - aeLogger.entering(SQLServerAeadAes256CbcHmac256Algorithm.class.getName(), Thread.currentThread().getStackTrace()[1].getMethodName(), - "Encrypting data."); - // we will generate this initialization vector based whether - // this encryption type is deterministic - assert (plainText != null); - byte[] iv = new byte[blockSizeInBytes]; - // Secret/private key to be used in AES encryption - SecretKeySpec skeySpec = new SecretKeySpec(columnEncryptionkey.getEncryptionKey(), "AES"); - - if (isDeterministic) { - // this method makes sure this is 16 bytes key - try { - iv = SQLServerSecurityUtility.getHMACWithSHA256(plainText, columnEncryptionkey.getIVKey(), blockSizeInBytes); - } - catch (InvalidKeyException | NoSuchAlgorithmException e) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_EncryptionFailed")); - Object[] msgArgs = {e.getMessage()}; - throw new SQLServerException(this, form.format(msgArgs), null, 0, false); - } - } - else { - SecureRandom random = new SecureRandom(); - random.nextBytes(iv); - } - - int numBlocks = plainText.length / blockSizeInBytes + 1; - - int hmacStartIndex = 1; - int authenticationTagLen = hasAuthenticationTag ? keySizeInBytes : 0; - int ivStartIndex = hmacStartIndex + authenticationTagLen; - int cipherStartIndex = ivStartIndex + blockSizeInBytes; - - // Output buffer size = size of VersionByte + Authentication Tag + IV + cipher Text blocks. - int outputBufSize = 1 + authenticationTagLen + iv.length + (numBlocks * blockSizeInBytes); - byte[] outBuffer = new byte[outputBufSize]; - - // Copying the version to output buffer - outBuffer[0] = algorithmVersion; - // Coping IV to the output buffer - System.arraycopy(iv, 0, outBuffer, ivStartIndex, iv.length); - - // Start the AES encryption - - try { - // initialization vector - IvParameterSpec ivector = new IvParameterSpec(iv); - Cipher encryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - encryptCipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivector); - - int count = 0; - int cipherIndex = cipherStartIndex; // this is where cipherText starts - - if (numBlocks > 1) { - count = (numBlocks - 1) * blockSizeInBytes; - cipherIndex += encryptCipher.update(plainText, 0, count, outBuffer, cipherIndex); - } - // doFinal will complete the encryption - byte[] buffTmp = encryptCipher.doFinal(plainText, count, plainText.length - count); - // Encryption completed - System.arraycopy(buffTmp, 0, outBuffer, cipherIndex, buffTmp.length); - - if (hasAuthenticationTag) { - - Mac hmac = Mac.getInstance("HmacSHA256"); - SecretKeySpec initkey = new SecretKeySpec(columnEncryptionkey.getMacKey(), "HmacSHA256"); - hmac.init(initkey); - hmac.update(version, 0, version.length); - hmac.update(iv, 0, iv.length); - hmac.update(outBuffer, cipherStartIndex, numBlocks * blockSizeInBytes); - hmac.update(versionSize, 0, version.length); - byte[] hash = hmac.doFinal(); - // coping the authentication tag in the output buffer which holds cipher text - System.arraycopy(hash, 0, outBuffer, hmacStartIndex, authenticationTagLen); - - } - } - catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException | InvalidKeyException | NoSuchPaddingException - | IllegalBlockSizeException | BadPaddingException | ShortBufferException e) { - - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_EncryptionFailed")); - Object[] msgArgs = {e.getMessage()}; - throw new SQLServerException(this, form.format(msgArgs), null, 0, false); - } - - aeLogger.exiting(SQLServerAeadAes256CbcHmac256Algorithm.class.getName(), Thread.currentThread().getStackTrace()[1].getMethodName(), - "Data encrypted."); - return outBuffer; - - } - - @Override - byte[] decryptData(byte[] cipherText) throws SQLServerException { - return decryptData(cipherText, true); - - } - - /** - * Decrypt the cipher text and return plain text - * - * @param cipherText - * data to be decrypted - * @param hasAuthenticationTag - * tells whether cipher text contain authentication tag - * @return plain text - * @throws SQLServerException - */ - private byte[] decryptData(byte[] cipherText, - boolean hasAuthenticationTag) throws SQLServerException { - assert (cipherText != null); - - byte[] iv = new byte[blockSizeInBytes]; - - int minimumCipherTextLength = hasAuthenticationTag ? minimumCipherTextLengthInBytesWithAuthenticationTag - : minimumCipherTextLengthInBytesNoAuthenticationTag; - - // Here we check if length of cipher text is more than minimum value, - // if not exception is thrown - if (cipherText.length < minimumCipherTextLength) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidCipherTextSize")); - Object[] msgArgs = {cipherText.length, minimumCipherTextLength}; - throw new SQLServerException(this, form.format(msgArgs), null, 0, false); - - } - - // Validate the version byte - int startIndex = 0; - if (cipherText[startIndex] != algorithmVersion) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidAlgorithmVersion")); - // converting byte to Hexa Decimal - Object[] msgArgs = {String.format("%02X ", cipherText[startIndex]), String.format("%02X ", algorithmVersion)}; - throw new SQLServerException(this, form.format(msgArgs), null, 0, false); - - } - - startIndex += 1; - int authenticationTagOffset = 0; - - // Read authentication tag - if (hasAuthenticationTag) { - authenticationTagOffset = startIndex; - // authentication tag size is keySizeInBytes - startIndex += keySizeInBytes; - } - - // Read IV from cipher text - System.arraycopy(cipherText, startIndex, iv, 0, iv.length); - startIndex += iv.length; - - // To read encrypted text from cipher - int cipherTextOffset = startIndex; - // All data after IV is encrypted data - int cipherTextCount = cipherText.length - startIndex; - - if (hasAuthenticationTag) { - byte[] authenticationTag; - try { - authenticationTag = prepareAuthenticationTag(iv, cipherText, cipherTextOffset, cipherTextCount); - } - catch (InvalidKeyException | NoSuchAlgorithmException e) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_DecryptionFailed")); - Object[] msgArgs = {e.getMessage()}; - throw new SQLServerException(this, form.format(msgArgs), null, 0, false); - - } - if (!(SQLServerSecurityUtility.compareBytes(authenticationTag, cipherText, authenticationTagOffset, cipherTextCount))) { - - throw new SQLServerException(this, SQLServerException.getErrString("R_InvalidAuthenticationTag"), null, 0, false); - - } - - } - - // Decrypt the text and return - return decryptData(iv, cipherText, cipherTextOffset, cipherTextCount); - } - - /** - * Decrypt data with specified IV - * - * @param iv - * initialization vector - * @param cipherText - * text to be decrypted - * @param offset - * of cipher text - * @param count - * length of cipher text - * @return plain text - * @throws SQLServerException - */ - private byte[] decryptData(byte[] iv, - byte[] cipherText, - int offset, - int count) throws SQLServerException { - aeLogger.entering(SQLServerAeadAes256CbcHmac256Algorithm.class.getName(), Thread.currentThread().getStackTrace()[1].getMethodName(), - "Decrypting data."); - assert (cipherText != null); - assert (iv != null); - byte[] plainText = null; - // key to be used for decryption - SecretKeySpec skeySpec = new SecretKeySpec(columnEncryptionkey.getEncryptionKey(), "AES"); - IvParameterSpec ivector = new IvParameterSpec(iv); - Cipher decryptCipher; - try { - // AES encryption CBC mode and PKCS5 padding - decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - decryptCipher.init(Cipher.DECRYPT_MODE, skeySpec, ivector); - plainText = decryptCipher.doFinal(cipherText, offset, count); - } - catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException | InvalidKeyException | NoSuchPaddingException - | IllegalBlockSizeException | BadPaddingException e) { - - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_DecryptionFailed")); - Object[] msgArgs = {e.getMessage()}; - throw new SQLServerException(this, form.format(msgArgs), null, 0, false); - } - - aeLogger.exiting(SQLServerAeadAes256CbcHmac256Algorithm.class.getName(), Thread.currentThread().getStackTrace()[1].getMethodName(), - "Data decrypted."); - return plainText; - - } - - /** - * Prepare the authentication tag - * - * @param iv - * initialization vector - * @param cipherText - * @param offset - * @param length - * length of cipher text - * @return authentication tag - * @throws NoSuchAlgorithmException - * @throws InvalidKeyException - */ - private byte[] prepareAuthenticationTag(byte[] iv, - byte[] cipherText, - int offset, - int length) throws NoSuchAlgorithmException, InvalidKeyException { - assert (cipherText != null); - byte[] computedHash; - byte[] authenticationTag = new byte[keySizeInBytes]; - - Mac hmac = Mac.getInstance("HmacSHA256"); - SecretKeySpec key = new SecretKeySpec(columnEncryptionkey.getMacKey(), "HmacSHA256"); - hmac.init(key); - hmac.update(version, 0, version.length); - hmac.update(iv, 0, iv.length); - hmac.update(cipherText, offset, length); - hmac.update(versionSize, 0, version.length); - computedHash = hmac.doFinal(); - System.arraycopy(computedHash, 0, authenticationTag, 0, authenticationTag.length); - - return authenticationTag; - - } - -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.text.MessageFormat; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.Mac; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.ShortBufferException; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + + +/** + * + * This class implements authenticated encryption with associated data (AEAD_AES_256_CBC_HMAC_SHA256) algorithm + * specified at + * http://tools.ietf.org/html/draft-mcgrew-aead-aes-cbc-hmac-sha2-05 + * + */ +class SQLServerAeadAes256CbcHmac256Algorithm extends SQLServerEncryptionAlgorithm { + + static final private java.util.logging.Logger aeLogger = java.util.logging.Logger + .getLogger("com.microsoft.sqlserver.jdbc.SQLServerAeadAes256CbcHmac256Algorithm"); + + final static String algorithmName = "AEAD_AES_256_CBC_HMAC_SHA256"; + // Stores column encryption key which includes root key and derived keys + private SQLServerAeadAes256CbcHmac256EncryptionKey columnEncryptionkey; + private byte algorithmVersion; + // This variable indicate whether encryption type is deterministic (if true) + // or random (if false) + private boolean isDeterministic = false; + // Each block in the AES is 128 bits + private int blockSizeInBytes = 16; + private int keySizeInBytes = SQLServerAeadAes256CbcHmac256EncryptionKey.keySize / 8; + private byte[] version = new byte[] {0x01}; + // Added so that java hashing algorithm is similar to c# + private byte[] versionSize = new byte[] {1}; + + /* + * Minimum Length of cipherText without authentication tag. This value is 1 (version byte) + 16 (IV) + 16 (minimum + * of 1 block of cipher Text) + */ + private int minimumCipherTextLengthInBytesNoAuthenticationTag = 1 + blockSizeInBytes + blockSizeInBytes; + + /* + * Minimum Length of cipherText. This value is 1 (version byte) + 32 (authentication tag) + 16 (IV) + 16 (minimum of + * 1 block of cipher Text) + */ + private int minimumCipherTextLengthInBytesWithAuthenticationTag = minimumCipherTextLengthInBytesNoAuthenticationTag + + keySizeInBytes; + + /** + * Initializes a new instance of SQLServerAeadAes256CbcHmac256Algorithm with a given key, encryption type and + * algorithm version + * + * @param columnEncryptionkey + * Root encryption key from which three other keys will be derived + * @param encryptionType + * Encryption Type, accepted values are Deterministic and Randomized. + * @param algorithmVersion + * Algorithm version + */ + SQLServerAeadAes256CbcHmac256Algorithm(SQLServerAeadAes256CbcHmac256EncryptionKey columnEncryptionkey, + SQLServerEncryptionType encryptionType, byte algorithmVersion) { + this.columnEncryptionkey = columnEncryptionkey; + + if (encryptionType == SQLServerEncryptionType.Deterministic) { + this.isDeterministic = true; + } + this.algorithmVersion = algorithmVersion; + version[0] = algorithmVersion; + } + + @Override + byte[] encryptData(byte[] plainText) throws SQLServerException { + // hasAuthenticationTag is true for this algorithm + return encryptData(plainText, true); + } + + /** + * Performs encryption of plain text + * + * @param plainText + * text to be encrypted + * @param hasAuthenticationTag + * specify if encryption needs authentication + * @return cipher text + * @throws SQLServerException + */ + protected byte[] encryptData(byte[] plainText, boolean hasAuthenticationTag) throws SQLServerException { + aeLogger.entering(SQLServerAeadAes256CbcHmac256Algorithm.class.getName(), + Thread.currentThread().getStackTrace()[1].getMethodName(), "Encrypting data."); + // we will generate this initialization vector based whether + // this encryption type is deterministic + assert (plainText != null); + byte[] iv = new byte[blockSizeInBytes]; + // Secret/private key to be used in AES encryption + SecretKeySpec skeySpec = new SecretKeySpec(columnEncryptionkey.getEncryptionKey(), "AES"); + + if (isDeterministic) { + // this method makes sure this is 16 bytes key + try { + iv = SQLServerSecurityUtility.getHMACWithSHA256(plainText, columnEncryptionkey.getIVKey(), + blockSizeInBytes); + } catch (InvalidKeyException | NoSuchAlgorithmException e) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_EncryptionFailed")); + Object[] msgArgs = {e.getMessage()}; + throw new SQLServerException(this, form.format(msgArgs), null, 0, false); + } + } else { + SecureRandom random = new SecureRandom(); + random.nextBytes(iv); + } + + int numBlocks = plainText.length / blockSizeInBytes + 1; + + int hmacStartIndex = 1; + int authenticationTagLen = hasAuthenticationTag ? keySizeInBytes : 0; + int ivStartIndex = hmacStartIndex + authenticationTagLen; + int cipherStartIndex = ivStartIndex + blockSizeInBytes; + + // Output buffer size = size of VersionByte + Authentication Tag + IV + cipher Text blocks. + int outputBufSize = 1 + authenticationTagLen + iv.length + (numBlocks * blockSizeInBytes); + byte[] outBuffer = new byte[outputBufSize]; + + // Copying the version to output buffer + outBuffer[0] = algorithmVersion; + // Coping IV to the output buffer + System.arraycopy(iv, 0, outBuffer, ivStartIndex, iv.length); + + // Start the AES encryption + + try { + // initialization vector + IvParameterSpec ivector = new IvParameterSpec(iv); + Cipher encryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + encryptCipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivector); + + int count = 0; + int cipherIndex = cipherStartIndex; // this is where cipherText starts + + if (numBlocks > 1) { + count = (numBlocks - 1) * blockSizeInBytes; + cipherIndex += encryptCipher.update(plainText, 0, count, outBuffer, cipherIndex); + } + // doFinal will complete the encryption + byte[] buffTmp = encryptCipher.doFinal(plainText, count, plainText.length - count); + // Encryption completed + System.arraycopy(buffTmp, 0, outBuffer, cipherIndex, buffTmp.length); + + if (hasAuthenticationTag) { + + Mac hmac = Mac.getInstance("HmacSHA256"); + SecretKeySpec initkey = new SecretKeySpec(columnEncryptionkey.getMacKey(), "HmacSHA256"); + hmac.init(initkey); + hmac.update(version, 0, version.length); + hmac.update(iv, 0, iv.length); + hmac.update(outBuffer, cipherStartIndex, numBlocks * blockSizeInBytes); + hmac.update(versionSize, 0, version.length); + byte[] hash = hmac.doFinal(); + // coping the authentication tag in the output buffer which holds cipher text + System.arraycopy(hash, 0, outBuffer, hmacStartIndex, authenticationTagLen); + + } + } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException | InvalidKeyException + | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException | ShortBufferException e) { + + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_EncryptionFailed")); + Object[] msgArgs = {e.getMessage()}; + throw new SQLServerException(this, form.format(msgArgs), null, 0, false); + } + + aeLogger.exiting(SQLServerAeadAes256CbcHmac256Algorithm.class.getName(), + Thread.currentThread().getStackTrace()[1].getMethodName(), "Data encrypted."); + return outBuffer; + + } + + @Override + byte[] decryptData(byte[] cipherText) throws SQLServerException { + return decryptData(cipherText, true); + + } + + /** + * Decrypt the cipher text and return plain text + * + * @param cipherText + * data to be decrypted + * @param hasAuthenticationTag + * tells whether cipher text contain authentication tag + * @return plain text + * @throws SQLServerException + */ + private byte[] decryptData(byte[] cipherText, boolean hasAuthenticationTag) throws SQLServerException { + assert (cipherText != null); + + byte[] iv = new byte[blockSizeInBytes]; + + int minimumCipherTextLength = hasAuthenticationTag ? minimumCipherTextLengthInBytesWithAuthenticationTag + : minimumCipherTextLengthInBytesNoAuthenticationTag; + + // Here we check if length of cipher text is more than minimum value, + // if not exception is thrown + if (cipherText.length < minimumCipherTextLength) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidCipherTextSize")); + Object[] msgArgs = {cipherText.length, minimumCipherTextLength}; + throw new SQLServerException(this, form.format(msgArgs), null, 0, false); + + } + + // Validate the version byte + int startIndex = 0; + if (cipherText[startIndex] != algorithmVersion) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidAlgorithmVersion")); + // converting byte to Hexa Decimal + Object[] msgArgs = {String.format("%02X ", cipherText[startIndex]), + String.format("%02X ", algorithmVersion)}; + throw new SQLServerException(this, form.format(msgArgs), null, 0, false); + + } + + startIndex += 1; + int authenticationTagOffset = 0; + + // Read authentication tag + if (hasAuthenticationTag) { + authenticationTagOffset = startIndex; + // authentication tag size is keySizeInBytes + startIndex += keySizeInBytes; + } + + // Read IV from cipher text + System.arraycopy(cipherText, startIndex, iv, 0, iv.length); + startIndex += iv.length; + + // To read encrypted text from cipher + int cipherTextOffset = startIndex; + // All data after IV is encrypted data + int cipherTextCount = cipherText.length - startIndex; + + if (hasAuthenticationTag) { + byte[] authenticationTag; + try { + authenticationTag = prepareAuthenticationTag(iv, cipherText, cipherTextOffset, cipherTextCount); + } catch (InvalidKeyException | NoSuchAlgorithmException e) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_DecryptionFailed")); + Object[] msgArgs = {e.getMessage()}; + throw new SQLServerException(this, form.format(msgArgs), null, 0, false); + + } + if (!(SQLServerSecurityUtility.compareBytes(authenticationTag, cipherText, authenticationTagOffset, + cipherTextCount))) { + + throw new SQLServerException(this, SQLServerException.getErrString("R_InvalidAuthenticationTag"), null, + 0, false); + + } + + } + + // Decrypt the text and return + return decryptData(iv, cipherText, cipherTextOffset, cipherTextCount); + } + + /** + * Decrypt data with specified IV + * + * @param iv + * initialization vector + * @param cipherText + * text to be decrypted + * @param offset + * of cipher text + * @param count + * length of cipher text + * @return plain text + * @throws SQLServerException + */ + private byte[] decryptData(byte[] iv, byte[] cipherText, int offset, int count) throws SQLServerException { + aeLogger.entering(SQLServerAeadAes256CbcHmac256Algorithm.class.getName(), + Thread.currentThread().getStackTrace()[1].getMethodName(), "Decrypting data."); + assert (cipherText != null); + assert (iv != null); + byte[] plainText = null; + // key to be used for decryption + SecretKeySpec skeySpec = new SecretKeySpec(columnEncryptionkey.getEncryptionKey(), "AES"); + IvParameterSpec ivector = new IvParameterSpec(iv); + Cipher decryptCipher; + try { + // AES encryption CBC mode and PKCS5 padding + decryptCipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); + decryptCipher.init(Cipher.DECRYPT_MODE, skeySpec, ivector); + plainText = decryptCipher.doFinal(cipherText, offset, count); + } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException | InvalidKeyException + | NoSuchPaddingException | IllegalBlockSizeException | BadPaddingException e) { + + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_DecryptionFailed")); + Object[] msgArgs = {e.getMessage()}; + throw new SQLServerException(this, form.format(msgArgs), null, 0, false); + } + + aeLogger.exiting(SQLServerAeadAes256CbcHmac256Algorithm.class.getName(), + Thread.currentThread().getStackTrace()[1].getMethodName(), "Data decrypted."); + return plainText; + + } + + /** + * Prepare the authentication tag + * + * @param iv + * initialization vector + * @param cipherText + * @param offset + * @param length + * length of cipher text + * @return authentication tag + * @throws NoSuchAlgorithmException + * @throws InvalidKeyException + */ + private byte[] prepareAuthenticationTag(byte[] iv, byte[] cipherText, int offset, + int length) throws NoSuchAlgorithmException, InvalidKeyException { + assert (cipherText != null); + byte[] computedHash; + byte[] authenticationTag = new byte[keySizeInBytes]; + + Mac hmac = Mac.getInstance("HmacSHA256"); + SecretKeySpec key = new SecretKeySpec(columnEncryptionkey.getMacKey(), "HmacSHA256"); + hmac.init(key); + hmac.update(version, 0, version.length); + hmac.update(iv, 0, iv.length); + hmac.update(cipherText, offset, length); + hmac.update(versionSize, 0, version.length); + computedHash = hmac.doFinal(); + System.arraycopy(computedHash, 0, authenticationTag, 0, authenticationTag.length); + + return authenticationTag; + + } + +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerAeadAes256CbcHmac256EncryptionKey.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerAeadAes256CbcHmac256EncryptionKey.java index b2e6826ab..b1a8c5853 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerAeadAes256CbcHmac256EncryptionKey.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerAeadAes256CbcHmac256EncryptionKey.java @@ -1,116 +1,118 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -import static java.nio.charset.StandardCharsets.UTF_16LE; - -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.text.MessageFormat; - -/** - * Encryption key class which consist of following 4 keys : 1) root key - Main key which is used to derive following keys 2) encryption key - A - * derived key that is used to encrypt the plain text and generate cipher text 3) mac_key - A derived key that is used to compute HMAC of the cipher - * text 4) iv_key - A derived key that is used to generate a synthetic IV from plain text data. - */ -class SQLServerAeadAes256CbcHmac256EncryptionKey extends SQLServerSymmetricKey { - - // This is the key size in the bits, since we are using AES256, it will 256 - static final int keySize = 256; - // Name of algorithm associated with this key - private final String algorithmName; - // Salt used to derive encryption key - private String encryptionKeySaltFormat; - // Salt used to derive mac key - private String macKeySaltFormat; - // Salt used to derive iv key - private String ivKeySaltFormat; - private SQLServerSymmetricKey encryptionKey; - private SQLServerSymmetricKey macKey; - private SQLServerSymmetricKey ivKey; - - /** - * Derive all the keys from the root key - * - * @param rootKey - * key used to derive other keys - * @param algorithmName - * name of the algorithm associated with keys - * @throws SQLServerException - */ - SQLServerAeadAes256CbcHmac256EncryptionKey(byte[] rootKey, - String algorithmName) throws SQLServerException { - super(rootKey); - this.algorithmName = algorithmName; - encryptionKeySaltFormat = "Microsoft SQL Server cell encryption key with encryption algorithm:" + this.algorithmName + " and key length:" - + keySize; - macKeySaltFormat = "Microsoft SQL Server cell MAC key with encryption algorithm:" + this.algorithmName + " and key length:" + keySize; - ivKeySaltFormat = "Microsoft SQL Server cell IV key with encryption algorithm:" + this.algorithmName + " and key length:" + keySize; - int keySizeInBytes = (keySize / 8); - if (rootKey.length != keySizeInBytes) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidKeySize")); - Object[] msgArgs = {rootKey.length, keySizeInBytes, this.algorithmName}; - throw new SQLServerException(this, form.format(msgArgs), null, 0, false); - - } - - // Derive encryption key - - byte[] encKeyBuff = new byte[keySizeInBytes]; - try { - // By default Java is big endian, we are getting bytes in little endian(LE in UTF-16LE) - // to make it compatible with C# driver which is little endian - encKeyBuff = SQLServerSecurityUtility.getHMACWithSHA256(encryptionKeySaltFormat.getBytes(UTF_16LE), rootKey, encKeyBuff.length); - - encryptionKey = new SQLServerSymmetricKey(encKeyBuff); - - // Derive mac key from root key - byte[] macKeyBuff = new byte[keySizeInBytes]; - macKeyBuff = SQLServerSecurityUtility.getHMACWithSHA256(macKeySaltFormat.getBytes(UTF_16LE), rootKey, macKeyBuff.length); - - macKey = new SQLServerSymmetricKey(macKeyBuff); - - // Derive the initialization vector from root key - byte[] ivKeyBuff = new byte[keySizeInBytes]; - ivKeyBuff = SQLServerSecurityUtility.getHMACWithSHA256(ivKeySaltFormat.getBytes(UTF_16LE), rootKey, ivKeyBuff.length); - ivKey = new SQLServerSymmetricKey(ivKeyBuff); - } - catch (InvalidKeyException | NoSuchAlgorithmException e) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_KeyExtractionFailed")); - Object[] msgArgs = {e.getMessage()}; - throw new SQLServerException(this, form.format(msgArgs), null, 0, false); - } - - } - - /** - * - * @return encryption key - */ - byte[] getEncryptionKey() { - return encryptionKey.getRootKey(); - } - - /** - * - * @return mac key - */ - byte[] getMacKey() { - return macKey.getRootKey(); - } - - /** - * - * @return iv key - */ - byte[] getIVKey() { - return ivKey.getRootKey(); - } - -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +import static java.nio.charset.StandardCharsets.UTF_16LE; + +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.text.MessageFormat; + + +/** + * Encryption key class which consist of following 4 keys : 1) root key - Main key which is used to derive following + * keys 2) encryption key - A derived key that is used to encrypt the plain text and generate cipher text 3) mac_key - A + * derived key that is used to compute HMAC of the cipher text 4) iv_key - A derived key that is used to generate a + * synthetic IV from plain text data. + */ +class SQLServerAeadAes256CbcHmac256EncryptionKey extends SQLServerSymmetricKey { + + // This is the key size in the bits, since we are using AES256, it will 256 + static final int keySize = 256; + // Name of algorithm associated with this key + private final String algorithmName; + // Salt used to derive encryption key + private String encryptionKeySaltFormat; + // Salt used to derive mac key + private String macKeySaltFormat; + // Salt used to derive iv key + private String ivKeySaltFormat; + private SQLServerSymmetricKey encryptionKey; + private SQLServerSymmetricKey macKey; + private SQLServerSymmetricKey ivKey; + + /** + * Derive all the keys from the root key + * + * @param rootKey + * key used to derive other keys + * @param algorithmName + * name of the algorithm associated with keys + * @throws SQLServerException + */ + SQLServerAeadAes256CbcHmac256EncryptionKey(byte[] rootKey, String algorithmName) throws SQLServerException { + super(rootKey); + this.algorithmName = algorithmName; + encryptionKeySaltFormat = "Microsoft SQL Server cell encryption key with encryption algorithm:" + + this.algorithmName + " and key length:" + keySize; + macKeySaltFormat = "Microsoft SQL Server cell MAC key with encryption algorithm:" + this.algorithmName + + " and key length:" + keySize; + ivKeySaltFormat = "Microsoft SQL Server cell IV key with encryption algorithm:" + this.algorithmName + + " and key length:" + keySize; + int keySizeInBytes = (keySize / 8); + if (rootKey.length != keySizeInBytes) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidKeySize")); + Object[] msgArgs = {rootKey.length, keySizeInBytes, this.algorithmName}; + throw new SQLServerException(this, form.format(msgArgs), null, 0, false); + + } + + // Derive encryption key + + byte[] encKeyBuff = new byte[keySizeInBytes]; + try { + // By default Java is big endian, we are getting bytes in little endian(LE in UTF-16LE) + // to make it compatible with C# driver which is little endian + encKeyBuff = SQLServerSecurityUtility.getHMACWithSHA256(encryptionKeySaltFormat.getBytes(UTF_16LE), rootKey, + encKeyBuff.length); + + encryptionKey = new SQLServerSymmetricKey(encKeyBuff); + + // Derive mac key from root key + byte[] macKeyBuff = new byte[keySizeInBytes]; + macKeyBuff = SQLServerSecurityUtility.getHMACWithSHA256(macKeySaltFormat.getBytes(UTF_16LE), rootKey, + macKeyBuff.length); + + macKey = new SQLServerSymmetricKey(macKeyBuff); + + // Derive the initialization vector from root key + byte[] ivKeyBuff = new byte[keySizeInBytes]; + ivKeyBuff = SQLServerSecurityUtility.getHMACWithSHA256(ivKeySaltFormat.getBytes(UTF_16LE), rootKey, + ivKeyBuff.length); + ivKey = new SQLServerSymmetricKey(ivKeyBuff); + } catch (InvalidKeyException | NoSuchAlgorithmException e) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_KeyExtractionFailed")); + Object[] msgArgs = {e.getMessage()}; + throw new SQLServerException(this, form.format(msgArgs), null, 0, false); + } + + } + + /** + * + * @return encryption key + */ + byte[] getEncryptionKey() { + return encryptionKey.getRootKey(); + } + + /** + * + * @return mac key + */ + byte[] getMacKey() { + return macKey.getRootKey(); + } + + /** + * + * @return iv key + */ + byte[] getIVKey() { + return ivKey.getRootKey(); + } + +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerAeadAes256CbcHmac256Factory.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerAeadAes256CbcHmac256Factory.java index 3a170da2d..58f5af235 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerAeadAes256CbcHmac256Factory.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerAeadAes256CbcHmac256Factory.java @@ -1,61 +1,60 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -import static java.nio.charset.StandardCharsets.UTF_8; - -import java.text.MessageFormat; -import java.util.concurrent.ConcurrentHashMap; -import java.util.Base64; - -/** - * Factory for SQLServerAeadAes256CbcHmac256Algorithm - */ -class SQLServerAeadAes256CbcHmac256Factory extends SQLServerEncryptionAlgorithmFactory { - // In future we can have more - private byte algorithmVersion = 0x1; - private ConcurrentHashMap encryptionAlgorithms = new ConcurrentHashMap<>(); - - @Override - SQLServerEncryptionAlgorithm create(SQLServerSymmetricKey columnEncryptionKey, - SQLServerEncryptionType encryptionType, - String encryptionAlgorithm) throws SQLServerException { - - assert (columnEncryptionKey != null); - if (encryptionType != SQLServerEncryptionType.Deterministic && encryptionType != SQLServerEncryptionType.Randomized) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidEncryptionType")); - Object[] msgArgs = {encryptionType, encryptionAlgorithm, - "'" + SQLServerEncryptionType.Deterministic + "," + SQLServerEncryptionType.Randomized + "'"}; - throw new SQLServerException(this, form.format(msgArgs), null, 0, false); - - } - - StringBuilder factoryKeyBuilder = new StringBuilder(); - factoryKeyBuilder.append(Base64.getEncoder().encodeToString(new String(columnEncryptionKey.getRootKey(), UTF_8).getBytes())); - - factoryKeyBuilder.append(":"); - factoryKeyBuilder.append(encryptionType); - factoryKeyBuilder.append(":"); - factoryKeyBuilder.append(algorithmVersion); - - String factoryKey = factoryKeyBuilder.toString(); - - SQLServerAeadAes256CbcHmac256Algorithm aesAlgorithm; - - if (!encryptionAlgorithms.containsKey(factoryKey)) { - SQLServerAeadAes256CbcHmac256EncryptionKey encryptedKey = new SQLServerAeadAes256CbcHmac256EncryptionKey(columnEncryptionKey.getRootKey(), - SQLServerAeadAes256CbcHmac256Algorithm.algorithmName); - aesAlgorithm = new SQLServerAeadAes256CbcHmac256Algorithm(encryptedKey, encryptionType, algorithmVersion); - encryptionAlgorithms.putIfAbsent(factoryKey, aesAlgorithm); - } - - return encryptionAlgorithms.get(factoryKey); - } - -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +import static java.nio.charset.StandardCharsets.UTF_8; + +import java.text.MessageFormat; +import java.util.Base64; +import java.util.concurrent.ConcurrentHashMap; + + +/** + * Factory for SQLServerAeadAes256CbcHmac256Algorithm + */ +class SQLServerAeadAes256CbcHmac256Factory extends SQLServerEncryptionAlgorithmFactory { + // In future we can have more + private byte algorithmVersion = 0x1; + private ConcurrentHashMap encryptionAlgorithms = new ConcurrentHashMap<>(); + + @Override + SQLServerEncryptionAlgorithm create(SQLServerSymmetricKey columnEncryptionKey, + SQLServerEncryptionType encryptionType, String encryptionAlgorithm) throws SQLServerException { + + assert (columnEncryptionKey != null); + if (encryptionType != SQLServerEncryptionType.Deterministic + && encryptionType != SQLServerEncryptionType.Randomized) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidEncryptionType")); + Object[] msgArgs = {encryptionType, encryptionAlgorithm, + "'" + SQLServerEncryptionType.Deterministic + "," + SQLServerEncryptionType.Randomized + "'"}; + throw new SQLServerException(this, form.format(msgArgs), null, 0, false); + + } + + StringBuilder factoryKeyBuilder = new StringBuilder(); + factoryKeyBuilder.append( + Base64.getEncoder().encodeToString(new String(columnEncryptionKey.getRootKey(), UTF_8).getBytes())); + + factoryKeyBuilder.append(":"); + factoryKeyBuilder.append(encryptionType); + factoryKeyBuilder.append(":"); + factoryKeyBuilder.append(algorithmVersion); + + String factoryKey = factoryKeyBuilder.toString(); + + SQLServerAeadAes256CbcHmac256Algorithm aesAlgorithm; + + if (!encryptionAlgorithms.containsKey(factoryKey)) { + SQLServerAeadAes256CbcHmac256EncryptionKey encryptedKey = new SQLServerAeadAes256CbcHmac256EncryptionKey( + columnEncryptionKey.getRootKey(), SQLServerAeadAes256CbcHmac256Algorithm.algorithmName); + aesAlgorithm = new SQLServerAeadAes256CbcHmac256Algorithm(encryptedKey, encryptionType, algorithmVersion); + encryptionAlgorithms.putIfAbsent(factoryKey, aesAlgorithm); + } + + return encryptionAlgorithms.get(factoryKey); + } + +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBlob.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBlob.java index 3631e2374..b1e785817 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBlob.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBlob.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -19,10 +16,10 @@ import java.util.logging.Level; import java.util.logging.Logger; + /** - * SQLServerBlob represents a binary LOB object and implements a java.sql.Blob. + * Represents a binary LOB object and implements a java.sql.Blob. */ - public final class SQLServerBlob extends SQLServerLob implements java.sql.Blob, java.io.Serializable { /** * Always refresh SerialVersionUID when prompted @@ -63,14 +60,13 @@ private static int nextInstanceID() { * Create a new BLOB * * @param connection - * the database connection this blob is implemented on + * the database connection this blob is implemented on * @param data - * the BLOB's data + * the BLOB's data * @deprecated Use {@link SQLServerConnection#createBlob()} instead. */ @Deprecated - public SQLServerBlob(SQLServerConnection connection, - byte data[]) { + public SQLServerBlob(SQLServerConnection connection, byte data[]) { traceID = " SQLServerBlob:" + nextInstanceID(); con = connection; @@ -114,9 +110,9 @@ public void free() throws SQLException { for (Closeable stream : activeStreams) { try { stream.close(); - } - catch (IOException ioException) { - logger.fine(toString() + " ignored IOException closing stream " + stream + ": " + ioException.getMessage()); + } catch (IOException ioException) { + logger.fine(toString() + " ignored IOException closing stream " + stream + ": " + + ioException.getMessage()); } } activeStreams = null; @@ -145,29 +141,26 @@ public InputStream getBinaryStream() throws SQLException { InputStream stream = (InputStream) activeStreams.get(0); try { stream.reset(); - } - catch (IOException e) { + } catch (IOException e) { throw new SQLServerException(e.getMessage(), null, 0, e); } return (InputStream) activeStreams.get(0); - } - else { + } else { if (value == null) { - throw new SQLServerException("Unexpected Error: blob value is null while all streams are closed.", null); + throw new SQLServerException("Unexpected Error: blob value is null while all streams are closed.", + null); } return getBinaryStreamInternal(0, value.length); } } @Override - public InputStream getBinaryStream(long pos, - long length) throws SQLException { + public InputStream getBinaryStream(long pos, long length) throws SQLException { SQLServerException.throwFeatureNotSupportedException(); return null; } - private InputStream getBinaryStreamInternal(int pos, - int length) { + private InputStream getBinaryStreamInternal(int pos, int length) { assert null != value; assert pos >= 0; assert 0 <= length && length <= value.length - pos; @@ -179,8 +172,7 @@ private InputStream getBinaryStreamInternal(int pos, } @Override - public byte[] getBytes(long pos, - int length) throws SQLException { + public byte[] getBytes(long pos, int length) throws SQLException { checkClosed(); getBytesFromStream(); @@ -239,8 +231,7 @@ private void getBytesFromStream() throws SQLServerException { BaseInputStream stream = (BaseInputStream) activeStreams.get(0); try { stream.reset(); - } - catch (IOException e) { + } catch (IOException e) { throw new SQLServerException(e.getMessage(), null, 0, e); } value = stream.getBytes(); @@ -248,8 +239,7 @@ private void getBytesFromStream() throws SQLServerException { } @Override - public long position(java.sql.Blob pattern, - long start) throws SQLException { + public long position(java.sql.Blob pattern, long start) throws SQLException { checkClosed(); getBytesFromStream(); @@ -266,8 +256,7 @@ public long position(java.sql.Blob pattern, } @Override - public long position(byte[] bPattern, - long start) throws SQLException { + public long position(byte[] bPattern, long start) throws SQLException { checkClosed(); getBytesFromStream(); if (start < 1) { @@ -334,27 +323,25 @@ public java.io.OutputStream setBinaryStream(long pos) throws SQLException { } @Override - public int setBytes(long pos, - byte[] bytes) throws SQLException { + public int setBytes(long pos, byte[] bytes) throws SQLException { checkClosed(); getBytesFromStream(); if (null == bytes) - SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_cantSetNull"), null, true); + SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_cantSetNull"), null, + true); return setBytes(pos, bytes, 0, bytes.length); } @Override - public int setBytes(long pos, - byte[] bytes, - int offset, - int len) throws SQLException { + public int setBytes(long pos, byte[] bytes, int offset, int len) throws SQLException { checkClosed(); getBytesFromStream(); if (null == bytes) - SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_cantSetNull"), null, true); + SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_cantSetNull"), null, + true); // Offset must be within incoming bytes boundary. if (offset < 0 || offset > bytes.length) { @@ -396,8 +383,7 @@ public int setBytes(long pos, // Copy rest of data. System.arraycopy(bytes, offset, combinedValue, (int) pos, len); value = combinedValue; - } - else { + } else { // Overwrite internal to value case. System.arraycopy(bytes, offset, value, (int) pos, len); } @@ -406,18 +392,19 @@ public int setBytes(long pos, } } + /** - * SQLServerBlobOutputStream is a simple java.io.OutputStream interface implementing class that forwards all calls to SQLServerBlob.setBytes. This - * class is returned to caller by SQLServerBlob class when setBinaryStream is called. + * SQLServerBlobOutputStream is a simple java.io.OutputStream interface implementing class that forwards all calls to + * SQLServerBlob.setBytes. This class is returned to caller by SQLServerBlob class when setBinaryStream is called. *

- * SQLServerBlobOutputStream starts writing at postion startPos and continues to write in a forward only manner. Reset/mark are not supported. + * SQLServerBlobOutputStream starts writing at postion startPos and continues to write in a forward only manner. + * Reset/mark are not supported. */ final class SQLServerBlobOutputStream extends java.io.OutputStream { private SQLServerBlob parentBlob = null; private long currentPos; - SQLServerBlobOutputStream(SQLServerBlob parentBlob, - long startPos) { + SQLServerBlobOutputStream(SQLServerBlob parentBlob, long startPos) { this.parentBlob = parentBlob; this.currentPos = startPos; } @@ -430,17 +417,14 @@ public void write(byte[] b) throws IOException { } @Override - public void write(byte[] b, - int off, - int len) throws IOException { + public void write(byte[] b, int off, int len) throws IOException { try { // Call parent's setBytes and update position. // setBytes can throw a SQLServerException, we translate // this to an IOException here. int bytesWritten = parentBlob.setBytes(currentPos, b, off, len); currentPos += bytesWritten; - } - catch (SQLException ex) { + } catch (SQLException ex) { throw new IOException(ex.getMessage()); } } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkBatchInsertRecord.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkBatchInsertRecord.java index 8ded138ac..3203f07f1 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkBatchInsertRecord.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkBatchInsertRecord.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -20,463 +17,417 @@ import java.util.HashMap; import java.util.List; import java.util.Map.Entry; - import java.util.Set; + /** - * A simple implementation of the ISQLServerBulkRecord interface that can be - * used to read in the basic Java data types from an ArrayList of Parameters - * that were provided by pstmt/cstmt. + * Provides a simple implementation of the ISQLServerBulkRecord interface that can be used to read in the basic Java + * data types from an ArrayList of Parameters that were provided by pstmt/cstmt. */ public class SQLServerBulkBatchInsertRecord extends SQLServerBulkCommon { - private List batchParam; - private int batchParamIndex = -1; - private List columnList; - private List valueList; - - /* - * Class name for logging. - */ - private static final String loggerClassName = "com.microsoft.sqlserver.jdbc.SQLServerBulkBatchInsertRecord"; - - /* - * Logger - */ - private static final java.util.logging.Logger loggerExternal = java.util.logging.Logger - .getLogger(loggerClassName); - - public SQLServerBulkBatchInsertRecord(ArrayList batchParam, - ArrayList columnList, ArrayList valueList, - String encoding) throws SQLServerException { - loggerExternal.entering(loggerClassName, - "SQLServerBulkBatchInsertRecord", - new Object[]{batchParam, encoding}); - - if (null == batchParam) { - throwInvalidArgument("batchParam"); - } - - if (null == valueList) { - throwInvalidArgument("valueList"); - } - - this.batchParam = batchParam; - this.columnList = columnList; - this.valueList = valueList; - columnMetadata = new HashMap<>(); - - loggerExternal.exiting(loggerClassName, - "SQLServerBulkBatchInsertRecord"); - } - - @Override - public DateTimeFormatter getColumnDateTimeFormatter(int column) { - return columnMetadata.get(column).dateTimeFormatter; - } - - @Override - public Set getColumnOrdinals() { - return columnMetadata.keySet(); - } - - @Override - public String getColumnName(int column) { - return columnMetadata.get(column).columnName; - } - - @Override - public int getColumnType(int column) { - return columnMetadata.get(column).columnType; - } - - @Override - public int getPrecision(int column) { - return columnMetadata.get(column).precision; - } - - @Override - public int getScale(int column) { - return columnMetadata.get(column).scale; - } - - @Override - public boolean isAutoIncrement(int column) { - return false; - } - - private Object convertValue(ColumnMetadata cm, Object data) - throws SQLServerException { - switch (cm.columnType) { - case Types.INTEGER : { - // Formatter to remove the decimal part as SQL Server floors the - // decimal in integer types - DecimalFormat decimalFormatter = new DecimalFormat("#"); - decimalFormatter.setRoundingMode(RoundingMode.DOWN); - String formatedfInput = decimalFormatter - .format(Double.parseDouble(data.toString())); - return Integer.valueOf(formatedfInput); - } - - case Types.TINYINT : - case Types.SMALLINT : { - // Formatter to remove the decimal part as SQL Server floors the - // decimal in integer types - DecimalFormat decimalFormatter = new DecimalFormat("#"); - decimalFormatter.setRoundingMode(RoundingMode.DOWN); - String formatedfInput = decimalFormatter - .format(Double.parseDouble(data.toString())); - return Short.valueOf(formatedfInput); - } - - case Types.BIGINT : { - BigDecimal bd = new BigDecimal(data.toString().trim()); - try { - return bd.setScale(0, RoundingMode.DOWN).longValueExact(); - } catch (ArithmeticException ex) { - String value = "'" + data + "'"; - MessageFormat form = new MessageFormat(SQLServerException - .getErrString("R_errorConvertingValue")); - throw new SQLServerException(form.format( - new Object[]{value, JDBCType.of(cm.columnType)}), - null, 0, ex); - } - } - - case Types.DECIMAL : - case Types.NUMERIC : { - BigDecimal bd = new BigDecimal(data.toString().trim()); - return bd.setScale(cm.scale, RoundingMode.HALF_UP); - } - - case Types.BIT : { - // "true" => 1, "false" => 0 - // Any non-zero value (integer/double) => 1, 0/0.0 => 0 - try { - return (0 == Double.parseDouble(data.toString())) - ? Boolean.FALSE - : Boolean.TRUE; - } catch (NumberFormatException e) { - return Boolean.parseBoolean(data.toString()); - } - } - - case Types.REAL : { - return Float.parseFloat(data.toString()); - } - - case Types.DOUBLE : { - return Double.parseDouble(data.toString()); - } - - case Types.BINARY : - case Types.VARBINARY : - case Types.LONGVARBINARY : - case Types.BLOB : { - // Strip off 0x if present. - String binData = data.toString().trim(); - if (binData.startsWith("0x") || binData.startsWith("0X")) { - return binData.substring(2); - } else { - return binData; - } - } - - case java.sql.Types.TIME_WITH_TIMEZONE : { - OffsetTime offsetTimeValue; - - // The per-column DateTimeFormatter gets priority. - if (null != cm.dateTimeFormatter) - offsetTimeValue = OffsetTime.parse(data.toString(), - cm.dateTimeFormatter); - else if (timeFormatter != null) - offsetTimeValue = OffsetTime.parse(data.toString(), - timeFormatter); - else - offsetTimeValue = OffsetTime.parse(data.toString()); - - return offsetTimeValue; - } - - case java.sql.Types.TIMESTAMP_WITH_TIMEZONE : { - OffsetDateTime offsetDateTimeValue; - - // The per-column DateTimeFormatter gets priority. - if (null != cm.dateTimeFormatter) - offsetDateTimeValue = OffsetDateTime.parse(data.toString(), - cm.dateTimeFormatter); - else if (dateTimeFormatter != null) - offsetDateTimeValue = OffsetDateTime.parse(data.toString(), - dateTimeFormatter); - else - offsetDateTimeValue = OffsetDateTime.parse(data.toString()); - - return offsetDateTimeValue; - } - - case Types.NULL : { - return null; - } - - case Types.DATE : - case Types.CHAR : - case Types.NCHAR : - case Types.VARCHAR : - case Types.NVARCHAR : - case Types.LONGVARCHAR : - case Types.LONGNVARCHAR : - case Types.CLOB : - default : { - // The string is copied as is. - return data; - } - } - } - - private String removeSingleQuote(String s) { - int len = s.length(); - return (s.charAt(0) == '\'' && s.charAt(len - 1) == '\'') - ? s.substring(1, len - 1) - : s; - } - - @Override - public Object[] getRowData() throws SQLServerException { - Object[] data = new Object[columnMetadata.size()]; - int valueIndex = 0; - String valueData; - Object rowData; - int columnListIndex = 0; - - // check if the size of the list of values = size of the list of columns - // (which is optional) - if (null != columnList && columnList.size() != valueList.size()) { - MessageFormat form = new MessageFormat( - SQLServerException.getErrString("R_DataSchemaMismatch")); - Object[] msgArgs = {}; - throw new SQLServerException(form.format(msgArgs), - SQLState.COL_NOT_FOUND, DriverError.NOT_SET, null); - } - - for (Entry pair : columnMetadata.entrySet()) { - int index = pair.getKey() - 1; - - // To explain what each variable represents: - // columnMetadata = map containing the ENTIRE list of columns in the - // table. - // columnList = the *optional* list of columns the user can provide. - // For example, the (c1, c3) part of this query: INSERT into t1 (c1, - // c3) values (?, ?) - // valueList = the *mandatory* list of columns the user needs - // provide. This is the (?, ?) part of the previous query. The size - // of this valueList will always equal the number of - // the entire columns in the table IF columnList has NOT been - // provided. If columnList HAS been provided, then this valueList - // may be smaller than the list of all columns (which is - // columnMetadata). - - // case when the user has not provided the optional list of column - // names. - if (null == columnList || columnList.size() == 0) { - valueData = valueList.get(index); - // if the user has provided a wildcard for this column, fetch - // the set value from the batchParam. - if (valueData.equalsIgnoreCase("?")) { - rowData = batchParam.get(batchParamIndex)[valueIndex++] - .getSetterValue(); - } else if (valueData.equalsIgnoreCase("null")) { - rowData = null; - } - // if the user has provided a hardcoded value for this column, - // rowData is simply set to the hardcoded value. - else { - rowData = removeSingleQuote(valueData); - } - } - // case when the user has provided the optional list of column - // names. - else { - // columnListIndex is a separate counter we need to keep track - // of for each time we've processed a column - // that the user provided. - // for example, if the user provided an optional columnList of - // (c1, c3, c5, c7) in a table that has 8 columns (c1~c8), - // then the columnListIndex would increment only when we're - // dealing with the four columns inside columnMetadata. - // compare the list of the optional list of column names to the - // table's metadata, and match each other, so we assign the - // correct value to each column. - if (columnList.size() > columnListIndex - && columnList.get(columnListIndex).equalsIgnoreCase( - columnMetadata.get(index + 1).columnName)) { - valueData = valueList.get(columnListIndex); - if (valueData.equalsIgnoreCase("?")) { - rowData = batchParam.get(batchParamIndex)[valueIndex++] - .getSetterValue(); - } else if (valueData.equalsIgnoreCase("null")) { - rowData = null; - } else { - rowData = removeSingleQuote(valueData); - } - columnListIndex++; - } else { - rowData = null; - } - } - - try { - if (null == rowData) { - data[index] = null; - continue; - } else if (0 == rowData.toString().length()) { - data[index] = ""; - continue; - } - data[index] = convertValue(pair.getValue(), rowData); - } catch (IllegalArgumentException e) { - String value = "'" + rowData + "'"; - MessageFormat form = new MessageFormat(SQLServerException - .getErrString("R_errorConvertingValue")); - throw new SQLServerException( - form.format(new Object[]{value, - JDBCType.of(pair.getValue().columnType)}), - null, 0, e); - } catch (ArrayIndexOutOfBoundsException e) { - throw new SQLServerException( - SQLServerException.getErrString("R_DataSchemaMismatch"), - e); - } - } - return data; - } - - @Override - void addColumnMetadataInternal(int positionInSource, String name, - int jdbcType, int precision, int scale, - DateTimeFormatter dateTimeFormatter) throws SQLServerException { - loggerExternal.entering(loggerClassName, "addColumnMetadata", - new Object[]{positionInSource, name, jdbcType, precision, - scale}); - - String colName = ""; - - if (0 >= positionInSource) { - MessageFormat form = new MessageFormat( - SQLServerException.getErrString("R_invalidColumnOrdinal")); - Object[] msgArgs = {positionInSource}; - throw new SQLServerException(form.format(msgArgs), - SQLState.COL_NOT_FOUND, DriverError.NOT_SET, null); - } - - if (null != name) - colName = name.trim(); - else if ((null != columnNames) - && (columnNames.length >= positionInSource)) - colName = columnNames[positionInSource - 1]; - - if ((null != columnNames) && (positionInSource > columnNames.length)) { - MessageFormat form = new MessageFormat( - SQLServerException.getErrString("R_invalidColumn")); - Object[] msgArgs = {positionInSource}; - throw new SQLServerException(form.format(msgArgs), - SQLState.COL_NOT_FOUND, DriverError.NOT_SET, null); - } - - checkDuplicateColumnName(positionInSource, name); - switch (jdbcType) { - /* - * SQL Server supports numerous string literal formats for temporal - * types, hence sending them as varchar with approximate - * precision(length) needed to send supported string literals. - * string literal formats supported by temporal types are available - * in MSDN page on data types. - */ - case java.sql.Types.DATE : - case java.sql.Types.TIME : - case java.sql.Types.TIMESTAMP : - case microsoft.sql.Types.DATETIMEOFFSET : - columnMetadata.put(positionInSource, new ColumnMetadata(colName, - jdbcType, precision, scale, dateTimeFormatter)); - break; - - // Redirect SQLXML as LONGNVARCHAR - // SQLXML is not valid type in TDS - case java.sql.Types.SQLXML : - columnMetadata.put(positionInSource, - new ColumnMetadata(colName, java.sql.Types.LONGNVARCHAR, - precision, scale, dateTimeFormatter)); - break; - - // Redirecting Float as Double based on data type mapping - // https://msdn.microsoft.com/en-us/library/ms378878%28v=sql.110%29.aspx - case java.sql.Types.FLOAT : - columnMetadata.put(positionInSource, - new ColumnMetadata(colName, java.sql.Types.DOUBLE, - precision, scale, dateTimeFormatter)); - break; - - // redirecting BOOLEAN as BIT - case java.sql.Types.BOOLEAN : - columnMetadata.put(positionInSource, - new ColumnMetadata(colName, java.sql.Types.BIT, - precision, scale, dateTimeFormatter)); - break; - - default : - columnMetadata.put(positionInSource, new ColumnMetadata(colName, - jdbcType, precision, scale, dateTimeFormatter)); - } - - loggerExternal.exiting(loggerClassName, "addColumnMetadata"); - } - - @Override - public void setTimestampWithTimezoneFormat(String dateTimeFormat) { - loggerExternal.entering(loggerClassName, - "setTimestampWithTimezoneFormat", dateTimeFormat); - - super.setTimestampWithTimezoneFormat(dateTimeFormat); - - loggerExternal.exiting(loggerClassName, - "setTimestampWithTimezoneFormat"); - } - - @Override - public void setTimestampWithTimezoneFormat( - DateTimeFormatter dateTimeFormatter) { - loggerExternal.entering(loggerClassName, - "setTimestampWithTimezoneFormat", - new Object[]{dateTimeFormatter}); - - super.setTimestampWithTimezoneFormat(dateTimeFormatter); - - loggerExternal.exiting(loggerClassName, - "setTimestampWithTimezoneFormat"); - } - - @Override - public void setTimeWithTimezoneFormat(String timeFormat) { - loggerExternal.entering(loggerClassName, "setTimeWithTimezoneFormat", - timeFormat); - - super.setTimeWithTimezoneFormat(timeFormat); - - loggerExternal.exiting(loggerClassName, "setTimeWithTimezoneFormat"); - } - - @Override - public void setTimeWithTimezoneFormat(DateTimeFormatter dateTimeFormatter) { - loggerExternal.entering(loggerClassName, "setTimeWithTimezoneFormat", - new Object[]{dateTimeFormatter}); - - super.setTimeWithTimezoneFormat(dateTimeFormatter); - - loggerExternal.exiting(loggerClassName, "setTimeWithTimezoneFormat"); - } - - @Override - public boolean next() throws SQLServerException { - batchParamIndex++; - return batchParamIndex < batchParam.size(); - } + private List batchParam; + private int batchParamIndex = -1; + private List columnList; + private List valueList; + + /* + * Class name for logging. + */ + private static final String loggerClassName = "com.microsoft.sqlserver.jdbc.SQLServerBulkBatchInsertRecord"; + + /* + * Logger + */ + private static final java.util.logging.Logger loggerExternal = java.util.logging.Logger.getLogger(loggerClassName); + + /* + * Constructs a SQLServerBulkBatchInsertRecord with the batch parameter, column list, value list, and encoding + */ + public SQLServerBulkBatchInsertRecord(ArrayList batchParam, ArrayList columnList, + ArrayList valueList, String encoding) throws SQLServerException { + loggerExternal.entering(loggerClassName, "SQLServerBulkBatchInsertRecord", new Object[] {batchParam, encoding}); + + if (null == batchParam) { + throwInvalidArgument("batchParam"); + } + + if (null == valueList) { + throwInvalidArgument("valueList"); + } + + this.batchParam = batchParam; + this.columnList = columnList; + this.valueList = valueList; + columnMetadata = new HashMap<>(); + + loggerExternal.exiting(loggerClassName, "SQLServerBulkBatchInsertRecord"); + } + + @Override + public DateTimeFormatter getColumnDateTimeFormatter(int column) { + return columnMetadata.get(column).dateTimeFormatter; + } + + @Override + public Set getColumnOrdinals() { + return columnMetadata.keySet(); + } + + @Override + public String getColumnName(int column) { + return columnMetadata.get(column).columnName; + } + + @Override + public int getColumnType(int column) { + return columnMetadata.get(column).columnType; + } + + @Override + public int getPrecision(int column) { + return columnMetadata.get(column).precision; + } + + @Override + public int getScale(int column) { + return columnMetadata.get(column).scale; + } + + @Override + public boolean isAutoIncrement(int column) { + return false; + } + + private Object convertValue(ColumnMetadata cm, Object data) throws SQLServerException { + switch (cm.columnType) { + case Types.INTEGER: { + // Formatter to remove the decimal part as SQL Server floors the + // decimal in integer types + DecimalFormat decimalFormatter = new DecimalFormat("#"); + decimalFormatter.setRoundingMode(RoundingMode.DOWN); + String formatedfInput = decimalFormatter.format(Double.parseDouble(data.toString())); + return Integer.valueOf(formatedfInput); + } + + case Types.TINYINT: + case Types.SMALLINT: { + // Formatter to remove the decimal part as SQL Server floors the + // decimal in integer types + DecimalFormat decimalFormatter = new DecimalFormat("#"); + decimalFormatter.setRoundingMode(RoundingMode.DOWN); + String formatedfInput = decimalFormatter.format(Double.parseDouble(data.toString())); + return Short.valueOf(formatedfInput); + } + + case Types.BIGINT: { + BigDecimal bd = new BigDecimal(data.toString().trim()); + try { + return bd.setScale(0, RoundingMode.DOWN).longValueExact(); + } catch (ArithmeticException ex) { + String value = "'" + data + "'"; + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_errorConvertingValue")); + throw new SQLServerException(form.format(new Object[] {value, JDBCType.of(cm.columnType)}), null, 0, + ex); + } + } + + case Types.DECIMAL: + case Types.NUMERIC: { + BigDecimal bd = new BigDecimal(data.toString().trim()); + return bd.setScale(cm.scale, RoundingMode.HALF_UP); + } + + case Types.BIT: { + // "true" => 1, "false" => 0 + // Any non-zero value (integer/double) => 1, 0/0.0 => 0 + try { + return (0 == Double.parseDouble(data.toString())) ? Boolean.FALSE : Boolean.TRUE; + } catch (NumberFormatException e) { + return Boolean.parseBoolean(data.toString()); + } + } + + case Types.REAL: { + return Float.parseFloat(data.toString()); + } + + case Types.DOUBLE: { + return Double.parseDouble(data.toString()); + } + + case Types.BINARY: + case Types.VARBINARY: + case Types.LONGVARBINARY: + case Types.BLOB: { + // Strip off 0x if present. + String binData = data.toString().trim(); + if (binData.startsWith("0x") || binData.startsWith("0X")) { + return binData.substring(2); + } else { + return binData; + } + } + + case java.sql.Types.TIME_WITH_TIMEZONE: { + OffsetTime offsetTimeValue; + + // The per-column DateTimeFormatter gets priority. + if (null != cm.dateTimeFormatter) + offsetTimeValue = OffsetTime.parse(data.toString(), cm.dateTimeFormatter); + else if (timeFormatter != null) + offsetTimeValue = OffsetTime.parse(data.toString(), timeFormatter); + else + offsetTimeValue = OffsetTime.parse(data.toString()); + + return offsetTimeValue; + } + + case java.sql.Types.TIMESTAMP_WITH_TIMEZONE: { + OffsetDateTime offsetDateTimeValue; + + // The per-column DateTimeFormatter gets priority. + if (null != cm.dateTimeFormatter) + offsetDateTimeValue = OffsetDateTime.parse(data.toString(), cm.dateTimeFormatter); + else if (dateTimeFormatter != null) + offsetDateTimeValue = OffsetDateTime.parse(data.toString(), dateTimeFormatter); + else + offsetDateTimeValue = OffsetDateTime.parse(data.toString()); + + return offsetDateTimeValue; + } + + case Types.NULL: { + return null; + } + + case Types.DATE: + case Types.CHAR: + case Types.NCHAR: + case Types.VARCHAR: + case Types.NVARCHAR: + case Types.LONGVARCHAR: + case Types.LONGNVARCHAR: + case Types.CLOB: + default: { + // The string is copied as is. + return data; + } + } + } + + private String removeSingleQuote(String s) { + int len = s.length(); + return (s.charAt(0) == '\'' && s.charAt(len - 1) == '\'') ? s.substring(1, len - 1) : s; + } + + @Override + public Object[] getRowData() throws SQLServerException { + Object[] data = new Object[columnMetadata.size()]; + int valueIndex = 0; + String valueData; + Object rowData; + int columnListIndex = 0; + + // check if the size of the list of values = size of the list of columns + // (which is optional) + if (null != columnList && columnList.size() != valueList.size()) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_DataSchemaMismatch")); + Object[] msgArgs = {}; + throw new SQLServerException(form.format(msgArgs), SQLState.COL_NOT_FOUND, DriverError.NOT_SET, null); + } + + for (Entry pair : columnMetadata.entrySet()) { + int index = pair.getKey() - 1; + + // To explain what each variable represents: + // columnMetadata = map containing the ENTIRE list of columns in the + // table. + // columnList = the *optional* list of columns the user can provide. + // For example, the (c1, c3) part of this query: INSERT into t1 (c1, + // c3) values (?, ?) + // valueList = the *mandatory* list of columns the user needs + // provide. This is the (?, ?) part of the previous query. The size + // of this valueList will always equal the number of + // the entire columns in the table IF columnList has NOT been + // provided. If columnList HAS been provided, then this valueList + // may be smaller than the list of all columns (which is + // columnMetadata). + + // case when the user has not provided the optional list of column + // names. + if (null == columnList || columnList.size() == 0) { + valueData = valueList.get(index); + // if the user has provided a wildcard for this column, fetch + // the set value from the batchParam. + if (valueData.equalsIgnoreCase("?")) { + rowData = batchParam.get(batchParamIndex)[valueIndex++].getSetterValue(); + } else if (valueData.equalsIgnoreCase("null")) { + rowData = null; + } + // if the user has provided a hardcoded value for this column, + // rowData is simply set to the hardcoded value. + else { + rowData = removeSingleQuote(valueData); + } + } + // case when the user has provided the optional list of column + // names. + else { + // columnListIndex is a separate counter we need to keep track + // of for each time we've processed a column + // that the user provided. + // for example, if the user provided an optional columnList of + // (c1, c3, c5, c7) in a table that has 8 columns (c1~c8), + // then the columnListIndex would increment only when we're + // dealing with the four columns inside columnMetadata. + // compare the list of the optional list of column names to the + // table's metadata, and match each other, so we assign the + // correct value to each column. + if (columnList.size() > columnListIndex + && columnList.get(columnListIndex).equalsIgnoreCase(columnMetadata.get(index + 1).columnName)) { + valueData = valueList.get(columnListIndex); + if (valueData.equalsIgnoreCase("?")) { + rowData = batchParam.get(batchParamIndex)[valueIndex++].getSetterValue(); + } else if (valueData.equalsIgnoreCase("null")) { + rowData = null; + } else { + rowData = removeSingleQuote(valueData); + } + columnListIndex++; + } else { + rowData = null; + } + } + + try { + if (null == rowData) { + data[index] = null; + continue; + } else if (0 == rowData.toString().length()) { + data[index] = ""; + continue; + } + data[index] = convertValue(pair.getValue(), rowData); + } catch (IllegalArgumentException e) { + String value = "'" + rowData + "'"; + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_errorConvertingValue")); + throw new SQLServerException(form.format(new Object[] {value, JDBCType.of(pair.getValue().columnType)}), + null, 0, e); + } catch (ArrayIndexOutOfBoundsException e) { + throw new SQLServerException(SQLServerException.getErrString("R_DataSchemaMismatch"), e); + } + } + return data; + } + + @Override + void addColumnMetadataInternal(int positionInSource, String name, int jdbcType, int precision, int scale, + DateTimeFormatter dateTimeFormatter) throws SQLServerException { + loggerExternal.entering(loggerClassName, "addColumnMetadata", + new Object[] {positionInSource, name, jdbcType, precision, scale}); + + String colName = ""; + + if (0 >= positionInSource) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidColumnOrdinal")); + Object[] msgArgs = {positionInSource}; + throw new SQLServerException(form.format(msgArgs), SQLState.COL_NOT_FOUND, DriverError.NOT_SET, null); + } + + if (null != name) + colName = name.trim(); + else if ((null != columnNames) && (columnNames.length >= positionInSource)) + colName = columnNames[positionInSource - 1]; + + if ((null != columnNames) && (positionInSource > columnNames.length)) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidColumn")); + Object[] msgArgs = {positionInSource}; + throw new SQLServerException(form.format(msgArgs), SQLState.COL_NOT_FOUND, DriverError.NOT_SET, null); + } + + checkDuplicateColumnName(positionInSource, name); + switch (jdbcType) { + /* + * SQL Server supports numerous string literal formats for temporal types, hence sending them as varchar + * with approximate precision(length) needed to send supported string literals. string literal formats + * supported by temporal types are available in MSDN page on data types. + */ + case java.sql.Types.DATE: + case java.sql.Types.TIME: + case java.sql.Types.TIMESTAMP: + case microsoft.sql.Types.DATETIMEOFFSET: + columnMetadata.put(positionInSource, + new ColumnMetadata(colName, jdbcType, precision, scale, dateTimeFormatter)); + break; + + // Redirect SQLXML as LONGNVARCHAR + // SQLXML is not valid type in TDS + case java.sql.Types.SQLXML: + columnMetadata.put(positionInSource, + new ColumnMetadata(colName, java.sql.Types.LONGNVARCHAR, precision, scale, dateTimeFormatter)); + break; + + // Redirecting Float as Double based on data type mapping + // https://msdn.microsoft.com/en-us/library/ms378878%28v=sql.110%29.aspx + case java.sql.Types.FLOAT: + columnMetadata.put(positionInSource, + new ColumnMetadata(colName, java.sql.Types.DOUBLE, precision, scale, dateTimeFormatter)); + break; + + // redirecting BOOLEAN as BIT + case java.sql.Types.BOOLEAN: + columnMetadata.put(positionInSource, + new ColumnMetadata(colName, java.sql.Types.BIT, precision, scale, dateTimeFormatter)); + break; + + default: + columnMetadata.put(positionInSource, + new ColumnMetadata(colName, jdbcType, precision, scale, dateTimeFormatter)); + } + + loggerExternal.exiting(loggerClassName, "addColumnMetadata"); + } + + @Override + public void setTimestampWithTimezoneFormat(String dateTimeFormat) { + loggerExternal.entering(loggerClassName, "setTimestampWithTimezoneFormat", dateTimeFormat); + + super.setTimestampWithTimezoneFormat(dateTimeFormat); + + loggerExternal.exiting(loggerClassName, "setTimestampWithTimezoneFormat"); + } + + @Override + public void setTimestampWithTimezoneFormat(DateTimeFormatter dateTimeFormatter) { + loggerExternal.entering(loggerClassName, "setTimestampWithTimezoneFormat", new Object[] {dateTimeFormatter}); + + super.setTimestampWithTimezoneFormat(dateTimeFormatter); + + loggerExternal.exiting(loggerClassName, "setTimestampWithTimezoneFormat"); + } + + @Override + public void setTimeWithTimezoneFormat(String timeFormat) { + loggerExternal.entering(loggerClassName, "setTimeWithTimezoneFormat", timeFormat); + + super.setTimeWithTimezoneFormat(timeFormat); + + loggerExternal.exiting(loggerClassName, "setTimeWithTimezoneFormat"); + } + + @Override + public void setTimeWithTimezoneFormat(DateTimeFormatter dateTimeFormatter) { + loggerExternal.entering(loggerClassName, "setTimeWithTimezoneFormat", new Object[] {dateTimeFormatter}); + + super.setTimeWithTimezoneFormat(dateTimeFormatter); + + loggerExternal.exiting(loggerClassName, "setTimeWithTimezoneFormat"); + } + + @Override + public boolean next() throws SQLServerException { + batchParamIndex++; + return batchParamIndex < batchParam.size(); + } } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCSVFileRecord.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCSVFileRecord.java index 31e101463..ac84bc58d 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCSVFileRecord.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCSVFileRecord.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -24,12 +21,12 @@ import java.time.format.DateTimeFormatter; import java.util.HashMap; import java.util.Map.Entry; - import java.util.Set; + /** - * A simple implementation of the ISQLServerBulkRecord interface that can be used to read in the basic Java data types from a delimited file where - * each line represents a row of data. + * Provides a simple implementation of the ISQLServerBulkRecord interface that can be used to read in the basic Java + * data types from a delimited file where each line represents a row of data. */ public class SQLServerBulkCSVFileRecord extends SQLServerBulkCommon implements java.lang.AutoCloseable { /* @@ -60,30 +57,27 @@ public class SQLServerBulkCSVFileRecord extends SQLServerBulkCommon implements j private static final java.util.logging.Logger loggerExternal = java.util.logging.Logger.getLogger(loggerClassName); /** - * Creates a simple reader to parse data from a delimited file with the given encoding. + * Constructs a simple reader to parse data from a delimited file with the given encoding. * * @param fileToParse - * File to parse data from + * File to parse data from * @param encoding - * Charset encoding to use for reading the file, or NULL for the default encoding. + * Charset encoding to use for reading the file, or NULL for the default encoding. * @param delimiter - * Delimiter to used to separate each column + * Delimiter to used to separate each column * @param firstLineIsColumnNames - * True if the first line of the file should be parsed as column names; false otherwise + * True if the first line of the file should be parsed as column names; false otherwise * @throws SQLServerException - * If the arguments are invalid, there are any errors in reading the file, or the file is empty + * If the arguments are invalid, there are any errors in reading the file, or the file is empty */ - public SQLServerBulkCSVFileRecord(String fileToParse, - String encoding, - String delimiter, + public SQLServerBulkCSVFileRecord(String fileToParse, String encoding, String delimiter, boolean firstLineIsColumnNames) throws SQLServerException { loggerExternal.entering(loggerClassName, "SQLServerBulkCSVFileRecord", new Object[] {fileToParse, encoding, delimiter, firstLineIsColumnNames}); if (null == fileToParse) { throwInvalidArgument("fileToParse"); - } - else if (null == delimiter) { + } else if (null == delimiter) { throwInvalidArgument("delimiter"); } @@ -93,8 +87,7 @@ else if (null == delimiter) { fis = new FileInputStream(fileToParse); if (null == encoding || 0 == encoding.length()) { sr = new InputStreamReader(fis); - } - else { + } else { sr = new InputStreamReader(fis, encoding); } @@ -106,12 +99,10 @@ else if (null == delimiter) { columnNames = currentLine.split(delimiter, -1); } } - } - catch (UnsupportedEncodingException unsupportedEncoding) { + } catch (UnsupportedEncodingException unsupportedEncoding) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_unsupportedEncoding")); throw new SQLServerException(form.format(new Object[] {encoding}), null, 0, unsupportedEncoding); - } - catch (Exception e) { + } catch (Exception e) { throw new SQLServerException(null, e.getMessage(), null, 0, false); } columnMetadata = new HashMap<>(); @@ -120,30 +111,27 @@ else if (null == delimiter) { } /** - * Creates a simple reader to parse data from a delimited file with the given encoding. + * Constructs a SQLServerBulkCSVFileRecord to parse data from a delimited file with the given encoding. * * @param fileToParse - * InputStream to parse data from + * InputStream to parse data from * @param encoding - * Charset encoding to use for reading the file, or NULL for the default encoding. + * Charset encoding to use for reading the file, or NULL for the default encoding. * @param delimiter - * Delimiter to used to separate each column + * Delimiter to used to separate each column * @param firstLineIsColumnNames - * True if the first line of the file should be parsed as column names; false otherwise + * True if the first line of the file should be parsed as column names; false otherwise * @throws SQLServerException - * If the arguments are invalid, there are any errors in reading the file, or the file is empty + * If the arguments are invalid, there are any errors in reading the file, or the file is empty */ - public SQLServerBulkCSVFileRecord(InputStream fileToParse, - String encoding, - String delimiter, + public SQLServerBulkCSVFileRecord(InputStream fileToParse, String encoding, String delimiter, boolean firstLineIsColumnNames) throws SQLServerException { loggerExternal.entering(loggerClassName, "SQLServerBulkCSVFileRecord", new Object[] {fileToParse, encoding, delimiter, firstLineIsColumnNames}); if (null == fileToParse) { throwInvalidArgument("fileToParse"); - } - else if (null == delimiter) { + } else if (null == delimiter) { throwInvalidArgument("delimiter"); } @@ -151,8 +139,7 @@ else if (null == delimiter) { try { if (null == encoding || 0 == encoding.length()) { sr = new InputStreamReader(fileToParse); - } - else { + } else { sr = new InputStreamReader(fileToParse, encoding); } fileReader = new BufferedReader(sr); @@ -163,12 +150,10 @@ else if (null == delimiter) { columnNames = currentLine.split(delimiter, -1); } } - } - catch (UnsupportedEncodingException unsupportedEncoding) { + } catch (UnsupportedEncodingException unsupportedEncoding) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_unsupportedEncoding")); throw new SQLServerException(form.format(new Object[] {encoding}), null, 0, unsupportedEncoding); - } - catch (Exception e) { + } catch (Exception e) { throw new SQLServerException(null, e.getMessage(), null, 0, false); } columnMetadata = new HashMap<>(); @@ -177,35 +162,33 @@ else if (null == delimiter) { } /** - * Creates a simple reader to parse data from a CSV file with the given encoding. + * Constructs a SQLServerBulkCSVFileRecord to parse data from a CSV file with the given encoding. * * @param fileToParse - * File to parse data from + * File to parse data from * @param encoding - * Charset encoding to use for reading the file. + * Charset encoding to use for reading the file. * @param firstLineIsColumnNames - * True if the first line of the file should be parsed as column names; false otherwise + * True if the first line of the file should be parsed as column names; false otherwise * @throws SQLServerException - * If the arguments are invalid, there are any errors in reading the file, or the file is empty + * If the arguments are invalid, there are any errors in reading the file, or the file is empty */ - public SQLServerBulkCSVFileRecord(String fileToParse, - String encoding, + public SQLServerBulkCSVFileRecord(String fileToParse, String encoding, boolean firstLineIsColumnNames) throws SQLServerException { this(fileToParse, encoding, ",", firstLineIsColumnNames); } /** - * Creates a simple reader to parse data from a CSV file with the default encoding. + * Constructs a SQLServerBulkCSVFileRecord to parse data from a CSV file with the default encoding. * * @param fileToParse - * File to parse data from + * File to parse data from * @param firstLineIsColumnNames - * True if the first line of the file should be parsed as column names; false otherwise + * True if the first line of the file should be parsed as column names; false otherwise * @throws SQLServerException - * If the arguments are invalid, there are any errors in reading the file, or the file is empty + * If the arguments are invalid, there are any errors in reading the file, or the file is empty */ - public SQLServerBulkCSVFileRecord(String fileToParse, - boolean firstLineIsColumnNames) throws SQLServerException { + public SQLServerBulkCSVFileRecord(String fileToParse, boolean firstLineIsColumnNames) throws SQLServerException { this(fileToParse, null, ",", firstLineIsColumnNames); } @@ -213,7 +196,7 @@ public SQLServerBulkCSVFileRecord(String fileToParse, * Releases any resources associated with the file reader. * * @throws SQLServerException - * when an error occurs + * when an error occurs */ public void close() throws SQLServerException { loggerExternal.entering(loggerClassName, "close"); @@ -222,21 +205,15 @@ public void close() throws SQLServerException { if (fileReader != null) try { fileReader.close(); - } - catch (Exception e) { - } + } catch (Exception e) {} if (sr != null) try { sr.close(); - } - catch (Exception e) { - } + } catch (Exception e) {} if (fis != null) try { fis.close(); - } - catch (Exception e) { - } + } catch (Exception e) {} loggerExternal.exiting(loggerClassName, "close"); } @@ -299,14 +276,16 @@ public Object[] getRowData() throws SQLServerException { if (data.length < pair.getKey() - 1) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidColumn")); Object[] msgArgs = {pair.getKey()}; - throw new SQLServerException(form.format(msgArgs), SQLState.COL_NOT_FOUND, DriverError.NOT_SET, null); + throw new SQLServerException(form.format(msgArgs), SQLState.COL_NOT_FOUND, DriverError.NOT_SET, + null); } // Source header has more columns than current line read if (columnNames != null && (columnNames.length > data.length)) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_DataSchemaMismatch")); Object[] msgArgs = {}; - throw new SQLServerException(form.format(msgArgs), SQLState.COL_NOT_FOUND, DriverError.NOT_SET, null); + throw new SQLServerException(form.format(msgArgs), SQLState.COL_NOT_FOUND, DriverError.NOT_SET, + null); } try { @@ -317,15 +296,16 @@ public Object[] getRowData() throws SQLServerException { switch (cm.columnType) { /* - * Both BCP and BULK INSERT considers double quotes as part of the data and throws error if any data (say "10") is to be - * inserted into an numeric column. Our implementation does the same. + * Both BCP and BULK INSERT considers double quotes as part of the data and throws error if any + * data (say "10") is to be inserted into an numeric column. Our implementation does the same. */ case Types.INTEGER: { // Formatter to remove the decimal part as SQL // Server floors the decimal in integer types DecimalFormat decimalFormatter = new DecimalFormat("#"); decimalFormatter.setRoundingMode(RoundingMode.DOWN); - String formatedfInput = decimalFormatter.format(Double.parseDouble(data[pair.getKey() - 1])); + String formatedfInput = decimalFormatter + .format(Double.parseDouble(data[pair.getKey() - 1])); dataRow[pair.getKey() - 1] = Integer.valueOf(formatedfInput); break; } @@ -336,7 +316,8 @@ public Object[] getRowData() throws SQLServerException { // Server floors the decimal in integer types DecimalFormat decimalFormatter = new DecimalFormat("#"); decimalFormatter.setRoundingMode(RoundingMode.DOWN); - String formatedfInput = decimalFormatter.format(Double.parseDouble(data[pair.getKey() - 1])); + String formatedfInput = decimalFormatter + .format(Double.parseDouble(data[pair.getKey() - 1])); dataRow[pair.getKey() - 1] = Short.valueOf(formatedfInput); break; } @@ -345,11 +326,12 @@ public Object[] getRowData() throws SQLServerException { BigDecimal bd = new BigDecimal(data[pair.getKey() - 1].trim()); try { dataRow[pair.getKey() - 1] = bd.setScale(0, RoundingMode.DOWN).longValueExact(); - } - catch (ArithmeticException ex) { + } catch (ArithmeticException ex) { String value = "'" + data[pair.getKey() - 1] + "'"; - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_errorConvertingValue")); - throw new SQLServerException(form.format(new Object[] {value, JDBCType.of(cm.columnType)}), null, 0, ex); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_errorConvertingValue")); + throw new SQLServerException( + form.format(new Object[] {value, JDBCType.of(cm.columnType)}), null, 0, ex); } break; } @@ -366,9 +348,10 @@ public Object[] getRowData() throws SQLServerException { // Any non-zero value (integer/double) => 1, 0/0.0 // => 0 try { - dataRow[pair.getKey() - 1] = (0 == Double.parseDouble(data[pair.getKey() - 1])) ? Boolean.FALSE : Boolean.TRUE; - } - catch (NumberFormatException e) { + dataRow[pair.getKey() + - 1] = (0 == Double.parseDouble(data[pair.getKey() - 1])) ? Boolean.FALSE + : Boolean.TRUE; + } catch (NumberFormatException e) { dataRow[pair.getKey() - 1] = Boolean.parseBoolean(data[pair.getKey() - 1]); } break; @@ -389,18 +372,19 @@ public Object[] getRowData() throws SQLServerException { case Types.LONGVARBINARY: case Types.BLOB: { /* - * For binary data, the value in file may or may not have the '0x' prefix. We will try to match our implementation with - * 'BULK INSERT' except that we will allow 0x prefix whereas 'BULK INSERT' command does not allow 0x prefix. A BULK INSERT - * example: A sample csv file containing data for 2 binary columns and 1 row: 61,62 Table definition: create table t1(c1 - * varbinary(10), c2 varbinary(10)) BULK INSERT command: bulk insert t1 from 'C:\in.csv' - * with(DATAFILETYPE='char',firstrow=1, FIELDTERMINATOR=',') select * from t1 shows 1 row with columns: 0x61, 0x62 + * For binary data, the value in file may or may not have the '0x' prefix. We will try to + * match our implementation with 'BULK INSERT' except that we will allow 0x prefix whereas + * 'BULK INSERT' command does not allow 0x prefix. A BULK INSERT example: A sample csv file + * containing data for 2 binary columns and 1 row: 61,62 Table definition: create table + * t1(c1 varbinary(10), c2 varbinary(10)) BULK INSERT command: bulk insert t1 from + * 'C:\in.csv' with(DATAFILETYPE='char',firstrow=1, FIELDTERMINATOR=',') select * from t1 + * shows 1 row with columns: 0x61, 0x62 */ // Strip off 0x if present. String binData = data[pair.getKey() - 1].trim(); if (binData.startsWith("0x") || binData.startsWith("0X")) { dataRow[pair.getKey() - 1] = binData.substring(2); - } - else { + } else { dataRow[pair.getKey() - 1] = binData; } break; @@ -426,7 +410,8 @@ else if (timeFormatter != null) // The per-column DateTimeFormatter gets priority. if (null != cm.dateTimeFormatter) - offsetDateTimeValue = OffsetDateTime.parse(data[pair.getKey() - 1], cm.dateTimeFormatter); + offsetDateTimeValue = OffsetDateTime.parse(data[pair.getKey() - 1], + cm.dateTimeFormatter); else if (dateTimeFormatter != null) offsetDateTimeValue = OffsetDateTime.parse(data[pair.getKey() - 1], dateTimeFormatter); else @@ -452,28 +437,29 @@ else if (dateTimeFormatter != null) default: { // The string is copied as is. /* - * Handling double quotes: Both BCP (without a format file) and BULK INSERT behaves the same way for double quotes. They - * treat double quotes as part of the data. For a CSV file as follows, data is inserted as is: ""abc"" "abc" abc a"b"c - * a""b""c Excel on the other hand, shows data as follows. It strips off beginning and ending quotes, and sometimes quotes - * get messed up. When the same CSV is saved from Excel again, Excel adds additional quotes. abc"" abc abc a"b"c a""b""c - * In our implementation we will match the behavior with BCP and BULK INSERT. BCP command: bcp table1 in in.csv -c -t , -r - * 0x0A -S localhost -U sa -P BULK INSERT command: bulk insert table1 from 'in.csv' with (FIELDTERMINATOR=',') - * - * Handling delimiters in data: Excel allows comma in data when data is surrounded with quotes. For example, - * "Hello, world" is treated as one cell. BCP and BULK INSERT deos not allow field terminators in data: - * https://technet.microsoft.com/en-us/library/ aa196735%28v=sql.80%29.aspx?f=255&MSPPError=- 2147217396 + * Handling double quotes: Both BCP (without a format file) and BULK INSERT behaves the same + * way for double quotes. They treat double quotes as part of the data. For a CSV file as + * follows, data is inserted as is: ""abc"" "abc" abc a"b"c a""b""c Excel on the other hand, + * shows data as follows. It strips off beginning and ending quotes, and sometimes quotes + * get messed up. When the same CSV is saved from Excel again, Excel adds additional quotes. + * abc"" abc abc a"b"c a""b""c In our implementation we will match the behavior with BCP and + * BULK INSERT. BCP command: bcp table1 in in.csv -c -t , -r 0x0A -S localhost -U sa -P + * BULK INSERT command: bulk insert table1 from 'in.csv' with (FIELDTERMINATOR=',') + * Handling delimiters in data: Excel allows comma in data when data is surrounded with + * quotes. For example, "Hello, world" is treated as one cell. BCP and BULK INSERT deos not + * allow field terminators in data: https://technet.microsoft.com/en-us/library/ + * aa196735%28v=sql.80%29.aspx?f=255&MSPPError=- 2147217396 */ dataRow[pair.getKey() - 1] = data[pair.getKey() - 1]; break; } } - } - catch (IllegalArgumentException e) { + } catch (IllegalArgumentException e) { String value = "'" + data[pair.getKey() - 1] + "'"; MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_errorConvertingValue")); - throw new SQLServerException(form.format(new Object[] {value, JDBCType.of(cm.columnType)}), null, 0, e); - } - catch (ArrayIndexOutOfBoundsException e) { + throw new SQLServerException(form.format(new Object[] {value, JDBCType.of(cm.columnType)}), null, 0, + e); + } catch (ArrayIndexOutOfBoundsException e) { throw new SQLServerException(SQLServerException.getErrString("R_DataSchemaMismatch"), e); } @@ -483,13 +469,10 @@ else if (dateTimeFormatter != null) } @Override - void addColumnMetadataInternal(int positionInSource, - String name, - int jdbcType, - int precision, - int scale, + void addColumnMetadataInternal(int positionInSource, String name, int jdbcType, int precision, int scale, DateTimeFormatter dateTimeFormatter) throws SQLServerException { - loggerExternal.entering(loggerClassName, "addColumnMetadata", new Object[] {positionInSource, name, jdbcType, precision, scale}); + loggerExternal.entering(loggerClassName, "addColumnMetadata", + new Object[] {positionInSource, name, jdbcType, precision, scale}); String colName = ""; @@ -513,36 +496,41 @@ else if ((null != columnNames) && (columnNames.length >= positionInSource)) checkDuplicateColumnName(positionInSource, name); switch (jdbcType) { /* - * SQL Server supports numerous string literal formats for temporal types, hence sending them as varchar with approximate - * precision(length) needed to send supported string literals. string literal formats supported by temporal types are available in MSDN - * page on data types. + * SQL Server supports numerous string literal formats for temporal types, hence sending them as varchar + * with approximate precision(length) needed to send supported string literals. string literal formats + * supported by temporal types are available in MSDN page on data types. */ case java.sql.Types.DATE: case java.sql.Types.TIME: case java.sql.Types.TIMESTAMP: case microsoft.sql.Types.DATETIMEOFFSET: - columnMetadata.put(positionInSource, new ColumnMetadata(colName, jdbcType, 50, scale, dateTimeFormatter)); + columnMetadata.put(positionInSource, + new ColumnMetadata(colName, jdbcType, 50, scale, dateTimeFormatter)); break; // Redirect SQLXML as LONGNVARCHAR // SQLXML is not valid type in TDS case java.sql.Types.SQLXML: - columnMetadata.put(positionInSource, new ColumnMetadata(colName, java.sql.Types.LONGNVARCHAR, precision, scale, dateTimeFormatter)); + columnMetadata.put(positionInSource, + new ColumnMetadata(colName, java.sql.Types.LONGNVARCHAR, precision, scale, dateTimeFormatter)); break; // Redirecting Float as Double based on data type mapping // https://msdn.microsoft.com/en-us/library/ms378878%28v=sql.110%29.aspx case java.sql.Types.FLOAT: - columnMetadata.put(positionInSource, new ColumnMetadata(colName, java.sql.Types.DOUBLE, precision, scale, dateTimeFormatter)); + columnMetadata.put(positionInSource, + new ColumnMetadata(colName, java.sql.Types.DOUBLE, precision, scale, dateTimeFormatter)); break; // redirecting BOOLEAN as BIT case java.sql.Types.BOOLEAN: - columnMetadata.put(positionInSource, new ColumnMetadata(colName, java.sql.Types.BIT, precision, scale, dateTimeFormatter)); + columnMetadata.put(positionInSource, + new ColumnMetadata(colName, java.sql.Types.BIT, precision, scale, dateTimeFormatter)); break; default: - columnMetadata.put(positionInSource, new ColumnMetadata(colName, jdbcType, precision, scale, dateTimeFormatter)); + columnMetadata.put(positionInSource, + new ColumnMetadata(colName, jdbcType, precision, scale, dateTimeFormatter)); } loggerExternal.exiting(loggerClassName, "addColumnMetadata"); @@ -588,8 +576,7 @@ public void setTimeWithTimezoneFormat(DateTimeFormatter dateTimeFormatter) { public boolean next() throws SQLServerException { try { currentLine = fileReader.readLine(); - } - catch (IOException e) { + } catch (IOException e) { throw new SQLServerException(e.getMessage(), null, 0, e); } return (null != currentLine); diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCommon.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCommon.java index dee5350cc..4fdae1249 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCommon.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCommon.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -13,147 +10,127 @@ import java.util.Map; import java.util.Map.Entry; + abstract class SQLServerBulkCommon implements ISQLServerBulkRecord { - /* - * Class to represent the column metadata - */ - protected class ColumnMetadata { - String columnName; - int columnType; - int precision; - int scale; - DateTimeFormatter dateTimeFormatter = null; - - ColumnMetadata(String name, int type, int precision, int scale, - DateTimeFormatter dateTimeFormatter) { - columnName = name; - columnType = type; - this.precision = precision; - this.scale = scale; - this.dateTimeFormatter = dateTimeFormatter; - } - } - - /* - * Contains all the column names if firstLineIsColumnNames is true - */ - protected String[] columnNames = null; - - /* - * Metadata to represent the columns in the batch/file. Each column should - * be mapped to its corresponding position within the parameter (from - * position 1 and onwards) - */ - protected Map columnMetadata; - - /* - * Contains the format that java.sql.Types.TIMESTAMP_WITH_TIMEZONE data - * should be read in as. - */ - protected DateTimeFormatter dateTimeFormatter = null; - - /* - * Contains the format that java.sql.Types.TIME_WITH_TIMEZONE data should be - * read in as. - */ - protected DateTimeFormatter timeFormatter = null; - - @Override - public void addColumnMetadata(int positionInSource, String name, - int jdbcType, int precision, int scale, - DateTimeFormatter dateTimeFormatter) throws SQLServerException { - addColumnMetadataInternal(positionInSource, name, jdbcType, precision, - scale, dateTimeFormatter); - } - - @Override - public void addColumnMetadata(int positionInSource, String name, - int jdbcType, int precision, int scale) throws SQLServerException { - addColumnMetadataInternal(positionInSource, name, jdbcType, precision, - scale, null); - } - - /** - * Adds metadata for the given column in the batch/file. - * - * @param positionInSource - * Indicates which column the metadata is for. Columns start at - * 1. - * @param name - * Name for the column (optional if only using column ordinal in - * a mapping for SQLServerBulkCopy operation) - * @param jdbcType - * JDBC data type of the column - * @param precision - * Precision for the column (ignored for the appropriate data - * types) - * @param scale - * Scale for the column (ignored for the appropriate data types) - * @param dateTimeFormatter - * format to parse data that is sent - * @throws SQLServerException - * when an error occurs - */ - void addColumnMetadataInternal(int positionInSource, String name, - int jdbcType, int precision, int scale, - DateTimeFormatter dateTimeFormatter) throws SQLServerException { - } - - @Override - public void setTimestampWithTimezoneFormat(String dateTimeFormat) { - this.dateTimeFormatter = DateTimeFormatter.ofPattern(dateTimeFormat); - } - - @Override - public void setTimestampWithTimezoneFormat( - DateTimeFormatter dateTimeFormatter) { - this.dateTimeFormatter = dateTimeFormatter; - } - - @Override - public void setTimeWithTimezoneFormat(String timeFormat) { - this.timeFormatter = DateTimeFormatter.ofPattern(timeFormat); - } - - @Override - public void setTimeWithTimezoneFormat(DateTimeFormatter dateTimeFormatter) { - this.timeFormatter = dateTimeFormatter; - } - - /* - * Helper method to throw a SQLServerExeption with the invalidArgument - * message and given argument. - */ - protected void throwInvalidArgument(String argument) - throws SQLServerException { - MessageFormat form = new MessageFormat( - SQLServerException.getErrString("R_invalidArgument")); - Object[] msgArgs = {argument}; - SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), - null, false); - } - - /* - * Method to throw a SQLServerExeption for duplicate column names - */ - protected void checkDuplicateColumnName(int positionInTable, String colName) - throws SQLServerException { - - if (null != colName && colName.trim().length() != 0) { - for (Entry entry : columnMetadata - .entrySet()) { - // duplicate check is not performed in case of same - // positionInTable value - if (null != entry && entry.getKey() != positionInTable) { - if (null != entry.getValue() && colName.trim() - .equalsIgnoreCase(entry.getValue().columnName)) { - throw new SQLServerException(SQLServerException - .getErrString("R_BulkDataDuplicateColumn"), - null); - } - } - } - } - } + /* + * Class to represent the column metadata + */ + protected class ColumnMetadata { + String columnName; + int columnType; + int precision; + int scale; + DateTimeFormatter dateTimeFormatter = null; + + ColumnMetadata(String name, int type, int precision, int scale, DateTimeFormatter dateTimeFormatter) { + columnName = name; + columnType = type; + this.precision = precision; + this.scale = scale; + this.dateTimeFormatter = dateTimeFormatter; + } + } + + /* + * Contains all the column names if firstLineIsColumnNames is true + */ + protected String[] columnNames = null; + + /* + * Metadata to represent the columns in the batch/file. Each column should be mapped to its corresponding position + * within the parameter (from position 1 and onwards) + */ + protected Map columnMetadata; + + /* + * Contains the format that java.sql.Types.TIMESTAMP_WITH_TIMEZONE data should be read in as. + */ + protected DateTimeFormatter dateTimeFormatter = null; + + /* + * Contains the format that java.sql.Types.TIME_WITH_TIMEZONE data should be read in as. + */ + protected DateTimeFormatter timeFormatter = null; + + @Override + public void addColumnMetadata(int positionInSource, String name, int jdbcType, int precision, int scale, + DateTimeFormatter dateTimeFormatter) throws SQLServerException { + addColumnMetadataInternal(positionInSource, name, jdbcType, precision, scale, dateTimeFormatter); + } + + @Override + public void addColumnMetadata(int positionInSource, String name, int jdbcType, int precision, + int scale) throws SQLServerException { + addColumnMetadataInternal(positionInSource, name, jdbcType, precision, scale, null); + } + + /** + * Adds metadata for the given column in the batch/file. + * + * @param positionInSource + * Indicates which column the metadata is for. Columns start at 1. + * @param name + * Name for the column (optional if only using column ordinal in a mapping for SQLServerBulkCopy operation) + * @param jdbcType + * JDBC data type of the column + * @param precision + * Precision for the column (ignored for the appropriate data types) + * @param scale + * Scale for the column (ignored for the appropriate data types) + * @param dateTimeFormatter + * format to parse data that is sent + * @throws SQLServerException + * when an error occurs + */ + void addColumnMetadataInternal(int positionInSource, String name, int jdbcType, int precision, int scale, + DateTimeFormatter dateTimeFormatter) throws SQLServerException {} + + @Override + public void setTimestampWithTimezoneFormat(String dateTimeFormat) { + this.dateTimeFormatter = DateTimeFormatter.ofPattern(dateTimeFormat); + } + + @Override + public void setTimestampWithTimezoneFormat(DateTimeFormatter dateTimeFormatter) { + this.dateTimeFormatter = dateTimeFormatter; + } + + @Override + public void setTimeWithTimezoneFormat(String timeFormat) { + this.timeFormatter = DateTimeFormatter.ofPattern(timeFormat); + } + + @Override + public void setTimeWithTimezoneFormat(DateTimeFormatter dateTimeFormatter) { + this.timeFormatter = dateTimeFormatter; + } + + /* + * Helper method to throw a SQLServerExeption with the invalidArgument message and given argument. + */ + protected void throwInvalidArgument(String argument) throws SQLServerException { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidArgument")); + Object[] msgArgs = {argument}; + SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), null, false); + } + + /* + * Method to throw a SQLServerExeption for duplicate column names + */ + protected void checkDuplicateColumnName(int positionInTable, String colName) throws SQLServerException { + + if (null != colName && colName.trim().length() != 0) { + for (Entry entry : columnMetadata.entrySet()) { + // duplicate check is not performed in case of same + // positionInTable value + if (null != entry && entry.getKey() != positionInTable) { + if (null != entry.getValue() && colName.trim().equalsIgnoreCase(entry.getValue().columnName)) { + throw new SQLServerException(SQLServerException.getErrString("R_BulkDataDuplicateColumn"), + null); + } + } + } + } + } } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java index 9122c44fa..90ea08396 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -51,23 +48,26 @@ import microsoft.sql.DateTimeOffset; + /** - * Lets you efficiently bulk load a SQL Server table with data from another source.
+ * Provides functionality to efficiently bulk load a SQL Server table with data from another source.
*
- * Microsoft SQL Server includes a popular command-prompt utility named bcp for moving data from one table to another, whether on a single server or - * between servers. The SQLServerBulkCopy class lets you write code solutions in Java that provide similar functionality. There are other ways to load - * data into a SQL Server table (INSERT statements, for example), but SQLServerBulkCopy offers a significant performance advantage over them.
- * The SQLServerBulkCopy class can be used to write data only to SQL Server tables. However, the data source is not limited to SQL Server; any data - * source can be used, as long as the data can be read with a ResultSet or ISQLServerBulkRecord instance. + * Microsoft SQL Server includes a popular command-prompt utility named bcp for moving data from one table to another, + * whether on a single server or between servers. The SQLServerBulkCopy class lets you write code solutions in Java that + * provide similar functionality. There are other ways to load data into a SQL Server table (INSERT statements, for + * example), but SQLServerBulkCopy offers a significant performance advantage over them.
+ * The SQLServerBulkCopy class can be used to write data only to SQL Server tables. However, the data source is not + * limited to SQL Server; any data source can be used, as long as the data can be read with a ResultSet or + * ISQLServerBulkRecord instance. */ public class SQLServerBulkCopy implements java.lang.AutoCloseable, java.io.Serializable { /** - * - */ - private static final long serialVersionUID = 1989903904654306244L; + * Update serialVersionUID when making changes to this file + */ + private static final long serialVersionUID = 1989903904654306244L; - /* - * Class to represent the column mappings between the source and destination table + /** + * Represents the column mappings between the source and destination table */ private class ColumnMapping { String sourceColumnName = null; @@ -75,100 +75,97 @@ private class ColumnMapping { String destinationColumnName = null; int destinationColumnOrdinal = -1; - ColumnMapping(String source, - String dest) { + ColumnMapping(String source, String dest) { this.sourceColumnName = source; this.destinationColumnName = dest; } - ColumnMapping(String source, - int dest) { + ColumnMapping(String source, int dest) { this.sourceColumnName = source; this.destinationColumnOrdinal = dest; } - ColumnMapping(int source, - String dest) { + ColumnMapping(int source, String dest) { this.sourceColumnOrdinal = source; this.destinationColumnName = dest; } - ColumnMapping(int source, - int dest) { + ColumnMapping(int source, int dest) { this.sourceColumnOrdinal = source; this.destinationColumnOrdinal = dest; } } - /* + /** * Class name for logging. */ private static final String loggerClassName = "com.microsoft.sqlserver.jdbc.SQLServerBulkCopy"; private static final int SQL_SERVER_2016_VERSION = 13; - /* + /** * Logger */ private static final java.util.logging.Logger loggerExternal = java.util.logging.Logger.getLogger(loggerClassName); - /* + /** * Destination server connection. */ private SQLServerConnection connection; - /* + /** * Options to control how the WriteToServer methods behave. */ private SQLServerBulkCopyOptions copyOptions; - /* + /** * Mappings between columns in the data source and columns in the destination */ private List columnMappings; - /* + /** * Flag if SQLServerBulkCopy owns the connection and should close it when Close is called */ private boolean ownsConnection; - /* - * Name of destination table on server. - * - * If destinationTable has not been set when WriteToServer is called, an Exception is thrown. - * - * destinationTable is a three-part name (..). You can qualify the table name with its database and owning schema if - * you choose. However, if the table name uses an underscore ("_") or any other special characters, you must escape the name using surrounding - * brackets. For more information, see "Identifiers" in SQL Server Books Online. - * - * You can bulk-copy data to a temporary table by using a value such as tempdb..#table or tempdb..#table for the destinationTable property. + /** + * Name of destination table on server. If destinationTable has not been set when WriteToServer is called, an + * Exception is thrown. destinationTable is a three-part name {@code (..)}. You can + * qualify the table name with its database and owning schema if you choose. However, if the table name uses an + * underscore ("_") or any other special characters, you must escape the name using surrounding brackets. For more + * information, see "Identifiers" in SQL Server Books Online. You can bulk-copy data to a temporary table by using a + * value such as {@code tempdb..#table or tempdb..#table} for the destinationTable property. */ private String destinationTableName; - /* + /** * Source data (from a Record). Is null unless the corresponding version of writeToServer is called. */ private ISQLServerBulkRecord sourceBulkRecord; - /* + /** * Source data (from ResultSet). Is null unless the corresponding version of writeToServer is called. */ private ResultSet sourceResultSet; - /* + /** * Metadata for the source table columns */ private ResultSetMetaData sourceResultSetMetaData; - /* The CekTable for the destination table. */ + /** + * The CekTable for the destination table. + */ private CekTable destCekTable = null; - /* Statement level encryption setting needed for querying against encrypted columns. */ + /** + * Statement level encryption setting needed for querying against encrypted columns. + */ private SQLServerStatementColumnEncryptionSetting stmtColumnEncriptionSetting = SQLServerStatementColumnEncryptionSetting.UseConnectionSetting; - + private ResultSet destinationTableMetadata; - - /* + + /** * Metadata for the destination table columns */ class BulkColumnMetaData { @@ -202,11 +199,7 @@ class BulkColumnMetaData { } // This constructor is needed for the source meta data. - BulkColumnMetaData(String colName, - boolean isNullable, - int precision, - int scale, - int jdbcType, + BulkColumnMetaData(String colName, boolean isNullable, int precision, int scale, int jdbcType, DateTimeFormatter dateTimeFormatter) throws SQLServerException { this.columnName = colName; this.isNullable = isNullable; @@ -216,17 +209,14 @@ class BulkColumnMetaData { this.dateTimeFormatter = dateTimeFormatter; } - BulkColumnMetaData(Column column, - String collationName, - String encryptionType) throws SQLServerException { + BulkColumnMetaData(Column column, String collationName, String encryptionType) throws SQLServerException { this(column); this.collationName = collationName; this.encryptionType = encryptionType; } // update the cryptoMeta of source when reading from forward only resultset - BulkColumnMetaData(BulkColumnMetaData bulkColumnMetaData, - CryptoMetadata cryptoMeta) { + BulkColumnMetaData(BulkColumnMetaData bulkColumnMetaData, CryptoMetadata cryptoMeta) { this.columnName = bulkColumnMetaData.columnName; this.isNullable = bulkColumnMetaData.isNullable; this.precision = bulkColumnMetaData.precision; @@ -236,28 +226,29 @@ class BulkColumnMetaData { } }; - /* + /** * A map to store the metadata information for the destination table. */ private Map destColumnMetadata; - /* + /** * A map to store the metadata information for the source table. */ private Map srcColumnMetadata; - /* + /** * Variable to store destination column count. */ private int destColumnCount; - /* + /** * Variable to store source column count. */ private int srcColumnCount; - /* - * Timer for the bulk copy operation. The other timeout timers in the TDS layer only measure the response of the first packet from SQL Server. + /** + * Timer for the bulk copy operation. The other timeout timers in the TDS layer only measure the response of the + * first packet from SQL Server. */ private final class BulkTimeoutTimer implements Runnable { private final int timeoutSeconds; @@ -266,8 +257,7 @@ private final class BulkTimeoutTimer implements Runnable { private Thread timerThread; private volatile boolean canceled = false; - BulkTimeoutTimer(int timeoutSeconds, - TDSCommand command) { + BulkTimeoutTimer(int timeoutSeconds, TDSCommand command) { assert timeoutSeconds > 0; assert null != command; @@ -300,10 +290,8 @@ public void run() { return; Thread.sleep(1000); - } - while (--secondsRemaining > 0); - } - catch (InterruptedException e) { + } while (--secondsRemaining > 0); + } catch (InterruptedException e) { // re-interrupt the current thread, in order to restore the thread's interrupt status. Thread.currentThread().interrupt(); return; @@ -313,8 +301,7 @@ public void run() { // time then interrupt the registered command. try { command.interrupt(SQLServerException.getErrString("R_queryTimedOut")); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { // Unfortunately, there's nothing we can do if we // fail to time out the request. There is no way // to report back what happened. @@ -324,33 +311,34 @@ public void run() { } private BulkTimeoutTimer timeoutTimer = null; - + /** - * The maximum temporal precision we can send when using varchar(precision) in bulkcommand, to send a smalldatetime/datetime - * value. + * The maximum temporal precision we can send when using varchar(precision) in bulkcommand, to send a + * smalldatetime/datetime value. */ private static final int sourceBulkRecordTemporalMaxPrecision = 50; /** - * Initializes a new instance of the SQLServerBulkCopy class using the specified open instance of SQLServerConnection. + * Constructs a SQLServerBulkCopy using the specified open instance of SQLServerConnection. * * @param connection - * Open instance of Connection to destination server. Must be from the Microsoft JDBC driver for SQL Server. + * Open instance of Connection to destination server. Must be from the Microsoft JDBC driver for SQL Server. * @throws SQLServerException - * If the supplied type is not a connection from the Microsoft JDBC driver for SQL Server. + * If the supplied type is not a connection from the Microsoft JDBC driver for SQL Server. */ public SQLServerBulkCopy(Connection connection) throws SQLServerException { loggerExternal.entering(loggerClassName, "SQLServerBulkCopy", connection); if (null == connection || !(connection instanceof SQLServerConnection)) { - SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_invalidDestConnection"), null, false); + SQLServerException.makeFromDriverError(null, null, + SQLServerException.getErrString("R_invalidDestConnection"), null, false); } if (connection instanceof SQLServerConnection) { this.connection = (SQLServerConnection) connection; - } - else { - SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_invalidDestConnection"), null, false); + } else { + SQLServerException.makeFromDriverError(null, null, + SQLServerException.getErrString("R_invalidDestConnection"), null, false); } ownsConnection = false; @@ -364,12 +352,12 @@ public SQLServerBulkCopy(Connection connection) throws SQLServerException { } /** - * Initializes and opens a new instance of SQLServerConnection based on the supplied connectionString. + * Constructs a SQLServerBulkCopy based on the supplied connectionString. * * @param connectionUrl - * Connection string for the destination server. + * Connection string for the destination server. * @throws SQLServerException - * If a connection cannot be established. + * If a connection cannot be established. */ public SQLServerBulkCopy(String connectionUrl) throws SQLServerException { loggerExternal.entering(loggerClassName, "SQLServerBulkCopy", "connectionUrl not traced."); @@ -395,20 +383,18 @@ public SQLServerBulkCopy(String connectionUrl) throws SQLServerException { * Adds a new column mapping, using ordinals to specify both the source and destination columns. * * @param sourceColumn - * Source column ordinal. + * Source column ordinal. * @param destinationColumn - * Destination column ordinal. + * Destination column ordinal. * @throws SQLServerException - * If the column mapping is invalid + * If the column mapping is invalid */ - public void addColumnMapping(int sourceColumn, - int destinationColumn) throws SQLServerException { + public void addColumnMapping(int sourceColumn, int destinationColumn) throws SQLServerException { loggerExternal.entering(loggerClassName, "addColumnMapping", new Object[] {sourceColumn, destinationColumn}); if (0 >= sourceColumn) { throwInvalidArgument("sourceColumn"); - } - else if (0 >= destinationColumn) { + } else if (0 >= destinationColumn) { throwInvalidArgument("destinationColumn"); } columnMappings.add(new ColumnMapping(sourceColumn, destinationColumn)); @@ -420,20 +406,18 @@ else if (0 >= destinationColumn) { * Adds a new column mapping, using an ordinal for the source column and a string for the destination column. * * @param sourceColumn - * Source column ordinal. + * Source column ordinal. * @param destinationColumn - * Destination column name. + * Destination column name. * @throws SQLServerException - * If the column mapping is invalid + * If the column mapping is invalid */ - public void addColumnMapping(int sourceColumn, - String destinationColumn) throws SQLServerException { + public void addColumnMapping(int sourceColumn, String destinationColumn) throws SQLServerException { loggerExternal.entering(loggerClassName, "addColumnMapping", new Object[] {sourceColumn, destinationColumn}); if (0 >= sourceColumn) { throwInvalidArgument("sourceColumn"); - } - else if (null == destinationColumn || destinationColumn.isEmpty()) { + } else if (null == destinationColumn || destinationColumn.isEmpty()) { throwInvalidArgument("destinationColumn"); } columnMappings.add(new ColumnMapping(sourceColumn, destinationColumn.trim())); @@ -442,23 +426,22 @@ else if (null == destinationColumn || destinationColumn.isEmpty()) { } /** - * Adds a new column mapping, using a column name to describe the source column and an ordinal to specify the destination column. + * Adds a new column mapping, using a column name to describe the source column and an ordinal to specify the + * destination column. * * @param sourceColumn - * Source column name. + * Source column name. * @param destinationColumn - * Destination column ordinal. + * Destination column ordinal. * @throws SQLServerException - * If the column mapping is invalid + * If the column mapping is invalid */ - public void addColumnMapping(String sourceColumn, - int destinationColumn) throws SQLServerException { + public void addColumnMapping(String sourceColumn, int destinationColumn) throws SQLServerException { loggerExternal.entering(loggerClassName, "addColumnMapping", new Object[] {sourceColumn, destinationColumn}); if (0 >= destinationColumn) { throwInvalidArgument("destinationColumn"); - } - else if (null == sourceColumn || sourceColumn.isEmpty()) { + } else if (null == sourceColumn || sourceColumn.isEmpty()) { throwInvalidArgument("sourceColumn"); } columnMappings.add(new ColumnMapping(sourceColumn.trim(), destinationColumn)); @@ -470,20 +453,18 @@ else if (null == sourceColumn || sourceColumn.isEmpty()) { * Adds a new column mapping, using column names to specify both source and destination columns. * * @param sourceColumn - * Source column name. + * Source column name. * @param destinationColumn - * Destination column name. + * Destination column name. * @throws SQLServerException - * If the column mapping is invalid + * If the column mapping is invalid */ - public void addColumnMapping(String sourceColumn, - String destinationColumn) throws SQLServerException { + public void addColumnMapping(String sourceColumn, String destinationColumn) throws SQLServerException { loggerExternal.entering(loggerClassName, "addColumnMapping", new Object[] {sourceColumn, destinationColumn}); if (null == sourceColumn || sourceColumn.isEmpty()) { throwInvalidArgument("sourceColumn"); - } - else if (null == destinationColumn || destinationColumn.isEmpty()) { + } else if (null == destinationColumn || destinationColumn.isEmpty()) { throwInvalidArgument("destinationColumn"); } columnMappings.add(new ColumnMapping(sourceColumn.trim(), destinationColumn.trim())); @@ -511,8 +492,7 @@ public void close() { if (ownsConnection) { try { connection.close(); - } - catch (SQLException e) { + } catch (SQLException e) { // Ignore this exception } } @@ -521,7 +501,7 @@ public void close() { } /** - * Gets the name of the destination table on the server. + * Returns the name of the destination table on the server. * * @return Destination table name. */ @@ -533,9 +513,9 @@ public String getDestinationTableName() { * Sets the name of the destination table on the server. * * @param tableName - * Destination table name. + * Destination table name. * @throws SQLServerException - * If the table name is null + * If the table name is null */ public void setDestinationTableName(String tableName) throws SQLServerException { loggerExternal.entering(loggerClassName, "setDestinationTableName", tableName); @@ -550,7 +530,7 @@ public void setDestinationTableName(String tableName) throws SQLServerException } /** - * Gets the current SQLServerBulkCopyOptions. + * Returns the current SQLServerBulkCopyOptions. * * @return Current SQLServerBulkCopyOptions settings. */ @@ -559,13 +539,14 @@ public SQLServerBulkCopyOptions getBulkCopyOptions() { } /** - * Update the behavior of the SQLServerBulkCopy instance according to the options supplied, if supplied SQLServerBulkCopyOption is not null. + * Update the behavior of the SQLServerBulkCopy instance according to the options supplied, if supplied + * SQLServerBulkCopyOption is not null. * * @param copyOptions - * Settings to change how the WriteToServer methods behave. + * Settings to change how the WriteToServer methods behave. * @throws SQLServerException - * If the SQLServerBulkCopyOption class was constructed using an existing Connection and the UseInternalTransaction option is - * specified. + * If the SQLServerBulkCopyOption class was constructed using an existing Connection and the + * UseInternalTransaction option is specified. */ public void setBulkCopyOptions(SQLServerBulkCopyOptions copyOptions) throws SQLServerException { loggerExternal.entering(loggerClassName, "updateBulkCopyOptions", copyOptions); @@ -576,7 +557,8 @@ public void setBulkCopyOptions(SQLServerBulkCopyOptions copyOptions) throws SQLS // Setting it with an external connection object should throw // exception. if (!ownsConnection && copyOptions.isUseInternalTransaction()) { - SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_invalidTransactionOption"), null, false); + SQLServerException.makeFromDriverError(null, null, + SQLServerException.getErrString("R_invalidTransactionOption"), null, false); } this.copyOptions = copyOptions; @@ -585,42 +567,42 @@ public void setBulkCopyOptions(SQLServerBulkCopyOptions copyOptions) throws SQLS } /** - * Copies all rows in the supplied ResultSet to a destination table specified by the destinationTableName property of the SQLServerBulkCopy - * object. + * Copies all rows in the supplied ResultSet to a destination table specified by the destinationTableName property + * of the SQLServerBulkCopy object. * * @param sourceData - * ResultSet to read data rows from. + * ResultSet to read data rows from. * @throws SQLServerException - * If there are any issues encountered when performing the bulk copy operation + * If there are any issues encountered when performing the bulk copy operation */ public void writeToServer(ResultSet sourceData) throws SQLServerException { writeResultSet(sourceData, false); } /** - * Copies all rows in the supplied RowSet to a destination table specified by the destinationTableName property of the SQLServerBulkCopy object. + * Copies all rows in the supplied RowSet to a destination table specified by the destinationTableName property of + * the SQLServerBulkCopy object. * * @param sourceData - * RowSet to read data rows from. + * RowSet to read data rows from. * @throws SQLServerException - * If there are any issues encountered when performing the bulk copy operation + * If there are any issues encountered when performing the bulk copy operation */ public void writeToServer(RowSet sourceData) throws SQLServerException { writeResultSet(sourceData, true); } /** - * Copies all rows in the supplied ResultSet to a destination table specified by the destinationTableName property of the SQLServerBulkCopy - * object. + * Copies all rows in the supplied ResultSet to a destination table specified by the destinationTableName property + * of the SQLServerBulkCopy object. * * @param sourceData - * ResultSet to read data rows from. + * ResultSet to read data rows from. * @param isRowSet * @throws SQLServerException - * If there are any issues encountered when performing the bulk copy operation + * If there are any issues encountered when performing the bulk copy operation */ - private void writeResultSet(ResultSet sourceData, - boolean isRowSet) throws SQLServerException { + private void writeResultSet(ResultSet sourceData, boolean isRowSet) throws SQLServerException { loggerExternal.entering(loggerClassName, "writeToServer"); if (null == sourceData) { @@ -628,19 +610,19 @@ private void writeResultSet(ResultSet sourceData, } try { - if (isRowSet) // Default RowSet implementation in Java doesn't have isClosed() implemented so need to do an alternate check instead. + if (isRowSet) // Default RowSet implementation in Java doesn't have isClosed() implemented so need to do an + // alternate check instead. { if (!sourceData.isBeforeFirst()) { sourceData.beforeFirst(); } - } - else { + } else { if (sourceData.isClosed()) { - SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_resultsetClosed"), null, false); + SQLServerException.makeFromDriverError(null, null, + SQLServerException.getErrString("R_resultsetClosed"), null, false); } } - } - catch (SQLException e) { + } catch (SQLException e) { throw new SQLServerException(null, e.getMessage(), null, 0, false); } @@ -652,8 +634,7 @@ private void writeResultSet(ResultSet sourceData, // Save the resultset metadata as it is used in many places. try { sourceResultSetMetaData = sourceResultSet.getMetaData(); - } - catch (SQLException e) { + } catch (SQLException e) { throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveColMeta"), e); } @@ -663,13 +644,13 @@ private void writeResultSet(ResultSet sourceData, } /** - * Copies all rows from the supplied ISQLServerBulkRecord to a destination table specified by the destinationTableName property of the - * SQLServerBulkCopy object. + * Copies all rows from the supplied ISQLServerBulkRecord to a destination table specified by the + * destinationTableName property of the SQLServerBulkCopy object. * * @param sourceData - * SQLServerBulkReader to read data rows from. + * SQLServerBulkReader to read data rows from. * @throws SQLServerException - * If there are any issues encountered when performing the bulk copy operation + * If there are any issues encountered when performing the bulk copy operation */ public void writeToServer(ISQLServerBulkRecord sourceData) throws SQLServerException { loggerExternal.entering(loggerClassName, "writeToServer"); @@ -686,7 +667,7 @@ public void writeToServer(ISQLServerBulkRecord sourceData) throws SQLServerExcep loggerExternal.exiting(loggerClassName, "writeToServer"); } - /* + /** * Initializes the defaults for member variables that require it. */ private void initializeDefaults() { @@ -721,10 +702,8 @@ final boolean doExecute() throws SQLServerException { // the resultset, false otherwise. We keep sending rows, one batch at a time until the // resultset is done. try { - while (doInsertBulk(this)) - ; - } - catch (SQLServerException topLevelException) { + while (doInsertBulk(this)); + } catch (SQLServerException topLevelException) { // Get to the root of this exception. Throwable rootCause = topLevelException; while (null != rootCause.getCause()) { @@ -754,11 +733,10 @@ final boolean doExecute() throws SQLServerException { connection.executeCommand(new InsertBulk()); } - /* + /** * write ColumnData token in COLMETADATA header */ - private void writeColumnMetaDataColumnData(TDSWriter tdsWriter, - int idx) throws SQLServerException { + private void writeColumnMetaDataColumnData(TDSWriter tdsWriter, int idx) throws SQLServerException { int srcColumnIndex, destPrecision; int bulkJdbcType, bulkPrecision, bulkScale; SQLCollation collation; @@ -766,8 +744,8 @@ private void writeColumnMetaDataColumnData(TDSWriter tdsWriter, boolean isStreaming, srcNullable; // For varchar, precision is the size of the varchar type. /* - * UserType USHORT/ULONG; (Changed to ULONG in TDS 7.2) The user type ID of the data type of the column. The value will be 0x0000 with the - * exceptions of TIMESTAMP (0x0050) and alias types (greater than 0x00FF) + * UserType USHORT/ULONG; (Changed to ULONG in TDS 7.2) The user type ID of the data type of the column. The + * value will be 0x0000 with the exceptions of TIMESTAMP (0x0050) and alias types (greater than 0x00FF) */ byte[] userType = new byte[4]; userType[0] = (byte) 0x00; @@ -776,13 +754,13 @@ private void writeColumnMetaDataColumnData(TDSWriter tdsWriter, userType[3] = (byte) 0x00; tdsWriter.writeBytes(userType); - /* - * Flags token - Bit flags in least significant bit order https://msdn.microsoft.com/en-us/library/dd357363.aspx flags[0] = (byte) 0x05; - * flags[1] = (byte) 0x00; + /** + * Flags token - Bit flags in least significant bit order https://msdn.microsoft.com/en-us/library/dd357363.aspx + * flags[0] = (byte) 0x05; flags[1] = (byte) 0x00; */ int destColumnIndex = columnMappings.get(idx).destinationColumnOrdinal; - /* + /** * TYPE_INFO FIXEDLENTYPE Example INT: tdsWriter.writeByte((byte) 0x38); */ srcColumnIndex = columnMappings.get(idx).sourceColumnOrdinal; @@ -790,7 +768,8 @@ private void writeColumnMetaDataColumnData(TDSWriter tdsWriter, byte flags[] = destColumnMetadata.get(destColumnIndex).flags; // If AllowEncryptedValueModification is set to true (and of course AE is off), // the driver will not sent AE information, so, we need to set Encryption bit flag to 0. - if (null == srcColumnMetadata.get(srcColumnIndex).cryptoMeta && null == destColumnMetadata.get(destColumnIndex).cryptoMeta + if (null == srcColumnMetadata.get(srcColumnIndex).cryptoMeta + && null == destColumnMetadata.get(destColumnIndex).cryptoMeta && true == copyOptions.isAllowEncryptedValueModifications()) { // flags[1]>>3 & 0x01 is the encryption bit flag. @@ -815,55 +794,57 @@ private void writeColumnMetaDataColumnData(TDSWriter tdsWriter, if (null == collation) collation = connection.getDatabaseCollation(); - if ((java.sql.Types.NCHAR == bulkJdbcType) || (java.sql.Types.NVARCHAR == bulkJdbcType) || (java.sql.Types.LONGNVARCHAR == bulkJdbcType)) { - isStreaming = (DataTypes.SHORT_VARTYPE_MAX_CHARS < bulkPrecision) || (DataTypes.SHORT_VARTYPE_MAX_CHARS < destPrecision); - } - else { - isStreaming = (DataTypes.SHORT_VARTYPE_MAX_BYTES < bulkPrecision) || (DataTypes.SHORT_VARTYPE_MAX_BYTES < destPrecision); + if ((java.sql.Types.NCHAR == bulkJdbcType) || (java.sql.Types.NVARCHAR == bulkJdbcType) + || (java.sql.Types.LONGNVARCHAR == bulkJdbcType)) { + isStreaming = (DataTypes.SHORT_VARTYPE_MAX_CHARS < bulkPrecision) + || (DataTypes.SHORT_VARTYPE_MAX_CHARS < destPrecision); + } else { + isStreaming = (DataTypes.SHORT_VARTYPE_MAX_BYTES < bulkPrecision) + || (DataTypes.SHORT_VARTYPE_MAX_BYTES < destPrecision); } CryptoMetadata destCryptoMeta = destColumnMetadata.get(destColumnIndex).cryptoMeta; - + /* - * if source is encrypted and destination is unenecrypted, use destination's sql type to send since there is no way of finding if source is - * encrypted without accessing the resultset. - * - * Send destination type if source resultset set is of type SQLServer, encryption is enabled and destination column is not encrypted + * if source is encrypted and destination is unenecrypted, use destination's sql type to send since there is no + * way of finding if source is encrypted without accessing the resultset. Send destination type if source + * resultset set is of type SQLServer, encryption is enabled and destination column is not encrypted */ - if ((sourceResultSet instanceof SQLServerResultSet) && (connection.isColumnEncryptionSettingEnabled()) && (null != destCryptoMeta)) { + if ((sourceResultSet instanceof SQLServerResultSet) && (connection.isColumnEncryptionSettingEnabled()) + && (null != destCryptoMeta)) { bulkJdbcType = destColumnMetadata.get(destColumnIndex).jdbcType; bulkPrecision = destPrecision; bulkScale = destColumnMetadata.get(destColumnIndex).scale; } // use varbinary to send if destination is encrypted - if (((null != destColumnMetadata.get(destColumnIndex).encryptionType) && copyOptions.isAllowEncryptedValueModifications()) + if (((null != destColumnMetadata.get(destColumnIndex).encryptionType) + && copyOptions.isAllowEncryptedValueModifications()) || (null != destColumnMetadata.get(destColumnIndex).cryptoMeta)) { tdsWriter.writeByte((byte) 0xA5); if (isStreaming) { tdsWriter.writeShort((short) 0xFFFF); - } - else { + } else { tdsWriter.writeShort((short) (bulkPrecision)); } } // In this case we will explicitly send binary value. - else if (((java.sql.Types.CHAR == bulkJdbcType) || (java.sql.Types.VARCHAR == bulkJdbcType) || (java.sql.Types.LONGVARCHAR == bulkJdbcType)) + else if (((java.sql.Types.CHAR == bulkJdbcType) || (java.sql.Types.VARCHAR == bulkJdbcType) + || (java.sql.Types.LONGVARCHAR == bulkJdbcType)) && (SSType.BINARY == destSSType || SSType.VARBINARY == destSSType || SSType.VARBINARYMAX == destSSType || SSType.IMAGE == destSSType)) { if (isStreaming) { // Send as VARBINARY if streaming is enabled tdsWriter.writeByte((byte) 0xA5); - } - else { + } else { tdsWriter.writeByte((byte) ((SSType.BINARY == destSSType) ? 0xAD : 0xA5)); } tdsWriter.writeShort((short) (bulkPrecision)); - } - else { - writeTypeInfo(tdsWriter, bulkJdbcType, bulkScale, bulkPrecision, destSSType, collation, isStreaming, srcNullable, false); + } else { + writeTypeInfo(tdsWriter, bulkJdbcType, bulkScale, bulkPrecision, destSSType, collation, isStreaming, + srcNullable, false); } if (null != destCryptoMeta) { @@ -877,8 +858,8 @@ else if (((java.sql.Types.CHAR == bulkJdbcType) || (java.sql.Types.VARCHAR == bu isStreaming = (DataTypes.SHORT_VARTYPE_MAX_BYTES < baseDestPrecision); // Send CryptoMetaData - tdsWriter.writeShort(destCryptoMeta.getOrdinal()); // Ordinal - tdsWriter.writeBytes(userType); // usertype + tdsWriter.writeShort(destCryptoMeta.getOrdinal()); // Ordinal + tdsWriter.writeBytes(userType); // usertype // BaseTypeInfo writeTypeInfo(tdsWriter, baseDestJDBCType, destCryptoMeta.baseTypeInfo.getScale(), baseDestPrecision, destCryptoMeta.baseTypeInfo.getSSType(), collation, isStreaming, srcNullable, true); @@ -888,7 +869,8 @@ else if (((java.sql.Types.CHAR == bulkJdbcType) || (java.sql.Types.VARCHAR == bu } /* - * ColName token The column name. Contains the column name length and column name. see: SQLServerConnection.java toUCS16(String s) + * ColName token The column name. Contains the column name length and column name. see: SQLServerConnection.java + * toUCS16(String s) */ int destColNameLen = columnMappings.get(idx).destinationColumnName.length(); String destColName = columnMappings.get(idx).destinationColumnName; @@ -904,21 +886,14 @@ else if (((java.sql.Types.CHAR == bulkJdbcType) || (java.sql.Types.VARCHAR == bu tdsWriter.writeBytes(colName); } - private void writeTypeInfo(TDSWriter tdsWriter, - int srcJdbcType, - int srcScale, - int srcPrecision, - SSType destSSType, - SQLCollation collation, - boolean isStreaming, - boolean srcNullable, + private void writeTypeInfo(TDSWriter tdsWriter, int srcJdbcType, int srcScale, int srcPrecision, SSType destSSType, + SQLCollation collation, boolean isStreaming, boolean srcNullable, boolean isBaseType) throws SQLServerException { switch (srcJdbcType) { case java.sql.Types.INTEGER: // 0x38 if (!srcNullable) { tdsWriter.writeByte(TDSType.INT4.byteValue()); - } - else { + } else { tdsWriter.writeByte(TDSType.INTN.byteValue()); tdsWriter.writeByte((byte) 0x04); } @@ -927,8 +902,7 @@ private void writeTypeInfo(TDSWriter tdsWriter, case java.sql.Types.BIGINT: // 0x7f if (!srcNullable) { tdsWriter.writeByte(TDSType.INT8.byteValue()); - } - else { + } else { tdsWriter.writeByte(TDSType.INTN.byteValue()); tdsWriter.writeByte((byte) 0x08); } @@ -937,8 +911,7 @@ private void writeTypeInfo(TDSWriter tdsWriter, case java.sql.Types.BIT: // 0x32 if (!srcNullable) { tdsWriter.writeByte(TDSType.BIT1.byteValue()); - } - else { + } else { tdsWriter.writeByte(TDSType.BITN.byteValue()); tdsWriter.writeByte((byte) 0x01); } @@ -947,8 +920,7 @@ private void writeTypeInfo(TDSWriter tdsWriter, case java.sql.Types.SMALLINT: // 0x34 if (!srcNullable) { tdsWriter.writeByte(TDSType.INT2.byteValue()); - } - else { + } else { tdsWriter.writeByte(TDSType.INTN.byteValue()); tdsWriter.writeByte((byte) 0x02); } @@ -957,8 +929,7 @@ private void writeTypeInfo(TDSWriter tdsWriter, case java.sql.Types.TINYINT: // 0x30 if (!srcNullable) { tdsWriter.writeByte(TDSType.INT1.byteValue()); - } - else { + } else { tdsWriter.writeByte(TDSType.INTN.byteValue()); tdsWriter.writeByte((byte) 0x01); } @@ -967,8 +938,7 @@ private void writeTypeInfo(TDSWriter tdsWriter, case java.sql.Types.DOUBLE: // (FLT8TYPE) 0x3E if (!srcNullable) { tdsWriter.writeByte(TDSType.FLOAT8.byteValue()); - } - else { + } else { tdsWriter.writeByte(TDSType.FLOATN.byteValue()); tdsWriter.writeByte((byte) 0x08); } @@ -977,8 +947,7 @@ private void writeTypeInfo(TDSWriter tdsWriter, case java.sql.Types.REAL: // (FLT4TYPE) 0x3B if (!srcNullable) { tdsWriter.writeByte(TDSType.FLOAT4.byteValue()); - } - else { + } else { tdsWriter.writeByte(TDSType.FLOATN.byteValue()); tdsWriter.writeByte((byte) 0x04); } @@ -994,8 +963,7 @@ private void writeTypeInfo(TDSWriter tdsWriter, tdsWriter.writeByte((byte) 8); else tdsWriter.writeByte((byte) 4); - } - else { + } else { if (java.sql.Types.DECIMAL == srcJdbcType) tdsWriter.writeByte(TDSType.DECIMALN.byteValue()); // 0x6A else @@ -1011,8 +979,7 @@ private void writeTypeInfo(TDSWriter tdsWriter, if (isBaseType && (SSType.GUID == destSSType)) { tdsWriter.writeByte(TDSType.GUID.byteValue()); tdsWriter.writeByte((byte) 0x10); - } - else { + } else { // BIGCHARTYPE tdsWriter.writeByte(TDSType.BIGCHAR.byteValue()); @@ -1034,8 +1001,7 @@ private void writeTypeInfo(TDSWriter tdsWriter, tdsWriter.writeByte(TDSType.BIGVARCHAR.byteValue()); if (isStreaming) { tdsWriter.writeShort((short) 0xFFFF); - } - else { + } else { tdsWriter.writeShort((short) (srcPrecision)); } collation.writeCollation(tdsWriter); @@ -1046,8 +1012,7 @@ private void writeTypeInfo(TDSWriter tdsWriter, tdsWriter.writeByte(TDSType.NVARCHAR.byteValue()); if (isStreaming) { tdsWriter.writeShort((short) 0xFFFF); - } - else { + } else { tdsWriter.writeShort(isBaseType ? (short) (srcPrecision) : (short) (2 * srcPrecision)); } collation.writeCollation(tdsWriter); @@ -1064,8 +1029,7 @@ private void writeTypeInfo(TDSWriter tdsWriter, tdsWriter.writeByte(TDSType.BIGVARBINARY.byteValue()); if (isStreaming) { tdsWriter.writeShort((short) 0xFFFF); - } - else { + } else { tdsWriter.writeShort((short) (srcPrecision)); } break; @@ -1077,8 +1041,7 @@ private void writeTypeInfo(TDSWriter tdsWriter, tdsWriter.writeByte(TDSType.BIGVARCHAR.byteValue()); tdsWriter.writeShort((short) (srcPrecision)); collation.writeCollation(tdsWriter); - } - else { + } else { switch (destSSType) { case SMALLDATETIME: if (!srcNullable) @@ -1107,16 +1070,16 @@ private void writeTypeInfo(TDSWriter tdsWriter, case java.sql.Types.DATE: // 0x28 /* - * SQL Server supports numerous string literal formats for temporal types, hence sending them as varchar with approximate - * precision(length) needed to send supported string literals if destination is unencrypted. string literal formats supported by - * temporal types are available in MSDN page on data types. + * SQL Server supports numerous string literal formats for temporal types, hence sending them as varchar + * with approximate precision(length) needed to send supported string literals if destination is + * unencrypted. string literal formats supported by temporal types are available in MSDN page on data + * types. */ if ((!isBaseType) && (null != sourceBulkRecord)) { tdsWriter.writeByte(TDSType.BIGVARCHAR.byteValue()); tdsWriter.writeShort((short) (srcPrecision)); collation.writeCollation(tdsWriter); - } - else { + } else { tdsWriter.writeByte(TDSType.DATEN.byteValue()); } break; @@ -1126,16 +1089,15 @@ private void writeTypeInfo(TDSWriter tdsWriter, tdsWriter.writeByte(TDSType.BIGVARCHAR.byteValue()); tdsWriter.writeShort((short) (srcPrecision)); collation.writeCollation(tdsWriter); - } - else { + } else { tdsWriter.writeByte(TDSType.TIMEN.byteValue()); tdsWriter.writeByte((byte) srcScale); } break; // Send as DATETIMEOFFSET for TIME_WITH_TIMEZONE and TIMESTAMP_WITH_TIMEZONE - case 2013: // java.sql.Types.TIME_WITH_TIMEZONE - case 2014: // java.sql.Types.TIMESTAMP_WITH_TIMEZONE + case 2013: // java.sql.Types.TIME_WITH_TIMEZONE + case 2014: // java.sql.Types.TIMESTAMP_WITH_TIMEZONE tdsWriter.writeByte(TDSType.DATETIMEOFFSETN.byteValue()); tdsWriter.writeByte((byte) srcScale); break; @@ -1145,15 +1107,14 @@ private void writeTypeInfo(TDSWriter tdsWriter, tdsWriter.writeByte(TDSType.BIGVARCHAR.byteValue()); tdsWriter.writeShort((short) (srcPrecision)); collation.writeCollation(tdsWriter); - } - else { + } else { tdsWriter.writeByte(TDSType.DATETIMEOFFSETN.byteValue()); tdsWriter.writeByte((byte) srcScale); } break; - case microsoft.sql.Types.SQL_VARIANT: //0x62 + case microsoft.sql.Types.SQL_VARIANT: // 0x62 tdsWriter.writeByte(TDSType.SQL_VARIANT.byteValue()); - tdsWriter.writeInt(TDS.SQL_VARIANT_LENGTH); + tdsWriter.writeInt(TDS.SQL_VARIANT_LENGTH); break; default: MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_BulkTypeNotSupported")); @@ -1162,39 +1123,42 @@ private void writeTypeInfo(TDSWriter tdsWriter, } } - /* - * Writes the CEK table needed for AE. Cek table (with 0 entries) will be present if AE was enabled and server supports it! OR if encryption was - * disabled in connection options + /** + * Writes the CEK table needed for AE. Cek table (with 0 entries) will be present if AE was enabled and server + * supports it! OR if encryption was disabled in connection options */ private void writeCekTable(TDSWriter tdsWriter) throws SQLServerException { if (connection.getServerSupportsColumnEncryption()) { if ((null != destCekTable) && (0 < destCekTable.getSize())) { tdsWriter.writeShort((short) destCekTable.getSize()); for (int cekIndx = 0; cekIndx < destCekTable.getSize(); cekIndx++) { - tdsWriter.writeInt(destCekTable.getCekTableEntry(cekIndx).getColumnEncryptionKeyValues().get(0).databaseId); - tdsWriter.writeInt(destCekTable.getCekTableEntry(cekIndx).getColumnEncryptionKeyValues().get(0).cekId); - tdsWriter.writeInt(destCekTable.getCekTableEntry(cekIndx).getColumnEncryptionKeyValues().get(0).cekVersion); - tdsWriter.writeBytes(destCekTable.getCekTableEntry(cekIndx).getColumnEncryptionKeyValues().get(0).cekMdVersion); + tdsWriter.writeInt( + destCekTable.getCekTableEntry(cekIndx).getColumnEncryptionKeyValues().get(0).databaseId); + tdsWriter.writeInt( + destCekTable.getCekTableEntry(cekIndx).getColumnEncryptionKeyValues().get(0).cekId); + tdsWriter.writeInt( + destCekTable.getCekTableEntry(cekIndx).getColumnEncryptionKeyValues().get(0).cekVersion); + tdsWriter.writeBytes( + destCekTable.getCekTableEntry(cekIndx).getColumnEncryptionKeyValues().get(0).cekMdVersion); // We don't need to send the keys. So count for EncryptionKeyValue is 0 in EK_INFO TDS rule. tdsWriter.writeByte((byte) 0x00); } - } - else { + } else { // If no encrypted columns, but the connection setting is true write 0 as the size of the CekTable. tdsWriter.writeShort((short) 0); } } } - /* + /** * ... */ private void writeColumnMetaData(TDSWriter tdsWriter) throws SQLServerException { /* - * TDS rules for Always Encrypted metadata COLMETADATA = TokenType Count CekTable NoMetaData / (1 *ColumnData) CekTable = EkValueCount EK_INFO - * EK_INFO = DatabaseId CekId CekVersion CekMDVersion Count EncryptionKeyValue + * TDS rules for Always Encrypted metadata COLMETADATA = TokenType Count CekTable NoMetaData / (1 *ColumnData) + * CekTable = EkValueCount EK_INFO EK_INFO = DatabaseId CekId CekVersion CekMDVersion Count EncryptionKeyValue */ /* @@ -1203,9 +1167,8 @@ private void writeColumnMetaData(TDSWriter tdsWriter) throws SQLServerException tdsWriter.writeByte((byte) TDS.TDS_COLMETADATA); /* - * Count token: The count of columns. Should be USHORT. Not Supported in Java. - * - * Remedy: tdsWriter.writeShort((short)columnMappings.size()); + * Count token: The count of columns. Should be USHORT. Not Supported in Java. Remedy: + * tdsWriter.writeShort((short)columnMappings.size()); */ byte[] count = new byte[2]; count[0] = (byte) (columnMappings.size() & 0xFF); @@ -1222,27 +1185,27 @@ private void writeColumnMetaData(TDSWriter tdsWriter) throws SQLServerException } } - /* + /** * Helper method that throws a timeout exception if the cause of the exception was that the query was cancelled */ - private void checkForTimeoutException(SQLException e, - BulkTimeoutTimer timeoutTimer) throws SQLServerException { - if ((null != e.getSQLState()) && (e.getSQLState().equals(SQLState.STATEMENT_CANCELED.getSQLStateCode())) && timeoutTimer.expired()) { + private void checkForTimeoutException(SQLException e, BulkTimeoutTimer timeoutTimer) throws SQLServerException { + if ((null != e.getSQLState()) && (e.getSQLState().equals(SQLState.STATEMENT_CANCELED.getSQLStateCode())) + && timeoutTimer.expired()) { // If SQLServerBulkCopy is managing the transaction, a rollback is needed. if (copyOptions.isUseInternalTransaction()) { connection.rollback(); } - throw new SQLServerException(SQLServerException.getErrString("R_queryTimedOut"), SQLState.STATEMENT_CANCELED, DriverError.NOT_SET, e); + throw new SQLServerException(SQLServerException.getErrString("R_queryTimedOut"), + SQLState.STATEMENT_CANCELED, DriverError.NOT_SET, e); } } - /* - * Validates whether the source JDBC types are compatible with the destination table data types. We need to do this only once for the whole bulk - * copy session. + /** + * Validates whether the source JDBC types are compatible with the destination table data types. We need to do this + * only once for the whole bulk copy session. */ - private void validateDataTypeConversions(int srcColOrdinal, - int destColOrdinal) throws SQLServerException { + private void validateDataTypeConversions(int srcColOrdinal, int destColOrdinal) throws SQLServerException { // Reducing unnecessary assignment to optimize for performance. This reduces code readability, but // may be worth it for the bulk copy. @@ -1250,9 +1213,10 @@ private void validateDataTypeConversions(int srcColOrdinal, CryptoMetadata destCryptoMeta = destColumnMetadata.get(destColOrdinal).cryptoMeta; JDBCType srcJdbcType = (null != sourceCryptoMeta) ? sourceCryptoMeta.baseTypeInfo.getSSType().getJDBCType() - : JDBCType.of(srcColumnMetadata.get(srcColOrdinal).jdbcType); + : JDBCType.of(srcColumnMetadata.get(srcColOrdinal).jdbcType); - SSType destSSType = (null != destCryptoMeta) ? destCryptoMeta.baseTypeInfo.getSSType() : destColumnMetadata.get(destColOrdinal).ssType; + SSType destSSType = (null != destCryptoMeta) ? destCryptoMeta.baseTypeInfo.getSSType() + : destColumnMetadata.get(destColOrdinal).ssType; // Throw if the source type cannot be converted to the destination type. if (!srcJdbcType.convertsTo(destSSType)) { @@ -1260,13 +1224,12 @@ private void validateDataTypeConversions(int srcColOrdinal, } } - private String getDestTypeFromSrcType(int srcColIndx, - int destColIndx, + private String getDestTypeFromSrcType(int srcColIndx, int destColIndx, TDSWriter tdsWriter) throws SQLServerException { boolean isStreaming; - SSType destSSType = (null != destColumnMetadata.get(destColIndx).cryptoMeta) - ? destColumnMetadata.get(destColIndx).cryptoMeta.baseTypeInfo.getSSType() : destColumnMetadata.get(destColIndx).ssType; + SSType destSSType = (null != destColumnMetadata.get(destColIndx).cryptoMeta) ? destColumnMetadata + .get(destColIndx).cryptoMeta.baseTypeInfo.getSSType() : destColumnMetadata.get(destColIndx).ssType; int bulkJdbcType, bulkPrecision, bulkScale; int srcPrecision; @@ -1285,8 +1248,7 @@ private String getDestTypeFromSrcType(int srcColIndx, // if destination is encrypted send metadata from destination and not from source if (DataTypes.SHORT_VARTYPE_MAX_BYTES < destPrecision) { return "varbinary(max)"; - } - else { + } else { return "varbinary(" + destColumnMetadata.get(destColIndx).precision + ")"; } } @@ -1299,22 +1261,24 @@ private String getDestTypeFromSrcType(int srcColIndx, bulkPrecision = validateSourcePrecision(srcPrecision, bulkJdbcType, destPrecision); /* - * if source is encrypted and destination is unenecrypted, use destination's sql type to send since there is no way of finding if source is - * encrypted without accessing the resultset. - * - * Send destination type if source resultset set is of type SQLServer, encryption is enabled and destination column is not encrypted + * if source is encrypted and destination is unenecrypted, use destination's sql type to send since there is no + * way of finding if source is encrypted without accessing the resultset. Send destination type if source + * resultset set is of type SQLServer, encryption is enabled and destination column is not encrypted */ - if ((sourceResultSet instanceof SQLServerResultSet) && (connection.isColumnEncryptionSettingEnabled()) && (null != destCryptoMeta)) { + if ((sourceResultSet instanceof SQLServerResultSet) && (connection.isColumnEncryptionSettingEnabled()) + && (null != destCryptoMeta)) { bulkJdbcType = destColumnMetadata.get(destColIndx).jdbcType; bulkPrecision = destPrecision; bulkScale = destColumnMetadata.get(destColIndx).scale; } - if ((java.sql.Types.NCHAR == bulkJdbcType) || (java.sql.Types.NVARCHAR == bulkJdbcType) || (java.sql.Types.LONGNVARCHAR == bulkJdbcType)) { - isStreaming = (DataTypes.SHORT_VARTYPE_MAX_CHARS < srcPrecision) || (DataTypes.SHORT_VARTYPE_MAX_CHARS < destPrecision); - } - else { - isStreaming = (DataTypes.SHORT_VARTYPE_MAX_BYTES < srcPrecision) || (DataTypes.SHORT_VARTYPE_MAX_BYTES < destPrecision); + if ((java.sql.Types.NCHAR == bulkJdbcType) || (java.sql.Types.NVARCHAR == bulkJdbcType) + || (java.sql.Types.LONGNVARCHAR == bulkJdbcType)) { + isStreaming = (DataTypes.SHORT_VARTYPE_MAX_CHARS < srcPrecision) + || (DataTypes.SHORT_VARTYPE_MAX_CHARS < destPrecision); + } else { + isStreaming = (DataTypes.SHORT_VARTYPE_MAX_BYTES < srcPrecision) + || (DataTypes.SHORT_VARTYPE_MAX_BYTES < destPrecision); } // SQL Server does not convert string to binary, we will have to explicitly convert before sending. @@ -1323,7 +1287,8 @@ private String getDestTypeFromSrcType(int srcColIndx, return "varbinary(max)"; else // Return binary(n) or varbinary(n) or varbinary(max) depending on destination type/precision. - return destSSType.toString() + "(" + ((DataTypes.SHORT_VARTYPE_MAX_BYTES < destPrecision) ? "max" : destPrecision) + ")"; + return destSSType.toString() + "(" + + ((DataTypes.SHORT_VARTYPE_MAX_BYTES < destPrecision) ? "max" : destPrecision) + ")"; } switch (bulkJdbcType) { @@ -1370,8 +1335,7 @@ private String getDestTypeFromSrcType(int srcColIndx, // Doesn't need to match with the exact size of data or with the destination column size. if (isStreaming) { return "varchar(max)"; - } - else { + } else { return "varchar(" + bulkPrecision + ")"; } @@ -1381,8 +1345,7 @@ private String getDestTypeFromSrcType(int srcColIndx, case java.sql.Types.NVARCHAR: if (isStreaming) { return "NVARCHAR(MAX)"; - } - else { + } else { return "NVARCHAR(" + bulkPrecision + ")"; } @@ -1403,74 +1366,73 @@ private String getDestTypeFromSrcType(int srcColIndx, switch (destSSType) { case SMALLDATETIME: if (null != sourceBulkRecord) { - return "varchar(" + ((0 == bulkPrecision) ? sourceBulkRecordTemporalMaxPrecision : bulkPrecision) + ")"; - } - else { + return "varchar(" + + ((0 == bulkPrecision) ? sourceBulkRecordTemporalMaxPrecision : bulkPrecision) + + ")"; + } else { return "smalldatetime"; } case DATETIME: if (null != sourceBulkRecord) { - return "varchar(" + ((0 == bulkPrecision) ? sourceBulkRecordTemporalMaxPrecision : bulkPrecision) + ")"; - } - else { + return "varchar(" + + ((0 == bulkPrecision) ? sourceBulkRecordTemporalMaxPrecision : bulkPrecision) + + ")"; + } else { return "datetime"; } default: // datetime2 /* - * If encrypted, varbinary will be returned before. The code will come here only if unencrypted. For unencrypted bulk copy if - * the source is CSV, we send the data as varchar and SQL Server will do the conversion. if the source is ResultSet, we send - * the data as the corresponding temporal type. + * If encrypted, varbinary will be returned before. The code will come here only if unencrypted. + * For unencrypted bulk copy if the source is CSV, we send the data as varchar and SQL Server + * will do the conversion. if the source is ResultSet, we send the data as the corresponding + * temporal type. */ if (null != sourceBulkRecord) { return "varchar(" + ((0 == bulkPrecision) ? destPrecision : bulkPrecision) + ")"; - } - else { + } else { return "datetime2(" + bulkScale + ")"; } } case java.sql.Types.DATE: /* - * If encrypted, varbinary will be returned before. The code will come here only if unencrypted. For unencrypted bulk copy if the - * source is CSV, we send the data as varchar and SQL Server will do the conversion. if the source is ResultSet, we send the data as - * the corresponding temporal type. + * If encrypted, varbinary will be returned before. The code will come here only if unencrypted. For + * unencrypted bulk copy if the source is CSV, we send the data as varchar and SQL Server will do the + * conversion. if the source is ResultSet, we send the data as the corresponding temporal type. */ if (null != sourceBulkRecord) { return "varchar(" + ((0 == bulkPrecision) ? destPrecision : bulkPrecision) + ")"; - } - else { + } else { return "date"; } case java.sql.Types.TIME: /* - * If encrypted, varbinary will be returned before. The code will come here only if unencrypted. For unencrypted bulk copy if the - * source is CSV, we send the data as varchar and SQL Server will do the conversion. if the source is ResultSet, we send the data as - * the corresponding temporal type. + * If encrypted, varbinary will be returned before. The code will come here only if unencrypted. For + * unencrypted bulk copy if the source is CSV, we send the data as varchar and SQL Server will do the + * conversion. if the source is ResultSet, we send the data as the corresponding temporal type. */ if (null != sourceBulkRecord) { return "varchar(" + ((0 == bulkPrecision) ? destPrecision : bulkPrecision) + ")"; - } - else { + } else { return "time(" + bulkScale + ")"; } // Return DATETIMEOFFSET for TIME_WITH_TIMEZONE and TIMESTAMP_WITH_TIMEZONE - case 2013: // java.sql.Types.TIME_WITH_TIMEZONE - case 2014: // java.sql.Types.TIMESTAMP_WITH_TIMEZONE + case 2013: // java.sql.Types.TIME_WITH_TIMEZONE + case 2014: // java.sql.Types.TIMESTAMP_WITH_TIMEZONE return "datetimeoffset(" + bulkScale + ")"; case microsoft.sql.Types.DATETIMEOFFSET: /* - * If encrypted, varbinary will be returned before. The code will come here only if unencrypted. For unencrypted bulk copy if the - * source is CSV, we send the data as varchar and SQL Server will do the conversion. if the source is ResultSet, we send the data as - * the corresponding temporal type. + * If encrypted, varbinary will be returned before. The code will come here only if unencrypted. For + * unencrypted bulk copy if the source is CSV, we send the data as varchar and SQL Server will do the + * conversion. if the source is ResultSet, we send the data as the corresponding temporal type. */ if (null != sourceBulkRecord) { return "varchar(" + ((0 == bulkPrecision) ? destPrecision : bulkPrecision) + ")"; - } - else { + } else { return "datetimeoffset(" + bulkScale + ")"; } case microsoft.sql.Types.SQL_VARIANT: @@ -1495,14 +1457,16 @@ private String createInsertBulkCommand(TDSWriter tdsWriter) throws SQLServerExce endColumn = " ) "; } ColumnMapping colMapping = columnMappings.get(i); - String columnCollation = destColumnMetadata.get(columnMappings.get(i).destinationColumnOrdinal).collationName; + String columnCollation = destColumnMetadata + .get(columnMappings.get(i).destinationColumnOrdinal).collationName; String addCollate = ""; - String destType = getDestTypeFromSrcType(colMapping.sourceColumnOrdinal, colMapping.destinationColumnOrdinal, tdsWriter) - .toUpperCase(Locale.ENGLISH); + String destType = getDestTypeFromSrcType(colMapping.sourceColumnOrdinal, + colMapping.destinationColumnOrdinal, tdsWriter).toUpperCase(Locale.ENGLISH); if (null != columnCollation && columnCollation.trim().length() > 0) { // we are adding collate in command only for char and varchar - if (null != destType && (destType.toLowerCase(Locale.ENGLISH).trim().startsWith("char") || destType.toLowerCase(Locale.ENGLISH).trim().startsWith("varchar"))) + if (null != destType && (destType.toLowerCase(Locale.ENGLISH).trim().startsWith("char") + || destType.toLowerCase(Locale.ENGLISH).trim().startsWith("varchar"))) addCollate = " COLLATE " + columnCollation; } if (colMapping.destinationColumnName.contains("]")) { @@ -1560,7 +1524,7 @@ private boolean doInsertBulk(TDSCommand command) throws SQLServerException { // Begin a manual transaction for this batch. connection.setAutoCommit(false); } - + boolean insertRowByRow = false; if (null != sourceResultSet && sourceResultSet instanceof SQLServerResultSet) { @@ -1570,13 +1534,13 @@ private boolean doInsertBulk(TDSCommand command) throws SQLServerException { if (connection.equals(src_stmt.getConnection()) && 0 != resultSetServerCursorId) { insertRowByRow = true; } - + if (((SQLServerResultSet) sourceResultSet).isForwardOnly()) { try { sourceResultSet.setFetchSize(1); - } - catch (SQLException e) { - SQLServerException.makeFromDriverError(connection, sourceResultSet, e.getMessage(), e.getSQLState(), true); + } catch (SQLException e) { + SQLServerException.makeFromDriverError(connection, sourceResultSet, e.getMessage(), e.getSQLState(), + true); } } } @@ -1592,12 +1556,10 @@ private boolean doInsertBulk(TDSCommand command) throws SQLServerException { try { // Write all ROW tokens in the stream. moreDataAvailable = writeBatchData(tdsWriter, command, insertRowByRow); - } - finally { + } finally { tdsWriter = command.getTDSWriter(); } - } - catch (SQLServerException ex) { + } catch (SQLServerException ex) { if (null == tdsWriter) { tdsWriter = command.getTDSWriter(); } @@ -1613,19 +1575,19 @@ private boolean doInsertBulk(TDSCommand command) throws SQLServerException { command.onRequestComplete(); throw ex; - } - finally { + } finally { if (null == tdsWriter) { tdsWriter = command.getTDSWriter(); } - + // reset the cryptoMeta in IOBuffer tdsWriter.setCryptoMetaData(null); } - + if (!insertRowByRow) { // Write the DONE token in the stream. We may have to append the DONE token with every packet that is sent. - // For the current packets the driver does not generate a DONE token, but the BulkLoadBCP stream needs a DONE token + // For the current packets the driver does not generate a DONE token, but the BulkLoadBCP stream needs a + // DONE token // after every packet. For now add it manually here for one packet. // Note: This may break if more than one packet is sent. // This is an example from https://msdn.microsoft.com/en-us/library/dd340549.aspx @@ -1666,7 +1628,7 @@ private void writePacketDataDone(TDSWriter tdsWriter) throws SQLServerException tdsWriter.writeInt(0); } - /* + /** * Helper method to throw a SQLServerExeption with the invalidArgument message and given argument. */ private void throwInvalidArgument(String argument) throws SQLServerException { @@ -1675,16 +1637,15 @@ private void throwInvalidArgument(String argument) throws SQLServerException { SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), null, false); } - /* + /** * Helper method to throw a SQLServerExeption with the errorConvertingValue message and given arguments. */ - private void throwInvalidJavaToJDBC(String javaClassName, - int jdbcType) throws SQLServerException { + private void throwInvalidJavaToJDBC(String javaClassName, int jdbcType) throws SQLServerException { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_errorConvertingValue")); throw new SQLServerException(form.format(new Object[] {javaClassName, jdbcType}), null, 0, null); } - /* + /** * The bulk copy operation */ private void writeToServer() throws SQLServerException { @@ -1715,28 +1676,24 @@ private void writeToServer() throws SQLServerException { } } - private void validateStringBinaryLengths(Object colValue, - int srcCol, - int destCol) throws SQLServerException { + private void validateStringBinaryLengths(Object colValue, int srcCol, int destCol) throws SQLServerException { int sourcePrecision; int destPrecision = destColumnMetadata.get(destCol).precision; int srcJdbcType = srcColumnMetadata.get(srcCol).jdbcType; SSType destSSType = destColumnMetadata.get(destCol).ssType; - if ((Util.isCharType(srcJdbcType) && Util.isCharType(destSSType)) || (Util.isBinaryType(srcJdbcType) && Util.isBinaryType(destSSType))) { + if ((Util.isCharType(srcJdbcType) && Util.isCharType(destSSType)) + || (Util.isBinaryType(srcJdbcType) && Util.isBinaryType(destSSType))) { if (colValue instanceof String) { - if (Util.isBinaryType(destSSType)) { - // if the dest value is binary and the value is of type string. - //Repro in test case: ImpISQLServerBulkRecord_IssuesTest#testSendValidValueforBinaryColumnAsString + if (Util.isBinaryType(destSSType)) { + // if the dest value is binary and the value is of type string. + // Repro in test case: ImpISQLServerBulkRecord_IssuesTest#testSendValidValueforBinaryColumnAsString sourcePrecision = (((String) colValue).getBytes().length) / 2; - } - else + } else sourcePrecision = ((String) colValue).length(); - } - else if (colValue instanceof byte[]) { + } else if (colValue instanceof byte[]) { sourcePrecision = ((byte[]) colValue).length; - } - else { + } else { return; } @@ -1750,28 +1707,29 @@ else if (colValue instanceof byte[]) { } } - /* - * Retrieves the column metadata for the destination table (and saves it for later) + /** + * Returns the column metadata for the destination table (and saves it for later) */ private void getDestinationMetadata() throws SQLServerException { if (null == destinationTableName) { - SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_invalidDestinationTable"), null, false); + SQLServerException.makeFromDriverError(null, null, + SQLServerException.getErrString("R_invalidDestinationTable"), null, false); } SQLServerResultSet rs = null; SQLServerResultSet rsMoreMetaData = null; SQLServerStatement stmt = null; - + try { if (null != destinationTableMetadata) { rs = (SQLServerResultSet) destinationTableMetadata; - } - else { - stmt = (SQLServerStatement) connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, - connection.getHoldability(), stmtColumnEncriptionSetting); + } else { + stmt = (SQLServerStatement) connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, + ResultSet.CONCUR_READ_ONLY, connection.getHoldability(), stmtColumnEncriptionSetting); // Get destination metadata - rs = stmt.executeQueryInternal("sp_executesql N'SET FMTONLY ON SELECT * FROM " + destinationTableName + " '"); + rs = stmt.executeQueryInternal( + "sp_executesql N'SET FMTONLY ON SELECT * FROM " + destinationTableName + " '"); } destColumnCount = rs.getMetaData().getColumnCount(); @@ -1781,34 +1739,31 @@ private void getDestinationMetadata() throws SQLServerException { if (!connection.getServerSupportsColumnEncryption()) { // SQL server prior to 2016 does not support encryption_type rsMoreMetaData = ((SQLServerStatement) connection.createStatement()) - .executeQueryInternal("select collation_name from sys.columns where " + "object_id=OBJECT_ID('" + destinationTableName + "') " - + "order by column_id ASC"); - } - else { - rsMoreMetaData = ((SQLServerStatement) connection.createStatement()) - .executeQueryInternal("select collation_name, encryption_type from sys.columns where " + "object_id=OBJECT_ID('" + .executeQueryInternal("select collation_name from sys.columns where " + "object_id=OBJECT_ID('" + destinationTableName + "') " + "order by column_id ASC"); + } else { + rsMoreMetaData = ((SQLServerStatement) connection.createStatement()) + .executeQueryInternal("select collation_name, encryption_type from sys.columns where " + + "object_id=OBJECT_ID('" + destinationTableName + "') " + "order by column_id ASC"); } for (int i = 1; i <= destColumnCount; ++i) { if (rsMoreMetaData.next()) { if (!connection.getServerSupportsColumnEncryption()) { - destColumnMetadata.put(i, new BulkColumnMetaData(rs.getColumn(i), rsMoreMetaData.getString("collation_name"), null)); - } - else { - destColumnMetadata.put(i, new BulkColumnMetaData(rs.getColumn(i), rsMoreMetaData.getString("collation_name"), - rsMoreMetaData.getString("encryption_type"))); - } - } - else { + destColumnMetadata.put(i, new BulkColumnMetaData(rs.getColumn(i), + rsMoreMetaData.getString("collation_name"), null)); + } else { + destColumnMetadata.put(i, + new BulkColumnMetaData(rs.getColumn(i), rsMoreMetaData.getString("collation_name"), + rsMoreMetaData.getString("encryption_type"))); + } + } else { destColumnMetadata.put(i, new BulkColumnMetaData(rs.getColumn(i))); } } - } - catch (SQLException e) { + } catch (SQLException e) { // Unable to retrieve metadata for destination throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveColMeta"), e); - } - finally { + } finally { if (null != rs) rs.close(); if (null != stmt) @@ -1818,9 +1773,9 @@ private void getDestinationMetadata() throws SQLServerException { } } - /* - * Retrieves the column metadata for the source (and saves it for later). Retrieving source metadata in BulkColumnMetaData object helps to access - * source metadata from the same place for both ResultSet and File. + /** + * Returns the column metadata for the source (and saves it for later). Retrieving source metadata in + * BulkColumnMetaData object helps to access source metadata from the same place for both ResultSet and File. */ private void getSourceMetadata() throws SQLServerException { srcColumnMetadata = new HashMap<>(); @@ -1835,48 +1790,43 @@ private void getSourceMetadata() throws SQLServerException { sourceResultSetMetaData.getPrecision(i), sourceResultSetMetaData.getScale(i), sourceResultSetMetaData.getColumnType(i), null)); } - } - catch (SQLException e) { + } catch (SQLException e) { // Unable to retrieve meta data for destination throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveColMeta"), e); } - } - else if (null != sourceBulkRecord) { + } else if (null != sourceBulkRecord) { Set columnOrdinals = sourceBulkRecord.getColumnOrdinals(); if (null == columnOrdinals || 0 == columnOrdinals.size()) { throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveColMeta"), null); - } - else { + } else { srcColumnCount = columnOrdinals.size(); for (Integer columnOrdinal : columnOrdinals) { currentColumn = columnOrdinal; - srcColumnMetadata.put(currentColumn, - new BulkColumnMetaData(sourceBulkRecord.getColumnName(currentColumn), true, sourceBulkRecord.getPrecision(currentColumn), - sourceBulkRecord.getScale(currentColumn), sourceBulkRecord.getColumnType(currentColumn), - ((sourceBulkRecord instanceof SQLServerBulkCSVFileRecord) - ? ((SQLServerBulkCSVFileRecord) sourceBulkRecord).getColumnDateTimeFormatter(currentColumn) : null))); + srcColumnMetadata.put(currentColumn, new BulkColumnMetaData( + sourceBulkRecord.getColumnName(currentColumn), true, + sourceBulkRecord.getPrecision(currentColumn), sourceBulkRecord.getScale(currentColumn), + sourceBulkRecord.getColumnType(currentColumn), + ((sourceBulkRecord instanceof SQLServerBulkCSVFileRecord) ? ((SQLServerBulkCSVFileRecord) sourceBulkRecord) + .getColumnDateTimeFormatter(currentColumn) : null))); } } - } - else { + } else { // Unable to retrieve meta data for source throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveColMeta"), null); } } - /* + /** * Oracle 12c database returns precision = 0 for char/varchar data types. */ - private int validateSourcePrecision(int srcPrecision, - int srcJdbcType, - int destPrecision) { + private int validateSourcePrecision(int srcPrecision, int srcJdbcType, int destPrecision) { if ((1 > srcPrecision) && Util.isCharType(srcJdbcType)) { srcPrecision = destPrecision; } return srcPrecision; } - /* + /** * Validates the column mappings */ private void validateColumnMappings() throws SQLServerException { @@ -1885,8 +1835,8 @@ private void validateColumnMappings() throws SQLServerException { // Check that the source schema matches the destination schema // If the number of columns are different, there is an obvious mismatch. if (destColumnCount != srcColumnCount) { - throw new SQLServerException(SQLServerException.getErrString("R_schemaMismatch"), SQLState.COL_NOT_FOUND, DriverError.NOT_SET, - null); + throw new SQLServerException(SQLServerException.getErrString("R_schemaMismatch"), + SQLState.COL_NOT_FOUND, DriverError.NOT_SET, null); } // Could validate that the data types can be converted, but easier to leave that check for later @@ -1912,13 +1862,13 @@ private void validateColumnMappings() throws SQLServerException { if (j != currentOrdinal) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidColumn")); Object[] msgArgs = {currentOrdinal}; - throw new SQLServerException(form.format(msgArgs), SQLState.COL_NOT_FOUND, DriverError.NOT_SET, null); + throw new SQLServerException(form.format(msgArgs), SQLState.COL_NOT_FOUND, + DriverError.NOT_SET, null); } j++; } } - } - else { + } else { int numMappings = columnMappings.size(); ColumnMapping cm; @@ -1941,15 +1891,15 @@ private void validateColumnMappings() throws SQLServerException { if (!foundColumn) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidColumn")); Object[] msgArgs = {cm.destinationColumnName}; - throw new SQLServerException(form.format(msgArgs), SQLState.COL_NOT_FOUND, DriverError.NOT_SET, null); + throw new SQLServerException(form.format(msgArgs), SQLState.COL_NOT_FOUND, + DriverError.NOT_SET, null); } - } - else if (0 > cm.destinationColumnOrdinal || destColumnCount < cm.destinationColumnOrdinal) { + } else if (0 > cm.destinationColumnOrdinal || destColumnCount < cm.destinationColumnOrdinal) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidColumn")); Object[] msgArgs = {cm.destinationColumnOrdinal}; - throw new SQLServerException(form.format(msgArgs), SQLState.COL_NOT_FOUND, DriverError.NOT_SET, null); - } - else { + throw new SQLServerException(form.format(msgArgs), SQLState.COL_NOT_FOUND, DriverError.NOT_SET, + null); + } else { cm.destinationColumnName = destColumnMetadata.get(cm.destinationColumnOrdinal).columnName; } } @@ -1970,8 +1920,7 @@ else if (0 > cm.destinationColumnOrdinal || destColumnCount < cm.destinationColu break; } } - } - else { + } else { Set columnOrdinals = sourceBulkRecord.getColumnOrdinals(); for (Integer currentColumn : columnOrdinals) { if (sourceBulkRecord.getColumnName(currentColumn).equals(cm.sourceColumnName)) { @@ -1985,10 +1934,10 @@ else if (0 > cm.destinationColumnOrdinal || destColumnCount < cm.destinationColu if (!foundColumn) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidColumn")); Object[] msgArgs = {cm.sourceColumnName}; - throw new SQLServerException(form.format(msgArgs), SQLState.COL_NOT_FOUND, DriverError.NOT_SET, null); + throw new SQLServerException(form.format(msgArgs), SQLState.COL_NOT_FOUND, + DriverError.NOT_SET, null); } - } - else // Validate that the source column is in range + } else // Validate that the source column is in range { boolean columnOutOfRange = true; if (null != sourceResultSet) { @@ -1996,8 +1945,7 @@ else if (0 > cm.destinationColumnOrdinal || destColumnCount < cm.destinationColu if (0 < cm.sourceColumnOrdinal && columns >= cm.sourceColumnOrdinal) { columnOutOfRange = false; } - } - else { + } else { // check if the ordinal is in SQLServerBulkCSVFileRecord.addColumnMetadata() if (srcColumnMetadata.containsKey(cm.sourceColumnOrdinal)) { columnOutOfRange = false; @@ -2007,22 +1955,24 @@ else if (0 > cm.destinationColumnOrdinal || destColumnCount < cm.destinationColu if (columnOutOfRange) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidColumn")); Object[] msgArgs = {cm.sourceColumnOrdinal}; - throw new SQLServerException(form.format(msgArgs), SQLState.COL_NOT_FOUND, DriverError.NOT_SET, null); + throw new SQLServerException(form.format(msgArgs), SQLState.COL_NOT_FOUND, + DriverError.NOT_SET, null); } } // Remove mappings for identity column if KEEP IDENTITY OPTION is FALSE - if (destColumnMetadata.get(cm.destinationColumnOrdinal).isIdentity && !copyOptions.isKeepIdentity()) { + if (destColumnMetadata.get(cm.destinationColumnOrdinal).isIdentity + && !copyOptions.isKeepIdentity()) { columnMappings.remove(i); numMappings--; i--; } } } - } - catch (SQLException e) { + } catch (SQLException e) { // Let the column mapping validations go straight through as a single exception - if ((e instanceof SQLServerException) && (null != e.getSQLState()) && e.getSQLState().equals(SQLState.COL_NOT_FOUND.getSQLStateCode())) { + if ((e instanceof SQLServerException) && (null != e.getSQLState()) + && e.getSQLState().equals(SQLState.COL_NOT_FOUND.getSQLStateCode())) { throw (SQLServerException) e; } @@ -2033,12 +1983,12 @@ else if (0 > cm.destinationColumnOrdinal || destColumnCount < cm.destinationColu // Throw an exception is Column mapping is empty. // If keep identity option is set to be false and not other mapping is explicitly provided. if (columnMappings.isEmpty()) { - throw new SQLServerException(null, SQLServerException.getErrString("R_BulkColumnMappingsIsEmpty"), null, 0, false); + throw new SQLServerException(null, SQLServerException.getErrString("R_BulkColumnMappingsIsEmpty"), null, 0, + false); } } - private void writeNullToTdsWriter(TDSWriter tdsWriter, - int srcJdbcType, + private void writeNullToTdsWriter(TDSWriter tdsWriter, int srcJdbcType, boolean isStreaming) throws SQLServerException { switch (srcJdbcType) { @@ -2053,8 +2003,7 @@ private void writeNullToTdsWriter(TDSWriter tdsWriter, case java.sql.Types.LONGVARBINARY: if (isStreaming) { tdsWriter.writeLong(PLPInputStream.PLP_NULL); - } - else { + } else { tdsWriter.writeByte((byte) 0xFF); tdsWriter.writeByte((byte) 0xFF); } @@ -2071,8 +2020,8 @@ private void writeNullToTdsWriter(TDSWriter tdsWriter, case java.sql.Types.TIMESTAMP: case java.sql.Types.DATE: case java.sql.Types.TIME: - case 2013: // java.sql.Types.TIME_WITH_TIMEZONE - case 2014: // java.sql.Types.TIMESTAMP_WITH_TIMEZONE + case 2013: // java.sql.Types.TIME_WITH_TIMEZONE + case 2014: // java.sql.Types.TIMESTAMP_WITH_TIMEZONE case microsoft.sql.Types.DATETIMEOFFSET: tdsWriter.writeByte((byte) 0x00); return; @@ -2086,36 +2035,34 @@ private void writeNullToTdsWriter(TDSWriter tdsWriter, } } - private void writeColumnToTdsWriter(TDSWriter tdsWriter, - int bulkPrecision, - int bulkScale, - int bulkJdbcType, + private void writeColumnToTdsWriter(TDSWriter tdsWriter, int bulkPrecision, int bulkScale, int bulkJdbcType, boolean bulkNullable, // should it be destNullable instead? - int srcColOrdinal, - int destColOrdinal, - boolean isStreaming, - Object colValue) throws SQLServerException { + int srcColOrdinal, int destColOrdinal, boolean isStreaming, Object colValue) throws SQLServerException { SSType destSSType = destColumnMetadata.get(destColOrdinal).ssType; - bulkPrecision = validateSourcePrecision(bulkPrecision, bulkJdbcType, destColumnMetadata.get(destColOrdinal).precision); + bulkPrecision = validateSourcePrecision(bulkPrecision, bulkJdbcType, + destColumnMetadata.get(destColOrdinal).precision); CryptoMetadata sourceCryptoMeta = srcColumnMetadata.get(srcColOrdinal).cryptoMeta; - if (((null != destColumnMetadata.get(destColOrdinal).encryptionType) && copyOptions.isAllowEncryptedValueModifications()) + if (((null != destColumnMetadata.get(destColOrdinal).encryptionType) + && copyOptions.isAllowEncryptedValueModifications()) // if destination is encrypted send varbinary explicitly(needed for unencrypted source) || (null != destColumnMetadata.get(destColOrdinal).cryptoMeta)) { bulkJdbcType = java.sql.Types.VARBINARY; } /* - * if source is encrypted and destination is unenecrypted, use destination sql type to send since there is no way of finding if source is - * encrypted without accessing the resultset, send destination type if source resultset set is of type SQLServer and encryption is enabled + * if source is encrypted and destination is unenecrypted, use destination sql type to send since there is no + * way of finding if source is encrypted without accessing the resultset, send destination type if source + * resultset set is of type SQLServer and encryption is enabled */ else if (null != sourceCryptoMeta) { bulkJdbcType = destColumnMetadata.get(destColOrdinal).jdbcType; bulkScale = destColumnMetadata.get(destColOrdinal).scale; - } - else if (null != sourceBulkRecord) { - // Bulk copy from CSV and destination is not encrypted. In this case, we send the temporal types as varchar and - // SQL Server does the conversion. If destination is encrypted, then temporal types can not be sent as varchar. + } else if (null != sourceBulkRecord) { + // Bulk copy from CSV and destination is not encrypted. In this case, we send the temporal types as varchar + // and + // SQL Server does the conversion. If destination is encrypted, then temporal types can not be sent as + // varchar. switch (bulkJdbcType) { case java.sql.Types.DATE: case java.sql.Types.TIME: @@ -2129,13 +2076,13 @@ else if (null != sourceBulkRecord) { } try { - // We are sending the data using JDBCType and not using SSType as SQL Server will automatically do the conversion. + // We are sending the data using JDBCType and not using SSType as SQL Server will automatically do the + // conversion. switch (bulkJdbcType) { case java.sql.Types.INTEGER: if (null == colValue) { writeNullToTdsWriter(tdsWriter, bulkJdbcType, isStreaming); - } - else { + } else { if (bulkNullable) { tdsWriter.writeByte((byte) 0x04); } @@ -2146,8 +2093,7 @@ else if (null != sourceBulkRecord) { case java.sql.Types.SMALLINT: if (null == colValue) { writeNullToTdsWriter(tdsWriter, bulkJdbcType, isStreaming); - } - else { + } else { if (bulkNullable) { tdsWriter.writeByte((byte) 0x02); } @@ -2158,8 +2104,7 @@ else if (null != sourceBulkRecord) { case java.sql.Types.BIGINT: if (null == colValue) { writeNullToTdsWriter(tdsWriter, bulkJdbcType, isStreaming); - } - else { + } else { if (bulkNullable) { tdsWriter.writeByte((byte) 0x08); } @@ -2170,8 +2115,7 @@ else if (null != sourceBulkRecord) { case java.sql.Types.BIT: if (null == colValue) { writeNullToTdsWriter(tdsWriter, bulkJdbcType, isStreaming); - } - else { + } else { if (bulkNullable) { tdsWriter.writeByte((byte) 0x01); } @@ -2182,8 +2126,7 @@ else if (null != sourceBulkRecord) { case java.sql.Types.TINYINT: if (null == colValue) { writeNullToTdsWriter(tdsWriter, bulkJdbcType, isStreaming); - } - else { + } else { if (bulkNullable) { tdsWriter.writeByte((byte) 0x01); } @@ -2197,8 +2140,7 @@ else if (null != sourceBulkRecord) { case java.sql.Types.DOUBLE: if (null == colValue) { writeNullToTdsWriter(tdsWriter, bulkJdbcType, isStreaming); - } - else { + } else { if (bulkNullable) { tdsWriter.writeByte((byte) 0x08); } @@ -2209,8 +2151,7 @@ else if (null != sourceBulkRecord) { case java.sql.Types.REAL: if (null == colValue) { writeNullToTdsWriter(tdsWriter, bulkJdbcType, isStreaming); - } - else { + } else { if (bulkNullable) { tdsWriter.writeByte((byte) 0x04); } @@ -2224,17 +2165,19 @@ else if (null != sourceBulkRecord) { case java.sql.Types.NUMERIC: if (null == colValue) { writeNullToTdsWriter(tdsWriter, bulkJdbcType, isStreaming); - } - else { + } else { /* - * if the precision that user provides is smaller than the precision of the actual value, the driver assumes the precision - * that user provides is the correct precision, and throws exception + * if the precision that user provides is smaller than the precision of the actual value, the + * driver assumes the precision that user provides is the correct precision, and throws + * exception */ - if (bulkPrecision < Util.getValueLengthBaseOnJavaType(colValue, JavaType.of(colValue), null, null, - JDBCType.of(bulkJdbcType))) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_valueOutOfRange")); + if (bulkPrecision < Util.getValueLengthBaseOnJavaType(colValue, JavaType.of(colValue), null, + null, JDBCType.of(bulkJdbcType))) { + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_valueOutOfRange")); Object[] msgArgs = {SSType.DECIMAL}; - throw new SQLServerException(form.format(msgArgs), SQLState.DATA_EXCEPTION_LENGTH_MISMATCH, DriverError.NOT_SET, null); + throw new SQLServerException(form.format(msgArgs), SQLState.DATA_EXCEPTION_LENGTH_MISMATCH, + DriverError.NOT_SET, null); } tdsWriter.writeBigDecimal((BigDecimal) colValue, bulkJdbcType, bulkPrecision, bulkScale); } @@ -2242,17 +2185,18 @@ else if (null != sourceBulkRecord) { case microsoft.sql.Types.GUID: case java.sql.Types.LONGVARCHAR: - case java.sql.Types.CHAR: // Fixed-length, non-Unicode string data. - case java.sql.Types.VARCHAR: // Variable-length, non-Unicode string data. + case java.sql.Types.CHAR: // Fixed-length, non-Unicode string data. + case java.sql.Types.VARCHAR: // Variable-length, non-Unicode string data. if (isStreaming) // PLP { // PLP_BODY rule in TDS - // Use ResultSet.getString for non-streaming data and ResultSet.getCharacterStream() for streaming data, - // so that if the source data source does not have streaming enabled, the smaller size data will still work. + // Use ResultSet.getString for non-streaming data and ResultSet.getCharacterStream() for + // streaming data, + // so that if the source data source does not have streaming enabled, the smaller size data will + // still work. if (null == colValue) { writeNullToTdsWriter(tdsWriter, bulkJdbcType, isStreaming); - } - else { + } else { // Send length as unknown. tdsWriter.writeLong(PLPInputStream.UNKNOWN_PLP_LEN); try { @@ -2261,59 +2205,56 @@ else if (null != sourceBulkRecord) { Reader reader; if (colValue instanceof Reader) { reader = (Reader) colValue; - } - else { + } else { reader = new StringReader(colValue.toString()); } - if ((SSType.BINARY == destSSType) || (SSType.VARBINARY == destSSType) || (SSType.VARBINARYMAX == destSSType) - || (SSType.IMAGE == destSSType)) { - tdsWriter.writeNonUnicodeReader(reader, DataTypes.UNKNOWN_STREAM_LENGTH, true, null); - } - else { + if ((SSType.BINARY == destSSType) || (SSType.VARBINARY == destSSType) + || (SSType.VARBINARYMAX == destSSType) || (SSType.IMAGE == destSSType)) { + tdsWriter.writeNonUnicodeReader(reader, DataTypes.UNKNOWN_STREAM_LENGTH, true, + null); + } else { SQLCollation destCollation = destColumnMetadata.get(destColOrdinal).collation; if (null != destCollation) { - tdsWriter.writeNonUnicodeReader(reader, DataTypes.UNKNOWN_STREAM_LENGTH, false, destCollation.getCharset()); - } - else { - tdsWriter.writeNonUnicodeReader(reader, DataTypes.UNKNOWN_STREAM_LENGTH, false, null); + tdsWriter.writeNonUnicodeReader(reader, DataTypes.UNKNOWN_STREAM_LENGTH, false, + destCollation.getCharset()); + } else { + tdsWriter.writeNonUnicodeReader(reader, DataTypes.UNKNOWN_STREAM_LENGTH, false, + null); } } reader.close(); - } - catch (IOException e) { - throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveSourceData"), e); + } catch (IOException e) { + throw new SQLServerException( + SQLServerException.getErrString("R_unableRetrieveSourceData"), e); } } - } - else // Non-PLP + } else // Non-PLP { if (null == colValue) { writeNullToTdsWriter(tdsWriter, bulkJdbcType, isStreaming); - } - else { + } else { String colValueStr = colValue.toString(); if ((SSType.BINARY == destSSType) || (SSType.VARBINARY == destSSType)) { byte[] bytes = null; try { bytes = ParameterUtils.HexToBin(colValueStr); - } - catch (SQLServerException e) { - throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveSourceData"), e); + } catch (SQLServerException e) { + throw new SQLServerException( + SQLServerException.getErrString("R_unableRetrieveSourceData"), e); } tdsWriter.writeShort((short) bytes.length); tdsWriter.writeBytes(bytes); - } - else { + } else { tdsWriter.writeShort((short) (colValueStr.length())); // converting string into destination collation using Charset SQLCollation destCollation = destColumnMetadata.get(destColOrdinal).collation; if (null != destCollation) { - tdsWriter.writeBytes(colValueStr.getBytes(destColumnMetadata.get(destColOrdinal).collation.getCharset())); + tdsWriter.writeBytes(colValueStr + .getBytes(destColumnMetadata.get(destColOrdinal).collation.getCharset())); - } - else { + } else { tdsWriter.writeBytes(colValueStr.getBytes()); } } @@ -2322,21 +2263,23 @@ else if (null != sourceBulkRecord) { break; /* - * The length value associated with these data types is specified within a USHORT. see MS-TDS.pdf page 38. However, nchar(n) - * nvarchar(n) supports n = 1 .. 4000 (see MSDN SQL 2014, SQL 2016 Transact-SQL) NVARCHAR/NCHAR/LONGNVARCHAR is not compatible with - * BINARY/VARBINARY as specified in enum UpdaterConversion of DataTypes.java + * The length value associated with these data types is specified within a USHORT. see MS-TDS.pdf page + * 38. However, nchar(n) nvarchar(n) supports n = 1 .. 4000 (see MSDN SQL 2014, SQL 2016 Transact-SQL) + * NVARCHAR/NCHAR/LONGNVARCHAR is not compatible with BINARY/VARBINARY as specified in enum + * UpdaterConversion of DataTypes.java */ case java.sql.Types.LONGNVARCHAR: case java.sql.Types.NCHAR: case java.sql.Types.NVARCHAR: if (isStreaming) { // PLP_BODY rule in TDS - // Use ResultSet.getString for non-streaming data and ResultSet.getNCharacterStream() for streaming data, - // so that if the source data source does not have streaming enabled, the smaller size data will still work. + // Use ResultSet.getString for non-streaming data and ResultSet.getNCharacterStream() for + // streaming data, + // so that if the source data source does not have streaming enabled, the smaller size data will + // still work. if (null == colValue) { writeNullToTdsWriter(tdsWriter, bulkJdbcType, isStreaming); - } - else { + } else { // Send length as unknown. tdsWriter.writeLong(PLPInputStream.UNKNOWN_PLP_LEN); try { @@ -2344,25 +2287,22 @@ else if (null != sourceBulkRecord) { Reader reader; if (colValue instanceof Reader) { reader = (Reader) colValue; - } - else { + } else { reader = new StringReader(colValue.toString()); } // writeReader is unicode. tdsWriter.writeReader(reader, DataTypes.UNKNOWN_STREAM_LENGTH, true); reader.close(); - } - catch (IOException e) { - throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveSourceData"), e); + } catch (IOException e) { + throw new SQLServerException( + SQLServerException.getErrString("R_unableRetrieveSourceData"), e); } } - } - else { + } else { if (null == colValue) { writeNullToTdsWriter(tdsWriter, bulkJdbcType, isStreaming); - } - else { + } else { int stringLength = colValue.toString().length(); byte[] typevarlen = new byte[2]; typevarlen[0] = (byte) (2 * stringLength & 0xFF); @@ -2378,12 +2318,12 @@ else if (null != sourceBulkRecord) { case java.sql.Types.VARBINARY: if (isStreaming) // PLP { - // Check for null separately for streaming and non-streaming data types, there could be source data sources who + // Check for null separately for streaming and non-streaming data types, there could be source + // data sources who // does not support streaming data. if (null == colValue) { writeNullToTdsWriter(tdsWriter, bulkJdbcType, isStreaming); - } - else { + } else { // Send length as unknown. tdsWriter.writeLong(PLPInputStream.UNKNOWN_PLP_LEN); try { @@ -2391,39 +2331,35 @@ else if (null != sourceBulkRecord) { InputStream iStream; if (colValue instanceof InputStream) { iStream = (InputStream) colValue; - } - else { + } else { if (colValue instanceof byte[]) { iStream = new ByteArrayInputStream((byte[]) colValue); - } - else - iStream = new ByteArrayInputStream(ParameterUtils.HexToBin(colValue.toString())); + } else + iStream = new ByteArrayInputStream( + ParameterUtils.HexToBin(colValue.toString())); } // We do not need to check for null values here as it is already checked above. tdsWriter.writeStream(iStream, DataTypes.UNKNOWN_STREAM_LENGTH, true); iStream.close(); - } - catch (IOException e) { - throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveSourceData"), e); + } catch (IOException e) { + throw new SQLServerException( + SQLServerException.getErrString("R_unableRetrieveSourceData"), e); } } - } - else // Non-PLP + } else // Non-PLP { if (null == colValue) { writeNullToTdsWriter(tdsWriter, bulkJdbcType, isStreaming); - } - else { + } else { byte[] srcBytes; if (colValue instanceof byte[]) { srcBytes = (byte[]) colValue; - } - else { + } else { try { srcBytes = ParameterUtils.HexToBin(colValue.toString()); - } - catch (SQLServerException e) { - throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveSourceData"), e); + } catch (SQLServerException e) { + throw new SQLServerException( + SQLServerException.getErrString("R_unableRetrieveSourceData"), e); } } tdsWriter.writeShort((short) srcBytes.length); @@ -2437,8 +2373,7 @@ else if (null != sourceBulkRecord) { case java.sql.Types.TIMESTAMP: if (null == colValue) { writeNullToTdsWriter(tdsWriter, bulkJdbcType, isStreaming); - } - else { + } else { switch (destSSType) { case SMALLDATETIME: if (bulkNullable) @@ -2450,7 +2385,7 @@ else if (null != sourceBulkRecord) { tdsWriter.writeByte((byte) 0x08); tdsWriter.writeDatetime(colValue.toString()); break; - default: // DATETIME2 + default: // DATETIME2 if (bulkNullable) { if (2 >= bulkScale) tdsWriter.writeByte((byte) 0x06); @@ -2470,8 +2405,7 @@ else if (4 >= bulkScale) case java.sql.Types.DATE: if (null == colValue) { writeNullToTdsWriter(tdsWriter, bulkJdbcType, isStreaming); - } - else { + } else { tdsWriter.writeByte((byte) 0x03); tdsWriter.writeDate(colValue.toString()); } @@ -2483,8 +2417,7 @@ else if (4 >= bulkScale) // values are read as java.sql.Types.TIMESTAMP if srcJdbcType is java.sql.Types.TIME if (null == colValue) { writeNullToTdsWriter(tdsWriter, bulkJdbcType, isStreaming); - } - else { + } else { if (2 >= bulkScale) tdsWriter.writeByte((byte) 0x03); else if (4 >= bulkScale) @@ -2496,11 +2429,10 @@ else if (4 >= bulkScale) } break; - case 2013: // java.sql.Types.TIME_WITH_TIMEZONE + case 2013: // java.sql.Types.TIME_WITH_TIMEZONE if (null == colValue) { writeNullToTdsWriter(tdsWriter, bulkJdbcType, isStreaming); - } - else { + } else { if (2 >= bulkScale) tdsWriter.writeByte((byte) 0x08); else if (4 >= bulkScale) @@ -2512,11 +2444,10 @@ else if (4 >= bulkScale) } break; - case 2014: // java.sql.Types.TIMESTAMP_WITH_TIMEZONE + case 2014: // java.sql.Types.TIMESTAMP_WITH_TIMEZONE if (null == colValue) { writeNullToTdsWriter(tdsWriter, bulkJdbcType, isStreaming); - } - else { + } else { if (2 >= bulkScale) tdsWriter.writeByte((byte) 0x08); else if (4 >= bulkScale) @@ -2529,11 +2460,11 @@ else if (4 >= bulkScale) break; case microsoft.sql.Types.DATETIMEOFFSET: - // We can safely cast the result set to a SQLServerResultSet as the DatetimeOffset type is only available in the JDBC driver. + // We can safely cast the result set to a SQLServerResultSet as the DatetimeOffset type is only + // available in the JDBC driver. if (null == colValue) { writeNullToTdsWriter(tdsWriter, bulkJdbcType, isStreaming); - } - else { + } else { if (2 >= bulkScale) tdsWriter.writeByte((byte) 0x08); else if (4 >= bulkScale) @@ -2550,7 +2481,8 @@ else if (4 >= bulkScale) MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_SQLVariantSupport")); throw new SQLServerException(null, form.format(new Object[] {}), null, 0, false); } - writeSqlVariant(tdsWriter, colValue, sourceResultSet, srcColOrdinal, destColOrdinal, bulkJdbcType, bulkScale, isStreaming); + writeSqlVariant(tdsWriter, colValue, sourceResultSet, srcColOrdinal, destColOrdinal, bulkJdbcType, + bulkScale, isStreaming); break; default: MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_BulkTypeNotSupported")); @@ -2558,8 +2490,7 @@ else if (4 >= bulkScale) SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), null, true); break; } // End of switch - } - catch (ClassCastException ex) { + } catch (ClassCastException ex) { if (null == colValue) { // this should not really happen, since ClassCastException should only happen when colValue is not null. // just do one more checking here to make sure @@ -2567,23 +2498,18 @@ else if (4 >= bulkScale) } MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_errorConvertingValue")); Object[] msgArgs = {colValue.getClass().getSimpleName(), JDBCType.of(bulkJdbcType)}; - throw new SQLServerException(form.format(msgArgs), SQLState.DATA_EXCEPTION_NOT_SPECIFIC, DriverError.NOT_SET, ex); + throw new SQLServerException(form.format(msgArgs), SQLState.DATA_EXCEPTION_NOT_SPECIFIC, + DriverError.NOT_SET, ex); } } - + /** * Writes sql_variant data based on the baseType for bulkcopy * * @throws SQLServerException */ - private void writeSqlVariant(TDSWriter tdsWriter, - Object colValue, - ResultSet sourceResultSet, - int srcColOrdinal, - int destColOrdinal, - int bulkJdbcType, - int bulkScale, - boolean isStreaming) throws SQLServerException { + private void writeSqlVariant(TDSWriter tdsWriter, Object colValue, ResultSet sourceResultSet, int srcColOrdinal, + int destColOrdinal, int bulkJdbcType, int bulkScale, boolean isStreaming) throws SQLServerException { if (null == colValue) { writeNullToTdsWriter(tdsWriter, bulkJdbcType, isStreaming); return; @@ -2603,32 +2529,32 @@ private void writeSqlVariant(TDSWriter tdsWriter, writeBulkCopySqlVariantHeader(10, TDSType.INT8.byteValue(), (byte) 0, tdsWriter); tdsWriter.writeLong(Long.valueOf(colValue.toString())); break; - + case INT4: writeBulkCopySqlVariantHeader(6, TDSType.INT4.byteValue(), (byte) 0, tdsWriter); tdsWriter.writeInt(Integer.valueOf(colValue.toString())); break; - + case INT2: writeBulkCopySqlVariantHeader(4, TDSType.INT2.byteValue(), (byte) 0, tdsWriter); tdsWriter.writeShort(Short.valueOf(colValue.toString())); break; - + case INT1: writeBulkCopySqlVariantHeader(3, TDSType.INT1.byteValue(), (byte) 0, tdsWriter); tdsWriter.writeByte(Byte.valueOf(colValue.toString())); break; - + case FLOAT8: writeBulkCopySqlVariantHeader(10, TDSType.FLOAT8.byteValue(), (byte) 0, tdsWriter); tdsWriter.writeDouble(Double.valueOf(colValue.toString())); break; - + case FLOAT4: writeBulkCopySqlVariantHeader(6, TDSType.FLOAT4.byteValue(), (byte) 0, tdsWriter); tdsWriter.writeReal(Float.valueOf(colValue.toString())); break; - + case MONEY8: // For decimalN we right TDSWriter.BIGDECIMAL_MAX_LENGTH as maximum length = 17 // 17 + 2 for basetype and probBytes + 2 for precision and length = 21 the length of data in header @@ -2637,96 +2563,101 @@ private void writeSqlVariant(TDSWriter tdsWriter, tdsWriter.writeByte((byte) 4); tdsWriter.writeSqlVariantInternalBigDecimal((BigDecimal) colValue, bulkJdbcType); break; - + case MONEY4: writeBulkCopySqlVariantHeader(21, TDSType.DECIMALN.byteValue(), (byte) 2, tdsWriter); tdsWriter.writeByte((byte) 38); tdsWriter.writeByte((byte) 4); tdsWriter.writeSqlVariantInternalBigDecimal((BigDecimal) colValue, bulkJdbcType); break; - + case BIT1: writeBulkCopySqlVariantHeader(3, TDSType.BIT1.byteValue(), (byte) 0, tdsWriter); tdsWriter.writeByte((byte) (((Boolean) colValue).booleanValue() ? 1 : 0)); break; - + case DATEN: writeBulkCopySqlVariantHeader(5, TDSType.DATEN.byteValue(), (byte) 0, tdsWriter); tdsWriter.writeDate(colValue.toString()); break; - + case TIMEN: - bulkScale = variantType.getScale(); + int timeBulkScale = variantType.getScale(); int timeHeaderLength = 0x08; // default - if (2 >= bulkScale) { + if (2 >= timeBulkScale) { timeHeaderLength = 0x06; - } - else if (4 >= bulkScale) { + } else if (4 >= timeBulkScale) { timeHeaderLength = 0x07; - } - else { + } else { timeHeaderLength = 0x08; } - writeBulkCopySqlVariantHeader(timeHeaderLength, TDSType.TIMEN.byteValue(), (byte) 1, tdsWriter); // depending on scale, the header + writeBulkCopySqlVariantHeader(timeHeaderLength, TDSType.TIMEN.byteValue(), (byte) 1, tdsWriter); // depending + // on + // scale, + // the + // header // length // defers - tdsWriter.writeByte((byte) bulkScale); - tdsWriter.writeTime((java.sql.Timestamp) colValue, bulkScale); + tdsWriter.writeByte((byte) timeBulkScale); + tdsWriter.writeTime((java.sql.Timestamp) colValue, timeBulkScale); break; - + case DATETIME8: writeBulkCopySqlVariantHeader(10, TDSType.DATETIME8.byteValue(), (byte) 0, tdsWriter); tdsWriter.writeDatetime(colValue.toString()); break; - + case DATETIME4: // when the type is ambiguous, we write to bigger type writeBulkCopySqlVariantHeader(10, TDSType.DATETIME8.byteValue(), (byte) 0, tdsWriter); tdsWriter.writeDatetime(colValue.toString()); break; - + case DATETIME2N: - writeBulkCopySqlVariantHeader(10, TDSType.DATETIME2N.byteValue(), (byte) 1, tdsWriter); // 1 is probbytes for time + writeBulkCopySqlVariantHeader(10, TDSType.DATETIME2N.byteValue(), (byte) 1, tdsWriter); // 1 is + // probbytes for + // time tdsWriter.writeByte((byte) 0x03); String timeStampValue = colValue.toString(); - tdsWriter.writeTime(java.sql.Timestamp.valueOf(timeStampValue), 0x03); // datetime2 in sql_variant has up to scale 3 support + tdsWriter.writeTime(java.sql.Timestamp.valueOf(timeStampValue), 0x03); // datetime2 in sql_variant has + // up to scale 3 support // Send only the date part tdsWriter.writeDate(timeStampValue.substring(0, timeStampValue.lastIndexOf(' '))); break; - + case BIGCHAR: int length = colValue.toString().length(); writeBulkCopySqlVariantHeader(9 + length, TDSType.BIGCHAR.byteValue(), (byte) 7, tdsWriter); - tdsWriter.writeCollationForSqlVariant(variantType); // writes collation info and sortID + tdsWriter.writeCollationForSqlVariant(variantType); // writes collation info and sortID tdsWriter.writeShort((short) (length)); SQLCollation destCollation = destColumnMetadata.get(destColOrdinal).collation; if (null != destCollation) { - tdsWriter.writeBytes(colValue.toString().getBytes(destColumnMetadata.get(destColOrdinal).collation.getCharset())); - } - else { + tdsWriter.writeBytes(colValue.toString() + .getBytes(destColumnMetadata.get(destColOrdinal).collation.getCharset())); + } else { tdsWriter.writeBytes(colValue.toString().getBytes()); } break; - + case BIGVARCHAR: length = colValue.toString().length(); writeBulkCopySqlVariantHeader(9 + length, TDSType.BIGVARCHAR.byteValue(), (byte) 7, tdsWriter); - tdsWriter.writeCollationForSqlVariant(variantType); // writes collation info and sortID + tdsWriter.writeCollationForSqlVariant(variantType); // writes collation info and sortID tdsWriter.writeShort((short) (length)); destCollation = destColumnMetadata.get(destColOrdinal).collation; if (null != destCollation) { - tdsWriter.writeBytes(colValue.toString().getBytes(destColumnMetadata.get(destColOrdinal).collation.getCharset())); - } - else { + tdsWriter.writeBytes(colValue.toString() + .getBytes(destColumnMetadata.get(destColOrdinal).collation.getCharset())); + } else { tdsWriter.writeBytes(colValue.toString().getBytes()); } break; - + case NCHAR: length = colValue.toString().length() * 2; writeBulkCopySqlVariantHeader(9 + length, TDSType.NCHAR.byteValue(), (byte) 7, tdsWriter); - tdsWriter.writeCollationForSqlVariant(variantType); // writes collation info and sortID + tdsWriter.writeCollationForSqlVariant(variantType); // writes collation info and sortID int stringLength = colValue.toString().length(); byte[] typevarlen = new byte[2]; typevarlen[0] = (byte) (2 * stringLength & 0xFF); @@ -2734,11 +2665,11 @@ else if (4 >= bulkScale) { tdsWriter.writeBytes(typevarlen); tdsWriter.writeString(colValue.toString()); break; - + case NVARCHAR: length = colValue.toString().length() * 2; writeBulkCopySqlVariantHeader(9 + length, TDSType.NVARCHAR.byteValue(), (byte) 7, tdsWriter); - tdsWriter.writeCollationForSqlVariant(variantType); // writes collation info and sortID + tdsWriter.writeCollationForSqlVariant(variantType); // writes collation info and sortID stringLength = colValue.toString().length(); typevarlen = new byte[2]; typevarlen[0] = (byte) (2 * stringLength & 0xFF); @@ -2746,27 +2677,28 @@ else if (4 >= bulkScale) { tdsWriter.writeBytes(typevarlen); tdsWriter.writeString(colValue.toString()); break; - + case GUID: length = colValue.toString().length(); writeBulkCopySqlVariantHeader(9 + length, TDSType.BIGCHAR.byteValue(), (byte) 7, tdsWriter); - // since while reading collation from sourceMetaData in guid we don't read collation, cause we are reading binary + // since while reading collation from sourceMetaData in guid we don't read collation, cause we are + // reading binary // but in writing it we are using char, we need to get the collation. - SQLCollation collation = (null != destColumnMetadata.get(srcColOrdinal).collation) ? destColumnMetadata.get(srcColOrdinal).collation - : connection.getDatabaseCollation(); + SQLCollation collation = (null != destColumnMetadata.get(srcColOrdinal).collation) ? destColumnMetadata + .get(srcColOrdinal).collation : connection.getDatabaseCollation(); variantType.setCollation(collation); - tdsWriter.writeCollationForSqlVariant(variantType); // writes collation info and sortID + tdsWriter.writeCollationForSqlVariant(variantType); // writes collation info and sortID tdsWriter.writeShort((short) (length)); // converting string into destination collation using Charset destCollation = destColumnMetadata.get(destColOrdinal).collation; if (null != destCollation) { - tdsWriter.writeBytes(colValue.toString().getBytes(destColumnMetadata.get(destColOrdinal).collation.getCharset())); - } - else { + tdsWriter.writeBytes(colValue.toString() + .getBytes(destColumnMetadata.get(destColOrdinal).collation.getCharset())); + } else { tdsWriter.writeBytes(colValue.toString().getBytes()); } break; - + case BIGBINARY: byte[] b = (byte[]) colValue; length = b.length; @@ -2774,24 +2706,22 @@ else if (4 >= bulkScale) { tdsWriter.writeShort((short) (variantType.getMaxLength())); // length if (null == colValue) { writeNullToTdsWriter(tdsWriter, bulkJdbcType, isStreaming); - } - else { + } else { byte[] srcBytes; if (colValue instanceof byte[]) { srcBytes = (byte[]) colValue; - } - else { + } else { try { srcBytes = ParameterUtils.HexToBin(colValue.toString()); - } - catch (SQLServerException e) { - throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveSourceData"), e); + } catch (SQLServerException e) { + throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveSourceData"), + e); } } tdsWriter.writeBytes(srcBytes); } break; - + case BIGVARBINARY: b = (byte[]) colValue; length = b.length; @@ -2799,24 +2729,22 @@ else if (4 >= bulkScale) { tdsWriter.writeShort((short) (variantType.getMaxLength())); // length if (null == colValue) { writeNullToTdsWriter(tdsWriter, bulkJdbcType, isStreaming); - } - else { + } else { byte[] srcBytes; if (colValue instanceof byte[]) { srcBytes = (byte[]) colValue; - } - else { + } else { try { srcBytes = ParameterUtils.HexToBin(colValue.toString()); - } - catch (SQLServerException e) { - throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveSourceData"), e); + } catch (SQLServerException e) { + throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveSourceData"), + e); } } tdsWriter.writeBytes(srcBytes); } break; - + default: MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_BulkTypeNotSupported")); Object[] msgArgs = {JDBCType.of(bulkJdbcType).toString().toLowerCase(Locale.ENGLISH)}; @@ -2824,44 +2752,43 @@ else if (4 >= bulkScale) { break; } } - + /** * Write header for sql_variant * * @param length: - * length of base type + Basetype + probBytes + * length of base type + Basetype + probBytes * @param tdsType * @param probBytes * @param tdsWriter * @throws SQLServerException */ - private void writeBulkCopySqlVariantHeader(int length, - byte tdsType, - byte probBytes, + private void writeBulkCopySqlVariantHeader(int length, byte tdsType, byte probBytes, TDSWriter tdsWriter) throws SQLServerException { tdsWriter.writeInt(length); tdsWriter.writeByte(tdsType); tdsWriter.writeByte(probBytes); } - private Object readColumnFromResultSet(int srcColOrdinal, - int srcJdbcType, - boolean isStreaming, + private Object readColumnFromResultSet(int srcColOrdinal, int srcJdbcType, boolean isStreaming, boolean isDestEncrypted) throws SQLServerException { CryptoMetadata srcCryptoMeta = null; // if source is encrypted read its baseTypeInfo if ((sourceResultSet instanceof SQLServerResultSet) - && (null != (srcCryptoMeta = ((SQLServerResultSet) sourceResultSet).getterGetColumn(srcColOrdinal).getCryptoMetadata()))) { + && (null != (srcCryptoMeta = ((SQLServerResultSet) sourceResultSet).getterGetColumn(srcColOrdinal) + .getCryptoMetadata()))) { srcJdbcType = srcCryptoMeta.baseTypeInfo.getSSType().getJDBCType().asJavaSqlType(); BulkColumnMetaData temp = srcColumnMetadata.get(srcColOrdinal); srcColumnMetadata.put(srcColOrdinal, new BulkColumnMetaData(temp, srcCryptoMeta)); } try { - // We are sending the data using JDBCType and not using SSType as SQL Server will automatically do the conversion. + // We are sending the data using JDBCType and not using SSType as SQL Server will automatically do the + // conversion. switch (srcJdbcType) { - // For numeric types (like, int, smallint, bit, ...) use getObject() instead of get* methods as get* methods + // For numeric types (like, int, smallint, bit, ...) use getObject() instead of get* methods as get* + // methods // return 0 if the value is null. // Change getObject to get* as other data sources may not have similar implementation. case java.sql.Types.INTEGER: @@ -2881,19 +2808,20 @@ private Object readColumnFromResultSet(int srcColOrdinal, case microsoft.sql.Types.GUID: case java.sql.Types.LONGVARCHAR: - case java.sql.Types.CHAR: // Fixed-length, non-Unicode string data. - case java.sql.Types.VARCHAR: // Variable-length, non-Unicode string data. + case java.sql.Types.CHAR: // Fixed-length, non-Unicode string data. + case java.sql.Types.VARCHAR: // Variable-length, non-Unicode string data. // PLP if stream type and both the source and destination are not encrypted // This is because AE does not support streaming types. // Therefore an encrypted source or destination means the data must not actually be streaming data if (isStreaming && !isDestEncrypted && (null == srcCryptoMeta)) // PLP { - // Use ResultSet.getString for non-streaming data and ResultSet.getCharacterStream() for streaming data, - // so that if the source data source does not have streaming enabled, the smaller size data will still work. + // Use ResultSet.getString for non-streaming data and ResultSet.getCharacterStream() for + // streaming data, + // so that if the source data source does not have streaming enabled, the smaller size data will + // still work. return sourceResultSet.getCharacterStream(srcColOrdinal); - } - else // Non-PLP + } else // Non-PLP { return sourceResultSet.getString(srcColOrdinal); } @@ -2906,11 +2834,12 @@ private Object readColumnFromResultSet(int srcColOrdinal, // Therefore an encrypted source or destination means the data must not actually be streaming data if (isStreaming && !isDestEncrypted && (null == srcCryptoMeta)) // PLP { - // Use ResultSet.getString for non-streaming data and ResultSet.getNCharacterStream() for streaming data, - // so that if the source data source does not have streaming enabled, the smaller size data will still work. + // Use ResultSet.getString for non-streaming data and ResultSet.getNCharacterStream() for + // streaming data, + // so that if the source data source does not have streaming enabled, the smaller size data will + // still work. return sourceResultSet.getNCharacterStream(srcColOrdinal); - } - else { + } else { return sourceResultSet.getObject(srcColOrdinal); } @@ -2923,8 +2852,7 @@ private Object readColumnFromResultSet(int srcColOrdinal, if (isStreaming && !isDestEncrypted && (null == srcCryptoMeta)) // PLP { return sourceResultSet.getBinaryStream(srcColOrdinal); - } - else // Non-PLP + } else // Non-PLP { return sourceResultSet.getBytes(srcColOrdinal); } @@ -2942,10 +2870,11 @@ private Object readColumnFromResultSet(int srcColOrdinal, return sourceResultSet.getDate(srcColOrdinal); case microsoft.sql.Types.DATETIMEOFFSET: - // We can safely cast the result set to a SQLServerResultSet as the DatetimeOffset type is only available in the JDBC driver. + // We can safely cast the result set to a SQLServerResultSet as the DatetimeOffset type is only + // available in the JDBC driver. return ((SQLServerResultSet) sourceResultSet).getDateTimeOffset(srcColOrdinal); - case microsoft.sql.Types.SQL_VARIANT: + case microsoft.sql.Types.SQL_VARIANT: return sourceResultSet.getObject(srcColOrdinal); default: MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_BulkTypeNotSupported")); @@ -2953,19 +2882,16 @@ private Object readColumnFromResultSet(int srcColOrdinal, SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), null, true); // This return will never be executed, but it is needed as Eclipse complains otherwise. return null; - } - } - catch (SQLException e) { + } + } catch (SQLException e) { throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveSourceData"), e); } } - /* + /** * Reads the given column from the result set current row and writes the data to tdsWriter. */ - private void writeColumn(TDSWriter tdsWriter, - int srcColOrdinal, - int destColOrdinal, + private void writeColumn(TDSWriter tdsWriter, int srcColOrdinal, int destColOrdinal, Object colValue) throws SQLServerException { int srcPrecision, srcScale, destPrecision, srcJdbcType; SSType destSSType = null; @@ -2977,11 +2903,13 @@ private void writeColumn(TDSWriter tdsWriter, destPrecision = destColumnMetadata.get(destColOrdinal).precision; - if ((java.sql.Types.NCHAR == srcJdbcType) || (java.sql.Types.NVARCHAR == srcJdbcType) || (java.sql.Types.LONGNVARCHAR == srcJdbcType)) { - isStreaming = (DataTypes.SHORT_VARTYPE_MAX_CHARS < srcPrecision) || (DataTypes.SHORT_VARTYPE_MAX_CHARS < destPrecision); - } - else { - isStreaming = (DataTypes.SHORT_VARTYPE_MAX_BYTES < srcPrecision) || (DataTypes.SHORT_VARTYPE_MAX_BYTES < destPrecision); + if ((java.sql.Types.NCHAR == srcJdbcType) || (java.sql.Types.NVARCHAR == srcJdbcType) + || (java.sql.Types.LONGNVARCHAR == srcJdbcType)) { + isStreaming = (DataTypes.SHORT_VARTYPE_MAX_CHARS < srcPrecision) + || (DataTypes.SHORT_VARTYPE_MAX_CHARS < destPrecision); + } else { + isStreaming = (DataTypes.SHORT_VARTYPE_MAX_BYTES < srcPrecision) + || (DataTypes.SHORT_VARTYPE_MAX_BYTES < destPrecision); } CryptoMetadata destCryptoMeta = destColumnMetadata.get(destColOrdinal).cryptoMeta; @@ -2995,24 +2923,25 @@ private void writeColumn(TDSWriter tdsWriter, colValue = readColumnFromResultSet(srcColOrdinal, srcJdbcType, isStreaming, (null != destCryptoMeta)); validateStringBinaryLengths(colValue, srcColOrdinal, destColOrdinal); - // if AllowEncryptedValueModifications is set send varbinary read from source without checking type conversion + // if AllowEncryptedValueModifications is set send varbinary read from source without checking type + // conversion if (!((copyOptions.isAllowEncryptedValueModifications()) // normalizationCheck() will be called for encrypted columns so skip this validation || ((null != destCryptoMeta) && (null != colValue)))) { validateDataTypeConversions(srcColOrdinal, destColOrdinal); } } - //If we are using ISQLBulkRecord and the data we are passing is char type, we need to check the source and dest precision + // If we are using ISQLBulkRecord and the data we are passing is char type, we need to check the source and dest + // precision else if (null != sourceBulkRecord && (null == destCryptoMeta)) { validateStringBinaryLengths(colValue, srcColOrdinal, destColOrdinal); - } - else if ((null != sourceBulkRecord) && (null != destCryptoMeta)) { + } else if ((null != sourceBulkRecord) && (null != destCryptoMeta)) { // From CSV to encrypted column. Convert to respective object. - if ((java.sql.Types.DATE == srcJdbcType) || (java.sql.Types.TIME == srcJdbcType) || (java.sql.Types.TIMESTAMP == srcJdbcType) - || (microsoft.sql.Types.DATETIMEOFFSET == srcJdbcType) || (2013 == srcJdbcType) || (2014 == srcJdbcType)) { + if ((java.sql.Types.DATE == srcJdbcType) || (java.sql.Types.TIME == srcJdbcType) + || (java.sql.Types.TIMESTAMP == srcJdbcType) || (microsoft.sql.Types.DATETIMEOFFSET == srcJdbcType) + || (2013 == srcJdbcType) || (2014 == srcJdbcType)) { colValue = getTemporalObjectFromCSV(colValue, srcJdbcType, srcColOrdinal); - } - else if ((java.sql.Types.NUMERIC == srcJdbcType) || (java.sql.Types.DECIMAL == srcJdbcType)) { + } else if ((java.sql.Types.NUMERIC == srcJdbcType) || (java.sql.Types.DECIMAL == srcJdbcType)) { int baseDestPrecision = destCryptoMeta.baseTypeInfo.getPrecision(); int baseDestScale = destCryptoMeta.baseTypeInfo.getScale(); if ((srcScale != baseDestScale) || (srcPrecision != baseDestPrecision)) { @@ -3028,14 +2957,13 @@ else if ((java.sql.Types.NUMERIC == srcJdbcType) || (java.sql.Types.DECIMAL == s CryptoMetadata srcCryptoMeta = srcColumnMetadata.get(srcColOrdinal).cryptoMeta; // If destination is encrypted column, transparently encrypt the data if ((null != destCryptoMeta) && (null != colValue)) { - JDBCType baseSrcJdbcType = (null != srcCryptoMeta) - ? srcColumnMetadata.get(srcColOrdinal).cryptoMeta.baseTypeInfo.getSSType().getJDBCType() : JDBCType.of(srcJdbcType); + JDBCType baseSrcJdbcType = (null != srcCryptoMeta) ? srcColumnMetadata + .get(srcColOrdinal).cryptoMeta.baseTypeInfo.getSSType().getJDBCType() : JDBCType.of(srcJdbcType); if (JDBCType.TIMESTAMP == baseSrcJdbcType) { if (SSType.DATETIME == destSSType) { baseSrcJdbcType = JDBCType.DATETIME; - } - else if (SSType.SMALLDATETIME == destSSType) { + } else if (SSType.SMALLDATETIME == destSSType) { baseSrcJdbcType = JDBCType.SMALLDATETIME; } } @@ -3044,29 +2972,32 @@ else if (SSType.SMALLDATETIME == destSSType) { || (SSType.SMALLMONEY == destSSType && JDBCType.DECIMAL == baseSrcJdbcType) || (SSType.GUID == destSSType && JDBCType.CHAR == baseSrcJdbcType))) { // check for bulkcopy from other than SQLServer, for instance for MYSQL, if anykind of chartype pass - if (!(Util.isCharType(destSSType) && Util.isCharType(srcJdbcType)) && !(sourceResultSet instanceof SQLServerResultSet)) + if (!(Util.isCharType(destSSType) && Util.isCharType(srcJdbcType)) + && !(sourceResultSet instanceof SQLServerResultSet)) // check for normalization of AE data types if (!baseSrcJdbcType.normalizationCheck(destSSType)) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_unsupportedConversionAE")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_unsupportedConversionAE")); Object[] msgArgs = {baseSrcJdbcType, destSSType}; throw new SQLServerException(this, form.format(msgArgs), null, 0, false); } } // if source is encrypted and temporal, call IOBuffer functions to encrypt - if ((baseSrcJdbcType == JDBCType.DATE) || (baseSrcJdbcType == JDBCType.TIMESTAMP) || (baseSrcJdbcType == JDBCType.TIME) - || (baseSrcJdbcType == JDBCType.DATETIMEOFFSET) || (baseSrcJdbcType == JDBCType.DATETIME) - || (baseSrcJdbcType == JDBCType.SMALLDATETIME)) { - colValue = getEncryptedTemporalBytes(tdsWriter, baseSrcJdbcType, colValue, srcColOrdinal, destCryptoMeta.baseTypeInfo.getScale()); - } - else { + if ((baseSrcJdbcType == JDBCType.DATE) || (baseSrcJdbcType == JDBCType.TIMESTAMP) + || (baseSrcJdbcType == JDBCType.TIME) || (baseSrcJdbcType == JDBCType.DATETIMEOFFSET) + || (baseSrcJdbcType == JDBCType.DATETIME) || (baseSrcJdbcType == JDBCType.SMALLDATETIME)) { + colValue = getEncryptedTemporalBytes(tdsWriter, baseSrcJdbcType, colValue, srcColOrdinal, + destCryptoMeta.baseTypeInfo.getScale()); + } else { TypeInfo destTypeInfo = destCryptoMeta.getBaseTypeInfo(); JDBCType destJdbcType = destTypeInfo.getSSType().getJDBCType(); /* - * the following if checks that no casting exception would be thrown in the normalizedValue() method below a SQLServerException is - * then thrown before the ClassCastException could occur an example of how this situation could arise would be if the application - * creates encrypted source and destination tables the result set used to read the source would have AE disabled (causing colValue to - * be varbinary) AE would be enabled on the connection used to complete the bulkCopy operation + * the following if checks that no casting exception would be thrown in the normalizedValue() method + * below a SQLServerException is then thrown before the ClassCastException could occur an example of how + * this situation could arise would be if the application creates encrypted source and destination + * tables the result set used to read the source would have AE disabled (causing colValue to be + * varbinary) AE would be enabled on the connection used to complete the bulkCopy operation */ if ((!Util.isBinaryType(destJdbcType.getIntValue())) && (colValue instanceof byte[])) { @@ -3075,19 +3006,32 @@ else if (SSType.SMALLDATETIME == destSSType) { throw new SQLServerException(this, form.format(msgArgs), null, 0, false); } // normalize the values before encrypting them - colValue = SQLServerSecurityUtility.encryptWithKey( - normalizedValue(destJdbcType, colValue, baseSrcJdbcType, destTypeInfo.getPrecision(), destTypeInfo.getScale()), - destCryptoMeta, connection); + colValue = SQLServerSecurityUtility.encryptWithKey(normalizedValue(destJdbcType, colValue, + baseSrcJdbcType, destTypeInfo.getPrecision(), destTypeInfo.getScale()), destCryptoMeta, + connection); } } - writeColumnToTdsWriter(tdsWriter, srcPrecision, srcScale, srcJdbcType, srcNullable, srcColOrdinal, destColOrdinal, isStreaming, colValue); + writeColumnToTdsWriter(tdsWriter, srcPrecision, srcScale, srcJdbcType, srcNullable, srcColOrdinal, + destColOrdinal, isStreaming, colValue); } - // this method is called against jdbc41, but it require jdbc42 to work - // therefore, we will throw exception. - protected Object getTemporalObjectFromCSVWithFormatter(String valueStrUntrimmed, - int srcJdbcType, - int srcColOrdinal, + /** + * Returns the temporal object from CSV This method is called against jdbc41, but it require jdbc42 to work + * therefore, we will throw exception. + * + * @param valueStrUntrimmed + * valueStrUntrimmed + * @param srcJdbcType + * srcJdbcType + * @param srcColOrdinal + * srcColOrdinal + * @param dateTimeFormatter + * dateTimeFormatter + * @return temporal object + * @throws SQLServerException + * if parsing error + */ + protected Object getTemporalObjectFromCSVWithFormatter(String valueStrUntrimmed, int srcJdbcType, int srcColOrdinal, DateTimeFormatter dateTimeFormatter) throws SQLServerException { try { TemporalAccessor ta = dateTimeFormatter.parse(valueStrUntrimmed); @@ -3124,7 +3068,7 @@ protected Object getTemporalObjectFromCSVWithFormatter(String valueStrUntrimmed, taNano *= 10; Timestamp ts = new Timestamp(cal.getTimeInMillis()); ts.setNanos(taNano); - + switch (srcJdbcType) { case java.sql.Types.TIMESTAMP: return ts; @@ -3139,8 +3083,7 @@ protected Object getTemporalObjectFromCSVWithFormatter(String valueStrUntrimmed, case microsoft.sql.Types.DATETIMEOFFSET: return DateTimeOffset.valueOf(ts, taOffsetSec / 60); } - } - catch (DateTimeException | ArithmeticException e) { + } catch (DateTimeException | ArithmeticException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_ParsingError")); Object[] msgArgs = {JDBCType.of(srcJdbcType)}; throw new SQLServerException(this, form.format(msgArgs), null, 0, false); @@ -3148,16 +3091,14 @@ protected Object getTemporalObjectFromCSVWithFormatter(String valueStrUntrimmed, return valueStrUntrimmed; } - private Object getTemporalObjectFromCSV(Object value, - int srcJdbcType, + private Object getTemporalObjectFromCSV(Object value, int srcJdbcType, int srcColOrdinal) throws SQLServerException { // TIME_WITH_TIMEZONE and TIMESTAMP_WITH_TIMEZONE are not supported with encrypted columns. if (2013 == srcJdbcType) { MessageFormat form1 = new MessageFormat(SQLServerException.getErrString("R_UnsupportedDataTypeAE")); Object[] msgArgs1 = {"TIME_WITH_TIMEZONE"}; throw new SQLServerException(this, form1.format(msgArgs1), null, 0, false); - } - else if (2014 == srcJdbcType) { + } else if (2014 == srcJdbcType) { MessageFormat form2 = new MessageFormat(SQLServerException.getErrString("R_UnsupportedDataTypeAE")); Object[] msgArgs2 = {"TIMESTAMP_WITH_TIMEZONE"}; throw new SQLServerException(this, form2.format(msgArgs2), null, 0, false); @@ -3188,7 +3129,8 @@ else if (2014 == srcJdbcType) { // Get the temporal values from the formatter DateTimeFormatter dateTimeFormatter = srcColumnMetadata.get(srcColOrdinal).dateTimeFormatter; if (null != dateTimeFormatter) { - return getTemporalObjectFromCSVWithFormatter(valueStrUntrimmed, srcJdbcType, srcColOrdinal, dateTimeFormatter); + return getTemporalObjectFromCSVWithFormatter(valueStrUntrimmed, srcJdbcType, srcColOrdinal, + dateTimeFormatter); } // If we are here that means datetimeformatter is not present. Only default format is supported in this case. @@ -3243,20 +3185,17 @@ else if (2014 == srcJdbcType) { fractionalSeconds = Integer.parseInt(valueStr.substring(startIndx, endIndx)); fractionalSecondsLength = endIndx - startIndx; hasTimeZone = true; - } - else // no timezone + } else // no timezone { fractionalSeconds = Integer.parseInt(valueStr.substring(startIndx)); fractionalSecondsLength = valueStr.length() - startIndx; } - } - else { + } else { endIndx = valueStr.indexOf(' ', startIndx); if (-1 != endIndx) { hasTimeZone = true; seconds = Integer.parseInt(valueStr.substring(startIndx, endIndx)); - } - else { + } else { seconds = Integer.parseInt(valueStr.substring(startIndx)); ++endIndx; // skip the space } @@ -3293,18 +3232,15 @@ else if ('-' == valueStr.charAt(startIndx)) { ts.setNanos(fractionalSeconds); return microsoft.sql.DateTimeOffset.valueOf(ts, totalOffset); } - } - catch (IndexOutOfBoundsException e) { + } catch (IndexOutOfBoundsException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_ParsingError")); Object[] msgArgs = {JDBCType.of(srcJdbcType)}; throw new SQLServerException(this, form.format(msgArgs), null, 0, false); - } - catch (NumberFormatException e) { + } catch (NumberFormatException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_ParsingError")); Object[] msgArgs = {JDBCType.of(srcJdbcType)}; throw new SQLServerException(this, form.format(msgArgs), null, 0, false); - } - catch (IllegalArgumentException e) { + } catch (IllegalArgumentException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_ParsingError")); Object[] msgArgs = {JDBCType.of(srcJdbcType)}; throw new SQLServerException(this, form.format(msgArgs), null, 0, false); @@ -3313,11 +3249,8 @@ else if ('-' == valueStr.charAt(startIndx)) { return value; } - private byte[] getEncryptedTemporalBytes(TDSWriter tdsWriter, - JDBCType srcTemporalJdbcType, - Object colValue, - int srcColOrdinal, - int scale) throws SQLServerException { + private byte[] getEncryptedTemporalBytes(TDSWriter tdsWriter, JDBCType srcTemporalJdbcType, Object colValue, + int srcColOrdinal, int scale) throws SQLServerException { long utcMillis; GregorianCalendar calendar; @@ -3340,8 +3273,7 @@ private byte[] getEncryptedTemporalBytes(TDSWriter tdsWriter, int subSecondNanos; if (colValue instanceof java.sql.Timestamp) { subSecondNanos = ((java.sql.Timestamp) colValue).getNanos(); - } - else { + } else { subSecondNanos = Nanos.PER_MILLISECOND * (int) (utcMillis % 1000); if (subSecondNanos < 0) subSecondNanos += Nanos.PER_SECOND; @@ -3355,7 +3287,8 @@ private byte[] getEncryptedTemporalBytes(TDSWriter tdsWriter, utcMillis = ((java.sql.Timestamp) colValue).getTime(); calendar.setTimeInMillis(utcMillis); subSecondNanos = ((java.sql.Timestamp) colValue).getNanos(); - return tdsWriter.writeEncryptedScaledTemporal(calendar, subSecondNanos, scale, SSType.DATETIME2, (short) 0); + return tdsWriter.writeEncryptedScaledTemporal(calendar, subSecondNanos, scale, SSType.DATETIME2, + (short) 0); case DATETIME: case SMALLDATETIME: @@ -3376,7 +3309,8 @@ private byte[] getEncryptedTemporalBytes(TDSWriter tdsWriter, calendar.setLenient(true); calendar.clear(); calendar.setTimeInMillis(utcMillis); - return tdsWriter.writeEncryptedScaledTemporal(calendar, subSecondNanos, scale, SSType.DATETIMEOFFSET, (short) minutesOffset); + return tdsWriter.writeEncryptedScaledTemporal(calendar, subSecondNanos, scale, SSType.DATETIMEOFFSET, + (short) minutesOffset); default: @@ -3386,10 +3320,7 @@ private byte[] getEncryptedTemporalBytes(TDSWriter tdsWriter, } } - private byte[] normalizedValue(JDBCType destJdbcType, - Object value, - JDBCType srcJdbcType, - int destPrecision, + private byte[] normalizedValue(JDBCType destJdbcType, Object value, JDBCType srcJdbcType, int destPrecision, int destScale) throws SQLServerException { Long longValue = null; byte[] byteValue = null; @@ -3399,7 +3330,8 @@ private byte[] normalizedValue(JDBCType destJdbcType, switch (destJdbcType) { case BIT: longValue = (long) ((Boolean) value ? 1 : 0); - return ByteBuffer.allocate(Long.SIZE / Byte.SIZE).order(ByteOrder.LITTLE_ENDIAN).putLong(longValue).array(); + return ByteBuffer.allocate(Long.SIZE / Byte.SIZE).order(ByteOrder.LITTLE_ENDIAN).putLong(longValue) + .array(); case TINYINT: case SMALLINT: @@ -3412,12 +3344,12 @@ private byte[] normalizedValue(JDBCType destJdbcType, int intValue = (int) value; short shortValue = (short) intValue; longValue = (long) shortValue; - } - else + } else longValue = (long) (short) value; } - return ByteBuffer.allocate(Long.SIZE / Byte.SIZE).order(ByteOrder.LITTLE_ENDIAN).putLong(longValue).array(); + return ByteBuffer.allocate(Long.SIZE / Byte.SIZE).order(ByteOrder.LITTLE_ENDIAN).putLong(longValue) + .array(); case INTEGER: switch (srcJdbcType) { @@ -3431,7 +3363,8 @@ private byte[] normalizedValue(JDBCType destJdbcType, default: longValue = Long.valueOf((Integer) value); } - return ByteBuffer.allocate(Long.SIZE / Byte.SIZE).order(ByteOrder.LITTLE_ENDIAN).putLong(longValue).array(); + return ByteBuffer.allocate(Long.SIZE / Byte.SIZE).order(ByteOrder.LITTLE_ENDIAN).putLong(longValue) + .array(); case BIGINT: switch (srcJdbcType) { @@ -3448,7 +3381,8 @@ private byte[] normalizedValue(JDBCType destJdbcType, default: longValue = (long) value; } - return ByteBuffer.allocate(Long.SIZE / Byte.SIZE).order(ByteOrder.LITTLE_ENDIAN).putLong(longValue).array(); + return ByteBuffer.allocate(Long.SIZE / Byte.SIZE).order(ByteOrder.LITTLE_ENDIAN).putLong(longValue) + .array(); case BINARY: case VARBINARY: @@ -3456,8 +3390,7 @@ private byte[] normalizedValue(JDBCType destJdbcType, byte[] byteArrayValue; if (value instanceof String) { byteArrayValue = ParameterUtils.HexToBin((String) value); - } - else { + } else { byteArrayValue = (byte[]) value; } if (byteArrayValue.length > destPrecision) { @@ -3496,11 +3429,14 @@ private byte[] normalizedValue(JDBCType destJdbcType, case FLOAT: Float floatValue = (value instanceof String) ? Float.parseFloat((String) value) : (Float) value; - return ByteBuffer.allocate((Float.SIZE / Byte.SIZE)).order(ByteOrder.LITTLE_ENDIAN).putFloat(floatValue).array(); + return ByteBuffer.allocate((Float.SIZE / Byte.SIZE)).order(ByteOrder.LITTLE_ENDIAN) + .putFloat(floatValue).array(); case DOUBLE: - Double doubleValue = (value instanceof String) ? Double.parseDouble((String) value) : (Double) value; - return ByteBuffer.allocate((Double.SIZE / Byte.SIZE)).order(ByteOrder.LITTLE_ENDIAN).putDouble(doubleValue).array(); + Double doubleValue = (value instanceof String) ? Double.parseDouble((String) value) + : (Double) value; + return ByteBuffer.allocate((Double.SIZE / Byte.SIZE)).order(ByteOrder.LITTLE_ENDIAN) + .putDouble(doubleValue).array(); case NUMERIC: case DECIMAL: @@ -3511,8 +3447,7 @@ private byte[] normalizedValue(JDBCType destJdbcType, MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidDataForAE")); Object[] msgArgs = {srcJdbcType, destJdbcType}; throw new SQLServerException(this, form.format(msgArgs), null, 0, false); - } - else if (srcDataScale < destScale) + } else if (srcDataScale < destScale) // update the scale of source data based on the metadata for scale sent early bigDataValue = bigDataValue.setScale(destScale); @@ -3531,11 +3466,12 @@ else if (srcDataScale < destScale) // Need to validate range in the client side as we are converting BigDecimal to integers. Util.validateMoneyRange(bdValue, destJdbcType); - // Get the total number of digits after the multiplication. Scale is hardcoded to 4. This is needed to get the proper rounding. + // Get the total number of digits after the multiplication. Scale is hardcoded to 4. This is needed + // to get the proper rounding. int digitCount = (bdValue.precision() - bdValue.scale()) + 4; - long moneyVal = ((BigDecimal) value) - .multiply(new BigDecimal(10000), new java.math.MathContext(digitCount, java.math.RoundingMode.HALF_UP)).longValue(); + long moneyVal = ((BigDecimal) value).multiply(new BigDecimal(10000), + new java.math.MathContext(digitCount, java.math.RoundingMode.HALF_UP)).longValue(); ByteBuffer bbuf = ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN); bbuf.putInt((int) (moneyVal >> 32)).array(); bbuf.putInt((int) moneyVal).array(); @@ -3552,13 +3488,11 @@ else if (srcDataScale < destScale) MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidDataForAE")); Object[] msgArgs = {srcJdbcType, destJdbcType}; throw new SQLServerException(this, form.format(msgArgs), null, 0, false); - } - catch (IllegalArgumentException ex) { + } catch (IllegalArgumentException ex) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidDataForAE")); Object[] msgArgs = {srcJdbcType, destJdbcType}; throw new SQLServerException(this, form.format(msgArgs), null, 0, false); - } - catch (ClassCastException ex) { + } catch (ClassCastException ex) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidDataForAE")); Object[] msgArgs = {srcJdbcType, destJdbcType}; throw new SQLServerException(this, form.format(msgArgs), null, 0, false); @@ -3569,35 +3503,33 @@ private boolean goToNextRow() throws SQLServerException { try { if (null != sourceResultSet) { return sourceResultSet.next(); - } - else { + } else { return sourceBulkRecord.next(); } - } - catch (SQLException e) { + } catch (SQLException e) { throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveSourceData"), e); } } - /* + /** * Writes data for a batch of rows to the TDSWriter object. Writes the following part in the BulkLoadBCP stream * (https://msdn.microsoft.com/en-us/library/dd340549.aspx) ... */ - private boolean writeBatchData(TDSWriter tdsWriter, - TDSCommand command, + private boolean writeBatchData(TDSWriter tdsWriter, TDSCommand command, boolean insertRowByRow) throws SQLServerException { int batchsize = copyOptions.getBatchSize(); int row = 0; while (true) { // Default batchsize is 0 - means all rows are sent in one batch. In this case we will return - // when all rows in the resultset are processed. If batchsize is not zero, we will return when one batch of rows are processed. + // when all rows in the resultset are processed. If batchsize is not zero, we will return when one batch of + // rows are processed. if (0 != batchsize && row >= batchsize) return true; // No more data available, return false so we do not execute any more batches. if (!goToNextRow()) return false; - + if (insertRowByRow) { // read response gotten from goToNextRow() ((SQLServerResultSet) sourceResultSet).getTDSReader().readPacket(); @@ -3614,12 +3546,13 @@ private boolean writeBatchData(TDSWriter tdsWriter, // Loop for each destination column. The mappings is a many to one mapping // where multiple source columns can be mapped to one destination column. for (ColumnMapping columnMapping : columnMappings) { - writeColumn(tdsWriter, columnMapping.sourceColumnOrdinal, columnMapping.destinationColumnOrdinal, null // cell - // value is - // retrieved - // inside - // writeRowData() - // method. + writeColumn(tdsWriter, columnMapping.sourceColumnOrdinal, columnMapping.destinationColumnOrdinal, + null // cell + // value is + // retrieved + // inside + // writeRowData() + // method. ); } } @@ -3630,14 +3563,14 @@ private boolean writeBatchData(TDSWriter tdsWriter, try { rowObjects = sourceBulkRecord.getRowData(); - } - catch (Exception ex) { + } catch (Exception ex) { // if no more data available to retrive throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveSourceData"), ex); } for (ColumnMapping columnMapping : columnMappings) { - // If the SQLServerBulkCSVRecord does not have metadata for columns, it returns strings in the object array. + // If the SQLServerBulkCSVRecord does not have metadata for columns, it returns strings in the + // object array. // COnvert the strings using destination table types. writeColumn(tdsWriter, columnMapping.sourceColumnOrdinal, columnMapping.destinationColumnOrdinal, rowObjects[columnMapping.sourceColumnOrdinal - 1]); @@ -3655,7 +3588,8 @@ private boolean writeBatchData(TDSWriter tdsWriter, } } - protected void setStmtColumnEncriptionSetting(SQLServerStatementColumnEncryptionSetting stmtColumnEncriptionSetting) { + protected void setStmtColumnEncriptionSetting( + SQLServerStatementColumnEncryptionSetting stmtColumnEncriptionSetting) { this.stmtColumnEncriptionSetting = stmtColumnEncriptionSetting; } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopyOptions.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopyOptions.java index c247b1c28..67f76277b 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopyOptions.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopyOptions.java @@ -1,294 +1,296 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -import java.text.MessageFormat; - -/** - * A collection of settings that control how an instance of SQLServerBulkCopy behaves. Used when constructing a SQLServerBulkCopy instance to change - * how the writeToServer methods for that instance behave. - */ -public class SQLServerBulkCopyOptions { - /** - * Number of rows in each batch. - * - * A batch is complete when BatchSize rows have been processed or there are no more rows to send to the destination data source. Zero (the - * default) indicates that each WriteToServer operation is a single batch. If the SqlBulkCopy instance has been declared without the - * UseInternalTransaction option in effect, rows are sent to the server BatchSize rows at a time, but no transaction-related action is taken. If - * UseInternalTransaction is in effect, each batch of rows is inserted as a separate transaction. - * - * Default: 0 - */ - private int batchSize; - - /** - * Number of seconds for the operation to complete before it times out. - * - * A value of 0 indicates no limit; the bulk copy will wait indefinitely. If the operation does time out, the transaction is not committed and all - * copied rows are removed from the destination table. - * - * Default: 60 - */ - private int bulkCopyTimeout; - - /** - * Check constraints while data is being inserted. - * - * Default: false - constraints are not checked - */ - private boolean checkConstraints; - - /** - * When specified, cause the server to fire the insert triggers for the rows being inserted into the database. - * - * Default: false - no triggers are fired. - */ - private boolean fireTriggers; - - /** - * Preserve source identity values. - * - * Default: false - identity values are assigned by the destination. - */ - private boolean keepIdentity; - - /** - * Preserve null values in the destination table regardless of the settings for default values. - * - * Default: false - null values are replaced by default values where applicable. - */ - private boolean keepNulls; - - /** - * Obtain a bulk update lock for the duration of the bulk copy operation. - * - * Default: false - row locks are used. - */ - private boolean tableLock; - - /** - * When specified, each batch of the bulk-copy operation will occur within a transaction. - * - * Default: false - no transaction - */ - private boolean useInternalTransaction; - - private boolean allowEncryptedValueModifications; - - /** - * Initializes an instance of the SQLServerBulkCopySettings class using defaults for all of the settings. - */ - public SQLServerBulkCopyOptions() { - batchSize = 0; - bulkCopyTimeout = 60; - checkConstraints = false; - fireTriggers = false; - keepIdentity = false; - keepNulls = false; - tableLock = false; - useInternalTransaction = false; - allowEncryptedValueModifications = false; - } - - /** - * Gets the number of rows in each batch. At the end of each batch, the rows in the batch are sent to the server. - * - * @return Number of rows in each batch. - */ - public int getBatchSize() { - return batchSize; - } - - /** - * Sets the number of rows in each batch. At the end of each batch, the rows in the batch are sent to the server. - * - * @param batchSize - * Number of rows in each batch. - * @throws SQLServerException - * If the batchSize being set is invalid. - */ - public void setBatchSize(int batchSize) throws SQLServerException { - if (batchSize >= 0) { - this.batchSize = batchSize; - } - else { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidNegativeArg")); - Object[] msgArgs = {"batchSize"}; - SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), null, false); - } - } - - /** - * Gets the number of seconds for the operation to complete before it times out. - * - * @return Number of seconds before operation times out. - */ - public int getBulkCopyTimeout() { - return bulkCopyTimeout; - } - - /** - * Sets the number of seconds for the operation to complete before it times out. - * - * @param timeout - * Number of seconds before operation times out. - * @throws SQLServerException - * If the timeout being set is invalid. - */ - public void setBulkCopyTimeout(int timeout) throws SQLServerException { - if (timeout >= 0) { - this.bulkCopyTimeout = timeout; - } - else { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidNegativeArg")); - Object[] msgArgs = {"timeout"}; - SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), null, false); - } - } - - /** - * Indicates whether or not to preserve any source identity values. - * - * @return True if source identity values are to be preserved; false if they are to be assigned by the destination. - */ - public boolean isKeepIdentity() { - return keepIdentity; - } - - /** - * Sets whether or not to preserve any source identity values. - * - * @param keepIdentity - * True if source identity values are to be preserved; false if they are to be assigned by the destination - */ - public void setKeepIdentity(boolean keepIdentity) { - this.keepIdentity = keepIdentity; - } - - /** - * Indicates whether to preserve null values in the destination table regardless of the settings for default values, or if they should be replaced - * by default values (where applicable). - * - * @return True if null values should be preserved; false if null values should be replaced by default values where applicable. - */ - public boolean isKeepNulls() { - return keepNulls; - } - - /** - * Sets whether to preserve null values in the destination table regardless of the settings for default values, or if they should be replaced by - * default values (where applicable). - * - * @param keepNulls - * True if null values should be preserved; false if null values should be replaced by default values where applicable. - */ - public void setKeepNulls(boolean keepNulls) { - this.keepNulls = keepNulls; - } - - /** - * Indicates whether SQLServerBulkCopy should obtain a bulk update lock for the duration of the bulk copy operation. - * - * @return True to obtain row locks; false otherwise. - */ - public boolean isTableLock() { - return tableLock; - } - - /** - * Sets whether SQLServerBulkCopy should obtain a bulk update lock for the duration of the bulk copy operation. - * - * @param tableLock - * True to obtain row locks; false otherwise. - */ - public void setTableLock(boolean tableLock) { - this.tableLock = tableLock; - } - - /** - * Indicates whether each batch of the bulk-copy operation will occur within a transaction or not. - * - * @return True if the batch will occur within a transaction; false otherwise. - */ - public boolean isUseInternalTransaction() { - return useInternalTransaction; - } - - /** - * Sets whether each batch of the bulk-copy operation will occur within a transaction or not. - * - * @param useInternalTransaction - * True if the batch will occur within a transaction; false otherwise. - */ - public void setUseInternalTransaction(boolean useInternalTransaction) { - this.useInternalTransaction = useInternalTransaction; - } - - /** - * Indicates whether constraints are to be checked while data is being inserted or not. - * - * @return True if constraints are to be checked; false otherwise. - */ - public boolean isCheckConstraints() { - return checkConstraints; - } - - /** - * Sets whether constraints are to be checked while data is being inserted or not. - * - * @param checkConstraints - * True if constraints are to be checked; false otherwise. - */ - public void setCheckConstraints(boolean checkConstraints) { - this.checkConstraints = checkConstraints; - } - - /** - * Indicates if the server should fire insert triggers for rows being inserted into the database. - * - * @return True triggers are enabled; false otherwise. - */ - public boolean isFireTriggers() { - return fireTriggers; - } - - /** - * Sets whether the server should be set to fire insert triggers for rows being inserted into the database. - * - * @param fireTriggers - * True triggers are to be enabled; false otherwise. - */ - public void setFireTriggers(boolean fireTriggers) { - this.fireTriggers = fireTriggers; - } - - /** - * Indicates if allowEncryptedValueModifications option is enabled or not - * - * @return True if allowEncryptedValueModification is set to true; false otherwise. - */ - public boolean isAllowEncryptedValueModifications() { - return allowEncryptedValueModifications; - } - - /** - * Sets whether the driver would send data as is or would decrypt the data and encrypt it again before sending to SQL Server - *

- * Use caution when specifying allowEncryptedValueModifications as this may lead to corrupting the database because the driver does not check if - * the data is indeed encrypted, or if it is correctly encrypted using the same encryption type, algorithm and key as the target column. - * - * @param allowEncryptedValueModifications - * enables bulk copying of encrypted data between tables or databases, without decrypting the data. Typically, an application would - * select data from encrypted columns from one table without decrypting the data (the app would connect to the database with the column - * encryption setting keyword set to disabled) and then would use this option to bulk insert the data, which is still encrypted. - */ - public void setAllowEncryptedValueModifications(boolean allowEncryptedValueModifications) { - this.allowEncryptedValueModifications = allowEncryptedValueModifications; - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +import java.text.MessageFormat; + + +/** + * Provides a collection of settings that control how an instance of SQLServerBulkCopy behaves. Used when constructing a + * SQLServerBulkCopy instance to change how the writeToServer methods for that instance behave. + */ +public class SQLServerBulkCopyOptions { + /** + * Number of rows in each batch. + * + * A batch is complete when BatchSize rows have been processed or there are no more rows to send to the destination + * data source. Zero (the default) indicates that each WriteToServer operation is a single batch. If the SqlBulkCopy + * instance has been declared without the UseInternalTransaction option in effect, rows are sent to the server + * BatchSize rows at a time, but no transaction-related action is taken. If UseInternalTransaction is in effect, + * each batch of rows is inserted as a separate transaction. + * + * Default: 0 + */ + private int batchSize; + + /** + * Number of seconds for the operation to complete before it times out. + * + * A value of 0 indicates no limit; the bulk copy will wait indefinitely. If the operation does time out, the + * transaction is not committed and all copied rows are removed from the destination table. + * + * Default: 60 + */ + private int bulkCopyTimeout; + + /** + * Checks constraints while data is being inserted. + * + * Default: false - constraints are not checked + */ + private boolean checkConstraints; + + /** + * When specified, cause the server to fire the insert triggers for the rows being inserted into the database. + * + * Default: false - no triggers are fired. + */ + private boolean fireTriggers; + + /** + * Preserve source identity values. + * + * Default: false - identity values are assigned by the destination. + */ + private boolean keepIdentity; + + /** + * Preserve null values in the destination table regardless of the settings for default values. + * + * Default: false - null values are replaced by default values where applicable. + */ + private boolean keepNulls; + + /** + * Obtain a bulk update lock for the duration of the bulk copy operation. + * + * Default: false - row locks are used. + */ + private boolean tableLock; + + /** + * When specified, each batch of the bulk-copy operation will occur within a transaction. + * + * Default: false - no transaction + */ + private boolean useInternalTransaction; + + private boolean allowEncryptedValueModifications; + + /** + * Constructs a SQLServerBulkCopySettings class using defaults for all of the settings. + */ + public SQLServerBulkCopyOptions() { + batchSize = 0; + bulkCopyTimeout = 60; + checkConstraints = false; + fireTriggers = false; + keepIdentity = false; + keepNulls = false; + tableLock = false; + useInternalTransaction = false; + allowEncryptedValueModifications = false; + } + + /** + * Returns the number of rows in each batch. At the end of each batch, the rows in the batch are sent to the server. + * + * @return Number of rows in each batch. + */ + public int getBatchSize() { + return batchSize; + } + + /** + * Sets the number of rows in each batch. At the end of each batch, the rows in the batch are sent to the server. + * + * @param batchSize + * Number of rows in each batch. + * @throws SQLServerException + * If the batchSize being set is invalid. + */ + public void setBatchSize(int batchSize) throws SQLServerException { + if (batchSize >= 0) { + this.batchSize = batchSize; + } else { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidNegativeArg")); + Object[] msgArgs = {"batchSize"}; + SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), null, false); + } + } + + /** + * Returns the number of seconds for the operation to complete before it times out. + * + * @return Number of seconds before operation times out. + */ + public int getBulkCopyTimeout() { + return bulkCopyTimeout; + } + + /** + * Sets the number of seconds for the operation to complete before it times out. + * + * @param timeout + * Number of seconds before operation times out. + * @throws SQLServerException + * If the timeout being set is invalid. + */ + public void setBulkCopyTimeout(int timeout) throws SQLServerException { + if (timeout >= 0) { + this.bulkCopyTimeout = timeout; + } else { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidNegativeArg")); + Object[] msgArgs = {"timeout"}; + SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), null, false); + } + } + + /** + * Returns whether or not to preserve any source identity values. + * + * @return True if source identity values are to be preserved; false if they are to be assigned by the destination. + */ + public boolean isKeepIdentity() { + return keepIdentity; + } + + /** + * Sets whether or not to preserve any source identity values. + * + * @param keepIdentity + * True if source identity values are to be preserved; false if they are to be assigned by the destination + */ + public void setKeepIdentity(boolean keepIdentity) { + this.keepIdentity = keepIdentity; + } + + /** + * Returns whether to preserve null values in the destination table regardless of the settings for default values, + * or if they should be replaced by default values (where applicable). + * + * @return True if null values should be preserved; false if null values should be replaced by default values where + * applicable. + */ + public boolean isKeepNulls() { + return keepNulls; + } + + /** + * Sets whether to preserve null values in the destination table regardless of the settings for default values, or + * if they should be replaced by default values (where applicable). + * + * @param keepNulls + * True if null values should be preserved; false if null values should be replaced by default values where + * applicable. + */ + public void setKeepNulls(boolean keepNulls) { + this.keepNulls = keepNulls; + } + + /** + * Returns whether SQLServerBulkCopy should obtain a bulk update lock for the duration of the bulk copy operation. + * + * @return True to obtain row locks; false otherwise. + */ + public boolean isTableLock() { + return tableLock; + } + + /** + * Sets whether SQLServerBulkCopy should obtain a bulk update lock for the duration of the bulk copy operation. + * + * @param tableLock + * True to obtain row locks; false otherwise. + */ + public void setTableLock(boolean tableLock) { + this.tableLock = tableLock; + } + + /** + * Returns whether each batch of the bulk-copy operation will occur within a transaction or not. + * + * @return True if the batch will occur within a transaction; false otherwise. + */ + public boolean isUseInternalTransaction() { + return useInternalTransaction; + } + + /** + * Sets whether each batch of the bulk-copy operation will occur within a transaction or not. + * + * @param useInternalTransaction + * True if the batch will occur within a transaction; false otherwise. + */ + public void setUseInternalTransaction(boolean useInternalTransaction) { + this.useInternalTransaction = useInternalTransaction; + } + + /** + * Returns whether constraints are to be checked while data is being inserted or not. + * + * @return True if constraints are to be checked; false otherwise. + */ + public boolean isCheckConstraints() { + return checkConstraints; + } + + /** + * Sets whether constraints are to be checked while data is being inserted or not. + * + * @param checkConstraints + * True if constraints are to be checked; false otherwise. + */ + public void setCheckConstraints(boolean checkConstraints) { + this.checkConstraints = checkConstraints; + } + + /** + * Returns if the server should fire insert triggers for rows being inserted into the database. + * + * @return True triggers are enabled; false otherwise. + */ + public boolean isFireTriggers() { + return fireTriggers; + } + + /** + * Sets whether the server should be set to fire insert triggers for rows being inserted into the database. + * + * @param fireTriggers + * True triggers are to be enabled; false otherwise. + */ + public void setFireTriggers(boolean fireTriggers) { + this.fireTriggers = fireTriggers; + } + + /** + * Returns if allowEncryptedValueModifications option is enabled or not + * + * @return True if allowEncryptedValueModification is set to true; false otherwise. + */ + public boolean isAllowEncryptedValueModifications() { + return allowEncryptedValueModifications; + } + + /** + * Sets whether the driver would send data as is or would decrypt the data and encrypt it again before sending to + * SQL Server + *

+ * Use caution when specifying allowEncryptedValueModifications as this may lead to corrupting the database because + * the driver does not check if the data is indeed encrypted, or if it is correctly encrypted using the same + * encryption type, algorithm and key as the target column. + * + * @param allowEncryptedValueModifications + * enables bulk copying of encrypted data between tables or databases, without decrypting the data. + * Typically, an application would select data from encrypted columns from one table without decrypting the + * data (the app would connect to the database with the column encryption setting keyword set to disabled) + * and then would use this option to bulk insert the data, which is still encrypted. + */ + public void setAllowEncryptedValueModifications(boolean allowEncryptedValueModifications) { + this.allowEncryptedValueModifications = allowEncryptedValueModifications; + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerCallableStatement.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerCallableStatement.java index 57da43fff..87054ef95 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerCallableStatement.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerCallableStatement.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -31,12 +28,14 @@ import java.util.Calendar; import java.util.UUID; + /** - * CallableStatement implements JDBC callable statements. CallableStatement allows the caller to specify the procedure name to call along with input - * parameter value and output parameter types. Callable statement also allows the return of a return status with the ? = call( ?, ..) JDBC syntax + * Provides implementation of JDBC callable statements. CallableStatement allows the caller to specify the procedure + * name to call along with input parameter value and output parameter types. Callable statement also allows the return + * of a return status with the ? = call( ?, ..) JDBC syntax *

- * The API javadoc for JDBC API methods that this class implements are not repeated here. Please see Sun's JDBC API interfaces javadoc for those - * details. + * The API javadoc for JDBC API methods that this class implements are not repeated here. Please see Sun's JDBC API + * interfaces javadoc for those details. */ public class SQLServerCallableStatement extends SQLServerPreparedStatement implements ISQLServerCallableStatement { @@ -67,28 +66,24 @@ String getClassNameInternal() { * Create a new callable statement. * * @param connection - * the connection + * the connection * @param sql - * the users call syntax + * the users call syntax * @param nRSType - * the result set type + * the result set type * @param nRSConcur - * the result set concurrency + * the result set concurrency * @param stmtColEncSetting - * the statement column encryption setting + * the statement column encryption setting * @throws SQLServerException */ - SQLServerCallableStatement(SQLServerConnection connection, - String sql, - int nRSType, - int nRSConcur, + SQLServerCallableStatement(SQLServerConnection connection, String sql, int nRSType, int nRSConcur, SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException { super(connection, sql, nRSType, nRSConcur, stmtColEncSetting); } @Override - public void registerOutParameter(int index, - int sqlType) throws SQLServerException { + public void registerOutParameter(int index, int sqlType) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {index, sqlType}); checkClosed(); @@ -228,8 +223,8 @@ final void processOutParameters() throws SQLServerException { } /** - * Processes the remainder of the batch up to the final or batch-terminating DONE token that marks the end of a sp_[cursor][prep]exec stored - * procedure call. + * Processes the remainder of the batch up to the final or batch-terminating DONE token that marks the end of a + * sp_[cursor][prep]exec stored procedure call. */ private void processBatchRemainder() throws SQLServerException { final class ExecDoneHandler extends TDSTokenHandler { @@ -260,8 +255,7 @@ boolean onDone(TDSReader tdsReader) throws SQLServerException { TDSParser.parse(resultsReader(), execDoneHandler); } - private void skipOutParameters(int numParamsToSkip, - boolean discardValues) throws SQLServerException { + private void skipOutParameters(int numParamsToSkip, boolean discardValues) throws SQLServerException { /** TDS token handler for locating OUT parameters (RETURN_VALUE tokens) in the response token stream */ final class OutParamHandler extends TDSTokenHandler { final StreamRetValue srv = new StreamRetValue(); @@ -335,7 +329,8 @@ boolean onRetValue(TDSReader tdsReader) throws SQLServerException { // of sp_[cursor][prep]exec params. outParamIndex -= outParamIndexAdjustment; if ((outParamIndex < 0 || outParamIndex >= inOutParam.length) || (!inOutParam[outParamIndex].isOutput())) { - getStatementLogger().info(toString() + " Unexpected outParamIndex: " + outParamIndex + "; adjustment: " + outParamIndexAdjustment); + getStatementLogger().info(toString() + " Unexpected outParamIndex: " + outParamIndex + "; adjustment: " + + outParamIndexAdjustment); connection.throwInvalidTDS(); } @@ -344,11 +339,10 @@ boolean onRetValue(TDSReader tdsReader) throws SQLServerException { } @Override - public void registerOutParameter(int index, - int sqlType, - String typeName) throws SQLServerException { + public void registerOutParameter(int index, int sqlType, String typeName) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {index, sqlType, typeName}); + loggerExternal.entering(getClassNameLogging(), "registerOutParameter", + new Object[] {index, sqlType, typeName}); checkClosed(); @@ -358,11 +352,10 @@ public void registerOutParameter(int index, } @Override - public void registerOutParameter(int index, - int sqlType, - int scale) throws SQLServerException { + public void registerOutParameter(int index, int sqlType, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {index, sqlType, scale}); + loggerExternal.entering(getClassNameLogging(), "registerOutParameter", + new Object[] {index, sqlType, scale}); checkClosed(); @@ -373,12 +366,10 @@ public void registerOutParameter(int index, } @Override - public void registerOutParameter(int index, - int sqlType, - int precision, - int scale) throws SQLServerException { + public void registerOutParameter(int index, int sqlType, int precision, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {index, sqlType, scale, precision}); + loggerExternal.entering(getClassNameLogging(), "registerOutParameter", + new Object[] {index, sqlType, scale, precision}); checkClosed(); @@ -403,14 +394,16 @@ private Parameter getterGetParam(int index) throws SQLServerException { // Check index refers to a registered OUT parameter if (!inOutParam[index - 1].isOutput()) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_outputParameterNotRegisteredForOutput")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_outputParameterNotRegisteredForOutput")); Object[] msgArgs = {index}; SQLServerException.makeFromDriverError(connection, this, form.format(msgArgs), "07009", true); } // If we haven't executed the statement yet then throw a nice friendly exception. if (!wasExecuted()) - SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_statementMustBeExecuted"), "07009", false); + SQLServerException.makeFromDriverError(connection, this, + SQLServerException.getErrString("R_statementMustBeExecuted"), "07009", false); resultsReader().getCommand().checkForInterrupt(); @@ -423,21 +416,19 @@ private Parameter getterGetParam(int index) throws SQLServerException { return lastParamAccessed; } - private Object getValue(int parameterIndex, - JDBCType jdbcType) throws SQLServerException { + private Object getValue(int parameterIndex, JDBCType jdbcType) throws SQLServerException { return getterGetParam(parameterIndex).getValue(jdbcType, null, null, resultsReader()); } - private Object getValue(int parameterIndex, - JDBCType jdbcType, - Calendar cal) throws SQLServerException { + private Object getValue(int parameterIndex, JDBCType jdbcType, Calendar cal) throws SQLServerException { return getterGetParam(parameterIndex).getValue(jdbcType, null, cal, resultsReader()); } - private Object getStream(int parameterIndex, - StreamType streamType) throws SQLServerException { + private Object getStream(int parameterIndex, StreamType streamType) throws SQLServerException { Object value = getterGetParam(parameterIndex).getValue(streamType.getJDBCType(), - new InputStreamGetterArgs(streamType, getIsResponseBufferingAdaptive(), getIsResponseBufferingAdaptive(), toString()), null, // calendar + new InputStreamGetterArgs(streamType, getIsResponseBufferingAdaptive(), + getIsResponseBufferingAdaptive(), toString()), + null, // calendar resultsReader()); activeStream = (Closeable) value; @@ -446,7 +437,9 @@ private Object getStream(int parameterIndex, private Object getSQLXMLInternal(int parameterIndex) throws SQLServerException { SQLServerSQLXML value = (SQLServerSQLXML) getterGetParam(parameterIndex).getValue(JDBCType.SQLXML, - new InputStreamGetterArgs(StreamType.SQLXML, getIsResponseBufferingAdaptive(), getIsResponseBufferingAdaptive(), toString()), null, // calendar + new InputStreamGetterArgs(StreamType.SQLXML, getIsResponseBufferingAdaptive(), + getIsResponseBufferingAdaptive(), toString()), + null, // calendar resultsReader()); if (null != value) @@ -518,8 +511,7 @@ public final String getNString(String parameterName) throws SQLException { @Deprecated @Override - public BigDecimal getBigDecimal(int parameterIndex, - int scale) throws SQLException { + public BigDecimal getBigDecimal(int parameterIndex, int scale) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "getBigDecimal", new Object[] {parameterIndex, scale}); checkClosed(); @@ -532,8 +524,7 @@ public BigDecimal getBigDecimal(int parameterIndex, @Deprecated @Override - public BigDecimal getBigDecimal(String parameterName, - int scale) throws SQLServerException { + public BigDecimal getBigDecimal(String parameterName, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "getBigDecimal", new Object[] {parameterName, scale}); checkClosed(); @@ -619,8 +610,7 @@ public Date getDate(String parameterName) throws SQLServerException { } @Override - public Date getDate(int index, - Calendar cal) throws SQLServerException { + public Date getDate(int index, Calendar cal) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "getDate", new Object[] {index, cal}); checkClosed(); @@ -630,8 +620,7 @@ public Date getDate(int index, } @Override - public Date getDate(String parameterName, - Calendar cal) throws SQLServerException { + public Date getDate(String parameterName, Calendar cal) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "getDate", new Object[] {parameterName, cal}); checkClosed(); @@ -701,90 +690,72 @@ public Object getObject(int index) throws SQLServerException { loggerExternal.entering(getClassNameLogging(), "getObject", index); checkClosed(); - Object value = getValue(index, getterGetParam(index).getJdbcTypeSetByUser() != null ? getterGetParam(index).getJdbcTypeSetByUser() - : getterGetParam(index).getJdbcType()); + Object value = getValue(index, + getterGetParam(index).getJdbcTypeSetByUser() != null ? getterGetParam(index).getJdbcTypeSetByUser() + : getterGetParam(index).getJdbcType()); loggerExternal.exiting(getClassNameLogging(), "getObject", value); return value; } @Override - public T getObject(int index, - Class type) throws SQLException { + public T getObject(int index, Class type) throws SQLException { loggerExternal.entering(getClassNameLogging(), "getObject", index); checkClosed(); Object returnValue; if (type == String.class) { returnValue = getString(index); - } - else if (type == Byte.class) { + } else if (type == Byte.class) { byte byteValue = getByte(index); returnValue = wasNull() ? null : byteValue; - } - else if (type == Short.class) { + } else if (type == Short.class) { short shortValue = getShort(index); returnValue = wasNull() ? null : shortValue; - } - else if (type == Integer.class) { + } else if (type == Integer.class) { int intValue = getInt(index); returnValue = wasNull() ? null : intValue; - } - else if (type == Long.class) { + } else if (type == Long.class) { long longValue = getLong(index); returnValue = wasNull() ? null : longValue; - } - else if (type == BigDecimal.class) { + } else if (type == BigDecimal.class) { returnValue = getBigDecimal(index); - } - else if (type == Boolean.class) { + } else if (type == Boolean.class) { boolean booleanValue = getBoolean(index); returnValue = wasNull() ? null : booleanValue; - } - else if (type == java.sql.Date.class) { + } else if (type == java.sql.Date.class) { returnValue = getDate(index); - } - else if (type == java.sql.Time.class) { + } else if (type == java.sql.Time.class) { returnValue = getTime(index); - } - else if (type == java.sql.Timestamp.class) { + } else if (type == java.sql.Timestamp.class) { returnValue = getTimestamp(index); - } - else if (type == microsoft.sql.DateTimeOffset.class) { + } else if (type == microsoft.sql.DateTimeOffset.class) { returnValue = getDateTimeOffset(index); - } - else if (type == UUID.class) { + } else if (type == UUID.class) { // read binary, avoid string allocation and parsing byte[] guid = getBytes(index); returnValue = guid != null ? Util.readGUIDtoUUID(guid) : null; - } - else if (type == SQLXML.class) { + } else if (type == SQLXML.class) { returnValue = getSQLXML(index); - } - else if (type == Blob.class) { + } else if (type == Blob.class) { returnValue = getBlob(index); - } - else if (type == Clob.class) { + } else if (type == Clob.class) { returnValue = getClob(index); - } - else if (type == NClob.class) { + } else if (type == NClob.class) { returnValue = getNClob(index); - } - else if (type == byte[].class) { + } else if (type == byte[].class) { returnValue = getBytes(index); - } - else if (type == Float.class) { + } else if (type == Float.class) { float floatValue = getFloat(index); returnValue = wasNull() ? null : floatValue; - } - else if (type == Double.class) { + } else if (type == Double.class) { double doubleValue = getDouble(index); returnValue = wasNull() ? null : doubleValue; - } - else { + } else { // if the type is not supported the specification says the should // a SQLException instead of SQLFeatureNotSupportedException MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_unsupportedConversionTo")); Object[] msgArgs = {type}; - throw new SQLServerException(form.format(msgArgs), SQLState.DATA_EXCEPTION_NOT_SPECIFIC, DriverError.NOT_SET, null); + throw new SQLServerException(form.format(msgArgs), SQLState.DATA_EXCEPTION_NOT_SPECIFIC, + DriverError.NOT_SET, null); } loggerExternal.exiting(getClassNameLogging(), "getObject", index); return type.cast(returnValue); @@ -796,15 +767,14 @@ public Object getObject(String parameterName) throws SQLServerException { checkClosed(); int parameterIndex = findColumn(parameterName); Object value = getValue(parameterIndex, - getterGetParam(parameterIndex).getJdbcTypeSetByUser() != null ? getterGetParam(parameterIndex).getJdbcTypeSetByUser() - : getterGetParam(parameterIndex).getJdbcType()); + getterGetParam(parameterIndex).getJdbcTypeSetByUser() != null ? getterGetParam(parameterIndex) + .getJdbcTypeSetByUser() : getterGetParam(parameterIndex).getJdbcType()); loggerExternal.exiting(getClassNameLogging(), "getObject", value); return value; } @Override - public T getObject(String parameterName, - Class type) throws SQLException { + public T getObject(String parameterName, Class type) throws SQLException { loggerExternal.entering(getClassNameLogging(), "getObject", parameterName); checkClosed(); int parameterIndex = findColumn(parameterName); @@ -852,8 +822,7 @@ public Time getTime(String parameterName) throws SQLServerException { } @Override - public Time getTime(int index, - Calendar cal) throws SQLServerException { + public Time getTime(int index, Calendar cal) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "getTime", new Object[] {index, cal}); checkClosed(); @@ -863,8 +832,7 @@ public Time getTime(int index, } @Override - public Time getTime(String parameterName, - Calendar cal) throws SQLServerException { + public Time getTime(String parameterName, Calendar cal) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "getTime", new Object[] {parameterName, cal}); checkClosed(); @@ -893,8 +861,7 @@ public Timestamp getTimestamp(String parameterName) throws SQLServerException { } @Override - public Timestamp getTimestamp(int index, - Calendar cal) throws SQLServerException { + public Timestamp getTimestamp(int index, Calendar cal) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "getTimestamp", new Object[] {index, cal}); checkClosed(); @@ -904,8 +871,7 @@ public Timestamp getTimestamp(int index, } @Override - public Timestamp getTimestamp(String name, - Calendar cal) throws SQLServerException { + public Timestamp getTimestamp(String name, Calendar cal) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "getTimestamp", new Object[] {name, cal}); checkClosed(); @@ -934,8 +900,7 @@ public Timestamp getDateTime(String parameterName) throws SQLServerException { } @Override - public Timestamp getDateTime(int index, - Calendar cal) throws SQLServerException { + public Timestamp getDateTime(int index, Calendar cal) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "getDateTime", new Object[] {index, cal}); checkClosed(); @@ -945,8 +910,7 @@ public Timestamp getDateTime(int index, } @Override - public Timestamp getDateTime(String name, - Calendar cal) throws SQLServerException { + public Timestamp getDateTime(String name, Calendar cal) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "getDateTime", new Object[] {name, cal}); checkClosed(); @@ -975,8 +939,7 @@ public Timestamp getSmallDateTime(String parameterName) throws SQLServerExceptio } @Override - public Timestamp getSmallDateTime(int index, - Calendar cal) throws SQLServerException { + public Timestamp getSmallDateTime(int index, Calendar cal) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "getSmallDateTime", new Object[] {index, cal}); checkClosed(); @@ -986,8 +949,7 @@ public Timestamp getSmallDateTime(int index, } @Override - public Timestamp getSmallDateTime(String name, - Calendar cal) throws SQLServerException { + public Timestamp getSmallDateTime(String name, Calendar cal) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "getSmallDateTime", new Object[] {name, cal}); checkClosed(); @@ -1004,8 +966,8 @@ public microsoft.sql.DateTimeOffset getDateTimeOffset(int index) throws SQLServe // DateTimeOffset is not supported with SQL Server versions earlier than Katmai if (!connection.isKatmaiOrLater()) - throw new SQLServerException(SQLServerException.getErrString("R_notSupported"), SQLState.DATA_EXCEPTION_NOT_SPECIFIC, DriverError.NOT_SET, - null); + throw new SQLServerException(SQLServerException.getErrString("R_notSupported"), + SQLState.DATA_EXCEPTION_NOT_SPECIFIC, DriverError.NOT_SET, null); microsoft.sql.DateTimeOffset value = (microsoft.sql.DateTimeOffset) getValue(index, JDBCType.DATETIMEOFFSET); loggerExternal.exiting(getClassNameLogging(), "getDateTimeOffset", value); @@ -1019,10 +981,11 @@ public microsoft.sql.DateTimeOffset getDateTimeOffset(String parameterName) thro // DateTimeOffset is not supported with SQL Server versions earlier than Katmai if (!connection.isKatmaiOrLater()) - throw new SQLServerException(SQLServerException.getErrString("R_notSupported"), SQLState.DATA_EXCEPTION_NOT_SPECIFIC, DriverError.NOT_SET, - null); + throw new SQLServerException(SQLServerException.getErrString("R_notSupported"), + SQLState.DATA_EXCEPTION_NOT_SPECIFIC, DriverError.NOT_SET, null); - microsoft.sql.DateTimeOffset value = (microsoft.sql.DateTimeOffset) getValue(findColumn(parameterName), JDBCType.DATETIMEOFFSET); + microsoft.sql.DateTimeOffset value = (microsoft.sql.DateTimeOffset) getValue(findColumn(parameterName), + JDBCType.DATETIMEOFFSET); loggerExternal.exiting(getClassNameLogging(), "getDateTimeOffset", value); return value; } @@ -1187,11 +1150,9 @@ void closeActiveStream() throws SQLServerException { if (null != activeStream) { try { activeStream.close(); - } - catch (IOException e) { + } catch (IOException e) { SQLServerException.makeFromDriverError(null, null, e.getMessage(), null, true); - } - finally { + } finally { activeStream = null; } } @@ -1234,15 +1195,13 @@ public NClob getNClob(String parameterName) throws SQLException { } @Override - public Object getObject(int parameterIndex, - java.util.Map> map) throws SQLException { + public Object getObject(int parameterIndex, java.util.Map> map) throws SQLException { SQLServerException.throwNotSupportedException(connection, this); return null; } @Override - public Object getObject(String parameterName, - java.util.Map> m) throws SQLException { + public Object getObject(String parameterName, java.util.Map> m) throws SQLException { checkClosed(); return getObject(findColumn(parameterName), m); } @@ -1277,16 +1236,18 @@ public java.sql.Array getArray(String parameterName) throws SQLException { * Find a column's index given its name. * * @param columnName - * the name + * the name * @throws SQLServerException - * when an error occurs + * when an error occurs * @return the index */ private int findColumn(String columnName) throws SQLServerException { if (parameterNames == null) { try (SQLServerStatement s = (SQLServerStatement) connection.createStatement()) { - // Note we are concatenating the information from the passed in sql, not any arguments provided by the user - // if the user can execute the sql, any fragments of it is potentially executed via the meta data call through injection + // Note we are concatenating the information from the passed in sql, not any arguments provided by the + // user + // if the user can execute the sql, any fragments of it is potentially executed via the meta data call + // through injection // is not a security issue. ThreePartName threePartName = ThreePartName.parse(procedureName); @@ -1306,11 +1267,11 @@ private int findColumn(String columnName) throws SQLServerException { metaQuery.append("@procedure_name="); metaQuery.append(threePartName.getProcedurePart()); metaQuery.append(" , @ODBCVer=3"); - } - else { + } else { // This should rarely happen, this will only happen if we can't find the stored procedure name // invalidly formatted call syntax. - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_parameterNotDefinedForProcedure")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_parameterNotDefinedForProcedure")); Object[] msgArgs = {columnName, ""}; SQLServerException.makeFromDriverError(connection, this, form.format(msgArgs), "07009", false); } @@ -1321,8 +1282,7 @@ private int findColumn(String columnName) throws SQLServerException { String parameterName = rs.getString(4); parameterNames.add(parameterName.trim()); } - } - catch (SQLException e) { + } catch (SQLException e) { SQLServerException.makeFromDriverError(connection, this, e.toString(), null, false); } @@ -1339,8 +1299,7 @@ private int findColumn(String columnName) throws SQLServerException { String columnNameWithoutAtSign = null; if (columnName.startsWith("@")) { columnNameWithoutAtSign = columnName.substring(1, columnName.length()); - } - else { + } else { columnNameWithoutAtSign = columnName; } @@ -1378,7 +1337,8 @@ private int findColumn(String columnName) throws SQLServerException { } if (-1 == matchPos) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_parameterNotDefinedForProcedure")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_parameterNotDefinedForProcedure")); Object[] msgArgs = {columnName, procedureName}; SQLServerException.makeFromDriverError(connection, this, form.format(msgArgs), "07009", false); } @@ -1392,32 +1352,29 @@ private int findColumn(String columnName) throws SQLServerException { } @Override - public void setTimestamp(String parameterName, - java.sql.Timestamp value, + public void setTimestamp(String parameterName, java.sql.Timestamp value, Calendar calendar) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setTimeStamp", new Object[] {parameterName, value, calendar}); + loggerExternal.entering(getClassNameLogging(), "setTimeStamp", + new Object[] {parameterName, value, calendar}); checkClosed(); setValue(findColumn(parameterName), JDBCType.TIMESTAMP, value, JavaType.TIMESTAMP, calendar, false); loggerExternal.exiting(getClassNameLogging(), "setTimeStamp"); } @Override - public void setTimestamp(String parameterName, - java.sql.Timestamp value, - Calendar calendar, + public void setTimestamp(String parameterName, java.sql.Timestamp value, Calendar calendar, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setTimeStamp", new Object[] {parameterName, value, calendar, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "setTimeStamp", + new Object[] {parameterName, value, calendar, forceEncrypt}); checkClosed(); setValue(findColumn(parameterName), JDBCType.TIMESTAMP, value, JavaType.TIMESTAMP, calendar, forceEncrypt); loggerExternal.exiting(getClassNameLogging(), "setTimeStamp"); } @Override - public void setTime(String parameterName, - java.sql.Time value, - Calendar calendar) throws SQLServerException { + public void setTime(String parameterName, java.sql.Time value, Calendar calendar) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setTime", new Object[] {parameterName, value, calendar}); checkClosed(); @@ -1426,21 +1383,18 @@ public void setTime(String parameterName, } @Override - public void setTime(String parameterName, - java.sql.Time value, - Calendar calendar, + public void setTime(String parameterName, java.sql.Time value, Calendar calendar, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setTime", new Object[] {parameterName, value, calendar, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "setTime", + new Object[] {parameterName, value, calendar, forceEncrypt}); checkClosed(); setValue(findColumn(parameterName), JDBCType.TIME, value, JavaType.TIME, calendar, forceEncrypt); loggerExternal.exiting(getClassNameLogging(), "setTime"); } @Override - public void setDate(String parameterName, - java.sql.Date value, - Calendar calendar) throws SQLServerException { + public void setDate(String parameterName, java.sql.Date value, Calendar calendar) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setDate", new Object[] {parameterName, value, calendar}); checkClosed(); @@ -1449,74 +1403,69 @@ public void setDate(String parameterName, } @Override - public void setDate(String parameterName, - java.sql.Date value, - Calendar calendar, + public void setDate(String parameterName, java.sql.Date value, Calendar calendar, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setDate", new Object[] {parameterName, value, calendar, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "setDate", + new Object[] {parameterName, value, calendar, forceEncrypt}); checkClosed(); setValue(findColumn(parameterName), JDBCType.DATE, value, JavaType.DATE, calendar, forceEncrypt); loggerExternal.exiting(getClassNameLogging(), "setDate"); } @Override - public final void setCharacterStream(String parameterName, - Reader reader) throws SQLException { + public final void setCharacterStream(String parameterName, Reader reader) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setCharacterStream", new Object[] {parameterName, reader}); checkClosed(); - setStream(findColumn(parameterName), StreamType.CHARACTER, reader, JavaType.READER, DataTypes.UNKNOWN_STREAM_LENGTH); + setStream(findColumn(parameterName), StreamType.CHARACTER, reader, JavaType.READER, + DataTypes.UNKNOWN_STREAM_LENGTH); loggerExternal.exiting(getClassNameLogging(), "setCharacterStream"); } @Override - public final void setCharacterStream(String parameterName, - Reader value, - int length) throws SQLException { + public final void setCharacterStream(String parameterName, Reader value, int length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setCharacterStream", new Object[] {parameterName, value, length}); + loggerExternal.entering(getClassNameLogging(), "setCharacterStream", + new Object[] {parameterName, value, length}); checkClosed(); setStream(findColumn(parameterName), StreamType.CHARACTER, value, JavaType.READER, length); loggerExternal.exiting(getClassNameLogging(), "setCharacterStream"); } @Override - public final void setCharacterStream(String parameterName, - Reader reader, - long length) throws SQLException { + public final void setCharacterStream(String parameterName, Reader reader, long length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setCharacterStream", new Object[] {parameterName, reader, length}); + loggerExternal.entering(getClassNameLogging(), "setCharacterStream", + new Object[] {parameterName, reader, length}); checkClosed(); setStream(findColumn(parameterName), StreamType.CHARACTER, reader, JavaType.READER, length); loggerExternal.exiting(getClassNameLogging(), "setCharacterStream"); } @Override - public final void setNCharacterStream(String parameterName, - Reader value) throws SQLException { + public final void setNCharacterStream(String parameterName, Reader value) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setNCharacterStream", new Object[] {parameterName, value}); checkClosed(); - setStream(findColumn(parameterName), StreamType.NCHARACTER, value, JavaType.READER, DataTypes.UNKNOWN_STREAM_LENGTH); + setStream(findColumn(parameterName), StreamType.NCHARACTER, value, JavaType.READER, + DataTypes.UNKNOWN_STREAM_LENGTH); loggerExternal.exiting(getClassNameLogging(), "setNCharacterStream"); } @Override - public final void setNCharacterStream(String parameterName, - Reader value, - long length) throws SQLException { + public final void setNCharacterStream(String parameterName, Reader value, long length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setNCharacterStream", new Object[] {parameterName, value, length}); + loggerExternal.entering(getClassNameLogging(), "setNCharacterStream", + new Object[] {parameterName, value, length}); checkClosed(); setStream(findColumn(parameterName), StreamType.NCHARACTER, value, JavaType.READER, length); loggerExternal.exiting(getClassNameLogging(), "setNCharacterStream"); } @Override - public final void setClob(String parameterName, - Clob value) throws SQLException { + public final void setClob(String parameterName, Clob value) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setClob", new Object[] {parameterName, value}); checkClosed(); @@ -1525,19 +1474,17 @@ public final void setClob(String parameterName, } @Override - public final void setClob(String parameterName, - Reader reader) throws SQLException { + public final void setClob(String parameterName, Reader reader) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setClob", new Object[] {parameterName, reader}); checkClosed(); - setStream(findColumn(parameterName), StreamType.CHARACTER, reader, JavaType.READER, DataTypes.UNKNOWN_STREAM_LENGTH); + setStream(findColumn(parameterName), StreamType.CHARACTER, reader, JavaType.READER, + DataTypes.UNKNOWN_STREAM_LENGTH); loggerExternal.exiting(getClassNameLogging(), "setClob"); } @Override - public final void setClob(String parameterName, - Reader value, - long length) throws SQLException { + public final void setClob(String parameterName, Reader value, long length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setClob", new Object[] {parameterName, value, length}); checkClosed(); @@ -1546,8 +1493,7 @@ public final void setClob(String parameterName, } @Override - public final void setNClob(String parameterName, - NClob value) throws SQLException { + public final void setNClob(String parameterName, NClob value) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setNClob", new Object[] {parameterName, value}); checkClosed(); @@ -1556,19 +1502,17 @@ public final void setNClob(String parameterName, } @Override - public final void setNClob(String parameterName, - Reader reader) throws SQLException { + public final void setNClob(String parameterName, Reader reader) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setNClob", new Object[] {parameterName, reader}); checkClosed(); - setStream(findColumn(parameterName), StreamType.NCHARACTER, reader, JavaType.READER, DataTypes.UNKNOWN_STREAM_LENGTH); + setStream(findColumn(parameterName), StreamType.NCHARACTER, reader, JavaType.READER, + DataTypes.UNKNOWN_STREAM_LENGTH); loggerExternal.exiting(getClassNameLogging(), "setNClob"); } @Override - public final void setNClob(String parameterName, - Reader reader, - long length) throws SQLException { + public final void setNClob(String parameterName, Reader reader, long length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setNClob", new Object[] {parameterName, reader, length}); checkClosed(); @@ -1577,8 +1521,7 @@ public final void setNClob(String parameterName, } @Override - public final void setNString(String parameterName, - String value) throws SQLException { + public final void setNString(String parameterName, String value) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setNString", new Object[] {parameterName, value}); checkClosed(); @@ -1587,19 +1530,17 @@ public final void setNString(String parameterName, } @Override - public final void setNString(String parameterName, - String value, - boolean forceEncrypt) throws SQLServerException { + public final void setNString(String parameterName, String value, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setNString", new Object[] {parameterName, value, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "setNString", + new Object[] {parameterName, value, forceEncrypt}); checkClosed(); setValue(findColumn(parameterName), JDBCType.NVARCHAR, value, JavaType.STRING, forceEncrypt); loggerExternal.exiting(getClassNameLogging(), "setNString"); } @Override - public void setObject(String parameterName, - Object value) throws SQLServerException { + public void setObject(String parameterName, Object value) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setObject", new Object[] {parameterName, value}); checkClosed(); @@ -1608,45 +1549,38 @@ public void setObject(String parameterName, } @Override - public void setObject(String parameterName, - Object value, - int sqlType) throws SQLServerException { + public void setObject(String parameterName, Object value, int sqlType) throws SQLServerException { String tvpName = null; if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setObject", new Object[] {parameterName, value, sqlType}); checkClosed(); if (microsoft.sql.Types.STRUCTURED == sqlType) { tvpName = getTVPNameIfNull(findColumn(parameterName), null); - setObject(setterGetParam(findColumn(parameterName)), value, JavaType.TVP, JDBCType.TVP, null, null, false, findColumn(parameterName), - tvpName); - } - else - setObject(setterGetParam(findColumn(parameterName)), value, JavaType.of(value), JDBCType.of(sqlType), null, null, false, + setObject(setterGetParam(findColumn(parameterName)), value, JavaType.TVP, JDBCType.TVP, null, null, false, findColumn(parameterName), tvpName); + } else + setObject(setterGetParam(findColumn(parameterName)), value, JavaType.of(value), JDBCType.of(sqlType), null, + null, false, findColumn(parameterName), tvpName); loggerExternal.exiting(getClassNameLogging(), "setObject"); } @Override - public void setObject(String parameterName, - Object value, - int sqlType, - int decimals) throws SQLServerException { + public void setObject(String parameterName, Object value, int sqlType, int decimals) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setObject", new Object[] {parameterName, value, sqlType, decimals}); + loggerExternal.entering(getClassNameLogging(), "setObject", + new Object[] {parameterName, value, sqlType, decimals}); checkClosed(); - setObject(setterGetParam(findColumn(parameterName)), value, JavaType.of(value), JDBCType.of(sqlType), decimals, null, false, - findColumn(parameterName), null); + setObject(setterGetParam(findColumn(parameterName)), value, JavaType.of(value), JDBCType.of(sqlType), decimals, + null, false, findColumn(parameterName), null); loggerExternal.exiting(getClassNameLogging(), "setObject"); } @Override - public void setObject(String parameterName, - Object value, - int sqlType, - int decimals, + public void setObject(String parameterName, Object value, int sqlType, int decimals, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setObject", new Object[] {parameterName, value, sqlType, decimals, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "setObject", + new Object[] {parameterName, value, sqlType, decimals, forceEncrypt}); checkClosed(); // scale - for java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types, @@ -1654,20 +1588,18 @@ public void setObject(String parameterName, // For all other types, this value will be ignored. setObject(setterGetParam(findColumn(parameterName)), value, JavaType.of(value), JDBCType.of(sqlType), - (java.sql.Types.NUMERIC == sqlType || java.sql.Types.DECIMAL == sqlType) ? decimals : null, null, forceEncrypt, - findColumn(parameterName), null); + (java.sql.Types.NUMERIC == sqlType || java.sql.Types.DECIMAL == sqlType) ? decimals : null, null, + forceEncrypt, findColumn(parameterName), null); loggerExternal.exiting(getClassNameLogging(), "setObject"); } @Override - public final void setObject(String parameterName, - Object value, - int targetSqlType, - Integer precision, + public final void setObject(String parameterName, Object value, int targetSqlType, Integer precision, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setObject", new Object[] {parameterName, value, targetSqlType, precision, scale}); + loggerExternal.entering(getClassNameLogging(), "setObject", + new Object[] {parameterName, value, targetSqlType, precision, scale}); checkClosed(); // scale - for java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types, @@ -1676,81 +1608,76 @@ public final void setObject(String parameterName, // For all other types, this value will be ignored. setObject(setterGetParam(findColumn(parameterName)), value, JavaType.of(value), JDBCType.of(targetSqlType), - (java.sql.Types.NUMERIC == targetSqlType || java.sql.Types.DECIMAL == targetSqlType || InputStream.class.isInstance(value) - || Reader.class.isInstance(value)) ? scale : null, + (java.sql.Types.NUMERIC == targetSqlType || java.sql.Types.DECIMAL == targetSqlType + || InputStream.class.isInstance(value) || Reader.class.isInstance(value)) ? scale : null, precision, false, findColumn(parameterName), null); loggerExternal.exiting(getClassNameLogging(), "setObject"); } @Override - public final void setAsciiStream(String parameterName, - InputStream value) throws SQLException { + public final void setAsciiStream(String parameterName, InputStream value) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setAsciiStream", new Object[] {parameterName, value}); checkClosed(); - setStream(findColumn(parameterName), StreamType.ASCII, value, JavaType.INPUTSTREAM, DataTypes.UNKNOWN_STREAM_LENGTH); + setStream(findColumn(parameterName), StreamType.ASCII, value, JavaType.INPUTSTREAM, + DataTypes.UNKNOWN_STREAM_LENGTH); loggerExternal.exiting(getClassNameLogging(), "setAsciiStream"); } @Override - public final void setAsciiStream(String parameterName, - InputStream value, - int length) throws SQLException { + public final void setAsciiStream(String parameterName, InputStream value, int length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setAsciiStream", new Object[] {parameterName, value, length}); + loggerExternal.entering(getClassNameLogging(), "setAsciiStream", + new Object[] {parameterName, value, length}); checkClosed(); setStream(findColumn(parameterName), StreamType.ASCII, value, JavaType.INPUTSTREAM, length); loggerExternal.exiting(getClassNameLogging(), "setAsciiStream"); } @Override - public final void setAsciiStream(String parameterName, - InputStream value, - long length) throws SQLException { + public final void setAsciiStream(String parameterName, InputStream value, long length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setAsciiStream", new Object[] {parameterName, value, length}); + loggerExternal.entering(getClassNameLogging(), "setAsciiStream", + new Object[] {parameterName, value, length}); checkClosed(); setStream(findColumn(parameterName), StreamType.ASCII, value, JavaType.INPUTSTREAM, length); loggerExternal.exiting(getClassNameLogging(), "setAsciiStream"); } @Override - public final void setBinaryStream(String parameterName, - InputStream value) throws SQLException { + public final void setBinaryStream(String parameterName, InputStream value) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setBinaryStream", new Object[] {parameterName, value}); checkClosed(); - setStream(findColumn(parameterName), StreamType.BINARY, value, JavaType.INPUTSTREAM, DataTypes.UNKNOWN_STREAM_LENGTH); + setStream(findColumn(parameterName), StreamType.BINARY, value, JavaType.INPUTSTREAM, + DataTypes.UNKNOWN_STREAM_LENGTH); loggerExternal.exiting(getClassNameLogging(), "setBinaryStream"); } @Override - public final void setBinaryStream(String parameterName, - InputStream value, - int length) throws SQLException { + public final void setBinaryStream(String parameterName, InputStream value, int length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setBinaryStream", new Object[] {parameterName, value, length}); + loggerExternal.entering(getClassNameLogging(), "setBinaryStream", + new Object[] {parameterName, value, length}); checkClosed(); setStream(findColumn(parameterName), StreamType.BINARY, value, JavaType.INPUTSTREAM, length); loggerExternal.exiting(getClassNameLogging(), "setBinaryStream"); } @Override - public final void setBinaryStream(String parameterName, - InputStream value, - long length) throws SQLException { + public final void setBinaryStream(String parameterName, InputStream value, long length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setBinaryStream", new Object[] {parameterName, value, length}); + loggerExternal.entering(getClassNameLogging(), "setBinaryStream", + new Object[] {parameterName, value, length}); checkClosed(); setStream(findColumn(parameterName), StreamType.BINARY, value, JavaType.INPUTSTREAM, length); loggerExternal.exiting(getClassNameLogging(), "setBinaryStream"); } @Override - public final void setBlob(String parameterName, - Blob inputStream) throws SQLException { + public final void setBlob(String parameterName, Blob inputStream) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setBlob", new Object[] {parameterName, inputStream}); checkClosed(); @@ -1759,29 +1686,27 @@ public final void setBlob(String parameterName, } @Override - public final void setBlob(String parameterName, - InputStream value) throws SQLException { + public final void setBlob(String parameterName, InputStream value) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setBlob", new Object[] {parameterName, value}); checkClosed(); - setStream(findColumn(parameterName), StreamType.BINARY, value, JavaType.INPUTSTREAM, DataTypes.UNKNOWN_STREAM_LENGTH); + setStream(findColumn(parameterName), StreamType.BINARY, value, JavaType.INPUTSTREAM, + DataTypes.UNKNOWN_STREAM_LENGTH); loggerExternal.exiting(getClassNameLogging(), "setBlob"); } @Override - public final void setBlob(String parameterName, - InputStream inputStream, - long length) throws SQLException { + public final void setBlob(String parameterName, InputStream inputStream, long length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setBlob", new Object[] {parameterName, inputStream, length}); + loggerExternal.entering(getClassNameLogging(), "setBlob", + new Object[] {parameterName, inputStream, length}); checkClosed(); setStream(findColumn(parameterName), StreamType.BINARY, inputStream, JavaType.INPUTSTREAM, length); loggerExternal.exiting(getClassNameLogging(), "setBlob"); } @Override - public void setTimestamp(String parameterName, - java.sql.Timestamp value) throws SQLServerException { + public void setTimestamp(String parameterName, java.sql.Timestamp value) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setTimestamp", new Object[] {parameterName, value}); checkClosed(); @@ -1790,9 +1715,7 @@ public void setTimestamp(String parameterName, } @Override - public void setTimestamp(String parameterName, - java.sql.Timestamp value, - int scale) throws SQLServerException { + public void setTimestamp(String parameterName, java.sql.Timestamp value, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setTimestamp", new Object[] {parameterName, value}); checkClosed(); @@ -1801,20 +1724,18 @@ public void setTimestamp(String parameterName, } @Override - public void setTimestamp(String parameterName, - java.sql.Timestamp value, - int scale, + public void setTimestamp(String parameterName, java.sql.Timestamp value, int scale, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setTimestamp", new Object[] {parameterName, value, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "setTimestamp", + new Object[] {parameterName, value, forceEncrypt}); checkClosed(); setValue(findColumn(parameterName), JDBCType.TIMESTAMP, value, JavaType.TIMESTAMP, null, scale, forceEncrypt); loggerExternal.exiting(getClassNameLogging(), "setTimestamp"); } @Override - public void setDateTimeOffset(String parameterName, - microsoft.sql.DateTimeOffset value) throws SQLServerException { + public void setDateTimeOffset(String parameterName, microsoft.sql.DateTimeOffset value) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setDateTimeOffset", new Object[] {parameterName, value}); checkClosed(); @@ -1823,31 +1744,30 @@ public void setDateTimeOffset(String parameterName, } @Override - public void setDateTimeOffset(String parameterName, - microsoft.sql.DateTimeOffset value, + public void setDateTimeOffset(String parameterName, microsoft.sql.DateTimeOffset value, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setDateTimeOffset", new Object[] {parameterName, value}); checkClosed(); - setValue(findColumn(parameterName), JDBCType.DATETIMEOFFSET, value, JavaType.DATETIMEOFFSET, null, scale, false); + setValue(findColumn(parameterName), JDBCType.DATETIMEOFFSET, value, JavaType.DATETIMEOFFSET, null, scale, + false); loggerExternal.exiting(getClassNameLogging(), "setDateTimeOffset"); } @Override - public void setDateTimeOffset(String parameterName, - microsoft.sql.DateTimeOffset value, - int scale, + public void setDateTimeOffset(String parameterName, microsoft.sql.DateTimeOffset value, int scale, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setDateTimeOffset", new Object[] {parameterName, value, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "setDateTimeOffset", + new Object[] {parameterName, value, forceEncrypt}); checkClosed(); - setValue(findColumn(parameterName), JDBCType.DATETIMEOFFSET, value, JavaType.DATETIMEOFFSET, null, scale, forceEncrypt); + setValue(findColumn(parameterName), JDBCType.DATETIMEOFFSET, value, JavaType.DATETIMEOFFSET, null, scale, + forceEncrypt); loggerExternal.exiting(getClassNameLogging(), "setDateTimeOffset"); } @Override - public void setDate(String parameterName, - java.sql.Date value) throws SQLServerException { + public void setDate(String parameterName, java.sql.Date value) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setDate", new Object[] {parameterName, value}); checkClosed(); @@ -1856,8 +1776,7 @@ public void setDate(String parameterName, } @Override - public void setTime(String parameterName, - java.sql.Time value) throws SQLServerException { + public void setTime(String parameterName, java.sql.Time value) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setTime", new Object[] {parameterName, value}); checkClosed(); @@ -1866,9 +1785,7 @@ public void setTime(String parameterName, } @Override - public void setTime(String parameterName, - java.sql.Time value, - int scale) throws SQLServerException { + public void setTime(String parameterName, java.sql.Time value, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setTime", new Object[] {parameterName, value}); checkClosed(); @@ -1877,20 +1794,18 @@ public void setTime(String parameterName, } @Override - public void setTime(String parameterName, - java.sql.Time value, - int scale, + public void setTime(String parameterName, java.sql.Time value, int scale, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setTime", new Object[] {parameterName, value, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "setTime", + new Object[] {parameterName, value, forceEncrypt}); checkClosed(); setValue(findColumn(parameterName), JDBCType.TIME, value, JavaType.TIME, null, scale, forceEncrypt); loggerExternal.exiting(getClassNameLogging(), "setTime"); } @Override - public void setDateTime(String parameterName, - java.sql.Timestamp value) throws SQLServerException { + public void setDateTime(String parameterName, java.sql.Timestamp value) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setDateTime", new Object[] {parameterName, value}); checkClosed(); @@ -1899,19 +1814,18 @@ public void setDateTime(String parameterName, } @Override - public void setDateTime(String parameterName, - java.sql.Timestamp value, + public void setDateTime(String parameterName, java.sql.Timestamp value, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setDateTime", new Object[] {parameterName, value, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "setDateTime", + new Object[] {parameterName, value, forceEncrypt}); checkClosed(); setValue(findColumn(parameterName), JDBCType.DATETIME, value, JavaType.TIMESTAMP, forceEncrypt); loggerExternal.exiting(getClassNameLogging(), "setDateTime"); } @Override - public void setSmallDateTime(String parameterName, - java.sql.Timestamp value) throws SQLServerException { + public void setSmallDateTime(String parameterName, java.sql.Timestamp value) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setSmallDateTime", new Object[] {parameterName, value}); checkClosed(); @@ -1920,19 +1834,18 @@ public void setSmallDateTime(String parameterName, } @Override - public void setSmallDateTime(String parameterName, - java.sql.Timestamp value, + public void setSmallDateTime(String parameterName, java.sql.Timestamp value, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setSmallDateTime", new Object[] {parameterName, value, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "setSmallDateTime", + new Object[] {parameterName, value, forceEncrypt}); checkClosed(); setValue(findColumn(parameterName), JDBCType.SMALLDATETIME, value, JavaType.TIMESTAMP, forceEncrypt); loggerExternal.exiting(getClassNameLogging(), "setSmallDateTime"); } @Override - public void setUniqueIdentifier(String parameterName, - String guid) throws SQLServerException { + public void setUniqueIdentifier(String parameterName, String guid) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setUniqueIdentifier", new Object[] {parameterName, guid}); checkClosed(); @@ -1941,19 +1854,17 @@ public void setUniqueIdentifier(String parameterName, } @Override - public void setUniqueIdentifier(String parameterName, - String guid, - boolean forceEncrypt) throws SQLServerException { + public void setUniqueIdentifier(String parameterName, String guid, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setUniqueIdentifier", new Object[] {parameterName, guid, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "setUniqueIdentifier", + new Object[] {parameterName, guid, forceEncrypt}); checkClosed(); setValue(findColumn(parameterName), JDBCType.GUID, guid, JavaType.STRING, forceEncrypt); loggerExternal.exiting(getClassNameLogging(), "setUniqueIdentifier"); } @Override - public void setBytes(String parameterName, - byte[] value) throws SQLServerException { + public void setBytes(String parameterName, byte[] value) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setBytes", new Object[] {parameterName, value}); checkClosed(); @@ -1962,19 +1873,17 @@ public void setBytes(String parameterName, } @Override - public void setBytes(String parameterName, - byte[] value, - boolean forceEncrypt) throws SQLServerException { + public void setBytes(String parameterName, byte[] value, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setBytes", new Object[] {parameterName, value, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "setBytes", + new Object[] {parameterName, value, forceEncrypt}); checkClosed(); setValue(findColumn(parameterName), JDBCType.BINARY, value, JavaType.BYTEARRAY, forceEncrypt); loggerExternal.exiting(getClassNameLogging(), "setBytes"); } @Override - public void setByte(String parameterName, - byte value) throws SQLServerException { + public void setByte(String parameterName, byte value) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setByte", new Object[] {parameterName, value}); checkClosed(); @@ -1983,19 +1892,17 @@ public void setByte(String parameterName, } @Override - public void setByte(String parameterName, - byte value, - boolean forceEncrypt) throws SQLServerException { + public void setByte(String parameterName, byte value, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setByte", new Object[] {parameterName, value, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "setByte", + new Object[] {parameterName, value, forceEncrypt}); checkClosed(); setValue(findColumn(parameterName), JDBCType.TINYINT, value, JavaType.BYTE, forceEncrypt); loggerExternal.exiting(getClassNameLogging(), "setByte"); } @Override - public void setString(String parameterName, - String value) throws SQLServerException { + public void setString(String parameterName, String value) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setString", new Object[] {parameterName, value}); checkClosed(); @@ -2004,19 +1911,17 @@ public void setString(String parameterName, } @Override - public void setString(String parameterName, - String value, - boolean forceEncrypt) throws SQLServerException { + public void setString(String parameterName, String value, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setString", new Object[] {parameterName, value, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "setString", + new Object[] {parameterName, value, forceEncrypt}); checkClosed(); setValue(findColumn(parameterName), JDBCType.VARCHAR, value, JavaType.STRING, forceEncrypt); loggerExternal.exiting(getClassNameLogging(), "setString"); } @Override - public void setMoney(String parameterName, - BigDecimal value) throws SQLServerException { + public void setMoney(String parameterName, BigDecimal value) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setMoney", new Object[] {parameterName, value}); checkClosed(); @@ -2025,19 +1930,17 @@ public void setMoney(String parameterName, } @Override - public void setMoney(String parameterName, - BigDecimal value, - boolean forceEncrypt) throws SQLServerException { + public void setMoney(String parameterName, BigDecimal value, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setMoney", new Object[] {parameterName, value, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "setMoney", + new Object[] {parameterName, value, forceEncrypt}); checkClosed(); setValue(findColumn(parameterName), JDBCType.MONEY, value, JavaType.BIGDECIMAL, forceEncrypt); loggerExternal.exiting(getClassNameLogging(), "setMoney"); } @Override - public void setSmallMoney(String parameterName, - BigDecimal value) throws SQLServerException { + public void setSmallMoney(String parameterName, BigDecimal value) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setSmallMoney", new Object[] {parameterName, value}); checkClosed(); @@ -2046,19 +1949,17 @@ public void setSmallMoney(String parameterName, } @Override - public void setSmallMoney(String parameterName, - BigDecimal value, - boolean forceEncrypt) throws SQLServerException { + public void setSmallMoney(String parameterName, BigDecimal value, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setSmallMoney", new Object[] {parameterName, value, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "setSmallMoney", + new Object[] {parameterName, value, forceEncrypt}); checkClosed(); setValue(findColumn(parameterName), JDBCType.SMALLMONEY, value, JavaType.BIGDECIMAL, forceEncrypt); loggerExternal.exiting(getClassNameLogging(), "setSmallMoney"); } @Override - public void setBigDecimal(String parameterName, - BigDecimal value) throws SQLServerException { + public void setBigDecimal(String parameterName, BigDecimal value) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setBigDecimal", new Object[] {parameterName, value}); checkClosed(); @@ -2067,33 +1968,30 @@ public void setBigDecimal(String parameterName, } @Override - public void setBigDecimal(String parameterName, - BigDecimal value, - int precision, + public void setBigDecimal(String parameterName, BigDecimal value, int precision, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setBigDecimal", new Object[] {parameterName, value, precision, scale}); + loggerExternal.entering(getClassNameLogging(), "setBigDecimal", + new Object[] {parameterName, value, precision, scale}); checkClosed(); setValue(findColumn(parameterName), JDBCType.DECIMAL, value, JavaType.BIGDECIMAL, precision, scale, false); loggerExternal.exiting(getClassNameLogging(), "setBigDecimal"); } @Override - public void setBigDecimal(String parameterName, - BigDecimal value, - int precision, - int scale, + public void setBigDecimal(String parameterName, BigDecimal value, int precision, int scale, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setBigDecimal", new Object[] {parameterName, value, precision, scale, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "setBigDecimal", + new Object[] {parameterName, value, precision, scale, forceEncrypt}); checkClosed(); - setValue(findColumn(parameterName), JDBCType.DECIMAL, value, JavaType.BIGDECIMAL, precision, scale, forceEncrypt); + setValue(findColumn(parameterName), JDBCType.DECIMAL, value, JavaType.BIGDECIMAL, precision, scale, + forceEncrypt); loggerExternal.exiting(getClassNameLogging(), "setBigDecimal"); } @Override - public void setDouble(String parameterName, - double value) throws SQLServerException { + public void setDouble(String parameterName, double value) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setDouble", new Object[] {parameterName, value}); checkClosed(); @@ -2102,19 +2000,17 @@ public void setDouble(String parameterName, } @Override - public void setDouble(String parameterName, - double value, - boolean forceEncrypt) throws SQLServerException { + public void setDouble(String parameterName, double value, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setDouble", new Object[] {parameterName, value, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "setDouble", + new Object[] {parameterName, value, forceEncrypt}); checkClosed(); setValue(findColumn(parameterName), JDBCType.DOUBLE, value, JavaType.DOUBLE, forceEncrypt); loggerExternal.exiting(getClassNameLogging(), "setDouble"); } @Override - public void setFloat(String parameterName, - float value) throws SQLServerException { + public void setFloat(String parameterName, float value) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setFloat", new Object[] {parameterName, value}); checkClosed(); @@ -2123,19 +2019,17 @@ public void setFloat(String parameterName, } @Override - public void setFloat(String parameterName, - float value, - boolean forceEncrypt) throws SQLServerException { + public void setFloat(String parameterName, float value, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setFloat", new Object[] {parameterName, value, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "setFloat", + new Object[] {parameterName, value, forceEncrypt}); checkClosed(); setValue(findColumn(parameterName), JDBCType.REAL, value, JavaType.FLOAT, forceEncrypt); loggerExternal.exiting(getClassNameLogging(), "setFloat"); } @Override - public void setInt(String parameterName, - int value) throws SQLServerException { + public void setInt(String parameterName, int value) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setInt", new Object[] {parameterName, value}); checkClosed(); @@ -2144,9 +2038,7 @@ public void setInt(String parameterName, } @Override - public void setInt(String parameterName, - int value, - boolean forceEncrypt) throws SQLServerException { + public void setInt(String parameterName, int value, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setInt", new Object[] {parameterName, value, forceEncrypt}); checkClosed(); @@ -2155,8 +2047,7 @@ public void setInt(String parameterName, } @Override - public void setLong(String parameterName, - long value) throws SQLServerException { + public void setLong(String parameterName, long value) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setLong", new Object[] {parameterName, value}); checkClosed(); @@ -2165,19 +2056,17 @@ public void setLong(String parameterName, } @Override - public void setLong(String parameterName, - long value, - boolean forceEncrypt) throws SQLServerException { + public void setLong(String parameterName, long value, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setLong", new Object[] {parameterName, value, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "setLong", + new Object[] {parameterName, value, forceEncrypt}); checkClosed(); setValue(findColumn(parameterName), JDBCType.BIGINT, value, JavaType.LONG, forceEncrypt); loggerExternal.exiting(getClassNameLogging(), "setLong"); } @Override - public void setShort(String parameterName, - short value) throws SQLServerException { + public void setShort(String parameterName, short value) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setShort", new Object[] {parameterName, value}); checkClosed(); @@ -2186,19 +2075,17 @@ public void setShort(String parameterName, } @Override - public void setShort(String parameterName, - short value, - boolean forceEncrypt) throws SQLServerException { + public void setShort(String parameterName, short value, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setShort", new Object[] {parameterName, value, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "setShort", + new Object[] {parameterName, value, forceEncrypt}); checkClosed(); setValue(findColumn(parameterName), JDBCType.SMALLINT, value, JavaType.SHORT, forceEncrypt); loggerExternal.exiting(getClassNameLogging(), "setShort"); } @Override - public void setBoolean(String parameterName, - boolean value) throws SQLServerException { + public void setBoolean(String parameterName, boolean value) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setBoolean", new Object[] {parameterName, value}); checkClosed(); @@ -2207,42 +2094,37 @@ public void setBoolean(String parameterName, } @Override - public void setBoolean(String parameterName, - boolean value, - boolean forceEncrypt) throws SQLServerException { + public void setBoolean(String parameterName, boolean value, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setBoolean", new Object[] {parameterName, value, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "setBoolean", + new Object[] {parameterName, value, forceEncrypt}); checkClosed(); setValue(findColumn(parameterName), JDBCType.BIT, value, JavaType.BOOLEAN, forceEncrypt); loggerExternal.exiting(getClassNameLogging(), "setBoolean"); } @Override - public void setNull(String parameterName, - int nType) throws SQLServerException { + public void setNull(String parameterName, int nType) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setNull", new Object[] {parameterName, nType}); checkClosed(); - setObject(setterGetParam(findColumn(parameterName)), null, JavaType.OBJECT, JDBCType.of(nType), null, null, false, findColumn(parameterName), - null); + setObject(setterGetParam(findColumn(parameterName)), null, JavaType.OBJECT, JDBCType.of(nType), null, null, + false, findColumn(parameterName), null); loggerExternal.exiting(getClassNameLogging(), "setNull"); } @Override - public void setNull(String parameterName, - int nType, - String sTypeName) throws SQLServerException { + public void setNull(String parameterName, int nType, String sTypeName) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setNull", new Object[] {parameterName, nType, sTypeName}); checkClosed(); - setObject(setterGetParam(findColumn(parameterName)), null, JavaType.OBJECT, JDBCType.of(nType), null, null, false, findColumn(parameterName), - sTypeName); + setObject(setterGetParam(findColumn(parameterName)), null, JavaType.OBJECT, JDBCType.of(nType), null, null, + false, findColumn(parameterName), sTypeName); loggerExternal.exiting(getClassNameLogging(), "setNull"); } @Override - public void setURL(String parameterName, - URL url) throws SQLException { + public void setURL(String parameterName, URL url) throws SQLException { loggerExternal.entering(getClassNameLogging(), "setURL", parameterName); checkClosed(); setURL(findColumn(parameterName), url); @@ -2250,36 +2132,36 @@ public void setURL(String parameterName, } @Override - public final void setStructured(String parameterName, - String tvpName, + public final void setStructured(String parameterName, String tvpName, SQLServerDataTable tvpDataTable) throws SQLServerException { tvpName = getTVPNameIfNull(findColumn(parameterName), tvpName); if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setStructured", new Object[] {parameterName, tvpName, tvpDataTable}); + loggerExternal.entering(getClassNameLogging(), "setStructured", + new Object[] {parameterName, tvpName, tvpDataTable}); checkClosed(); setValue(findColumn(parameterName), JDBCType.TVP, tvpDataTable, JavaType.TVP, tvpName); loggerExternal.exiting(getClassNameLogging(), "setStructured"); } @Override - public final void setStructured(String parameterName, - String tvpName, + public final void setStructured(String parameterName, String tvpName, ResultSet tvpResultSet) throws SQLServerException { tvpName = getTVPNameIfNull(findColumn(parameterName), tvpName); if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setStructured", new Object[] {parameterName, tvpName, tvpResultSet}); + loggerExternal.entering(getClassNameLogging(), "setStructured", + new Object[] {parameterName, tvpName, tvpResultSet}); checkClosed(); setValue(findColumn(parameterName), JDBCType.TVP, tvpResultSet, JavaType.TVP, tvpName); loggerExternal.exiting(getClassNameLogging(), "setStructured"); } @Override - public final void setStructured(String parameterName, - String tvpName, + public final void setStructured(String parameterName, String tvpName, ISQLServerDataRecord tvpDataRecord) throws SQLServerException { tvpName = getTVPNameIfNull(findColumn(parameterName), tvpName); if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setStructured", new Object[] {parameterName, tvpName, tvpDataRecord}); + loggerExternal.entering(getClassNameLogging(), "setStructured", + new Object[] {parameterName, tvpName, tvpDataRecord}); checkClosed(); setValue(findColumn(parameterName), JDBCType.TVP, tvpDataRecord, JavaType.TVP, tvpName); loggerExternal.exiting(getClassNameLogging(), "setStructured"); @@ -2298,8 +2180,7 @@ public URL getURL(String parameterName) throws SQLException { } @Override - public final void setSQLXML(String parameterName, - SQLXML xmlObject) throws SQLException { + public final void setSQLXML(String parameterName, SQLXML xmlObject) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setSQLXML", new Object[] {parameterName, xmlObject}); checkClosed(); @@ -2326,8 +2207,7 @@ public final SQLXML getSQLXML(String parameterName) throws SQLException { } @Override - public final void setRowId(String parameterName, - RowId value) throws SQLException { + public final void setRowId(String parameterName, RowId value) throws SQLException { SQLServerException.throwNotSupportedException(connection, this); } @@ -2344,55 +2224,52 @@ public final RowId getRowId(String parameterName) throws SQLException { } @Override - public void registerOutParameter(String parameterName, - int sqlType, - String typeName) throws SQLServerException { + public void registerOutParameter(String parameterName, int sqlType, String typeName) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {parameterName, sqlType, typeName}); + loggerExternal.entering(getClassNameLogging(), "registerOutParameter", + new Object[] {parameterName, sqlType, typeName}); checkClosed(); registerOutParameter(findColumn(parameterName), sqlType, typeName); loggerExternal.exiting(getClassNameLogging(), "registerOutParameter"); } @Override - public void registerOutParameter(String parameterName, - int sqlType, - int scale) throws SQLServerException { + public void registerOutParameter(String parameterName, int sqlType, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {parameterName, sqlType, scale}); + loggerExternal.entering(getClassNameLogging(), "registerOutParameter", + new Object[] {parameterName, sqlType, scale}); checkClosed(); registerOutParameter(findColumn(parameterName), sqlType, scale); loggerExternal.exiting(getClassNameLogging(), "registerOutParameter"); } @Override - public void registerOutParameter(String parameterName, - int sqlType, - int precision, + public void registerOutParameter(String parameterName, int sqlType, int precision, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {parameterName, sqlType, scale}); + loggerExternal.entering(getClassNameLogging(), "registerOutParameter", + new Object[] {parameterName, sqlType, scale}); checkClosed(); registerOutParameter(findColumn(parameterName), sqlType, precision, scale); loggerExternal.exiting(getClassNameLogging(), "registerOutParameter"); } @Override - public void registerOutParameter(String parameterName, - int sqlType) throws SQLServerException { + public void registerOutParameter(String parameterName, int sqlType) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {parameterName, sqlType}); + loggerExternal.entering(getClassNameLogging(), "registerOutParameter", + new Object[] {parameterName, sqlType}); checkClosed(); registerOutParameter(findColumn(parameterName), sqlType); loggerExternal.exiting(getClassNameLogging(), "registerOutParameter"); } @Override - public void registerOutParameter(int paramterIndex, - SQLType sqlType) throws SQLServerException { + public void registerOutParameter(int paramterIndex, SQLType sqlType) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {paramterIndex, sqlType}); + loggerExternal.entering(getClassNameLogging(), "registerOutParameter", + new Object[] {paramterIndex, sqlType}); // getVendorTypeNumber() returns the same constant integer values as in java.sql.Types registerOutParameter(paramterIndex, sqlType.getVendorTypeNumber()); @@ -2400,12 +2277,11 @@ public void registerOutParameter(int paramterIndex, } @Override - public void registerOutParameter(int paramterIndex, - SQLType sqlType, - String typeName) throws SQLServerException { + public void registerOutParameter(int paramterIndex, SQLType sqlType, String typeName) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {paramterIndex, sqlType, typeName}); + loggerExternal.entering(getClassNameLogging(), "registerOutParameter", + new Object[] {paramterIndex, sqlType, typeName}); // getVendorTypeNumber() returns the same constant integer values as in java.sql.Types registerOutParameter(paramterIndex, sqlType.getVendorTypeNumber(), typeName); @@ -2413,12 +2289,11 @@ public void registerOutParameter(int paramterIndex, } @Override - public void registerOutParameter(int paramterIndex, - SQLType sqlType, - int scale) throws SQLServerException { + public void registerOutParameter(int paramterIndex, SQLType sqlType, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {paramterIndex, sqlType, scale}); + loggerExternal.entering(getClassNameLogging(), "registerOutParameter", + new Object[] {paramterIndex, sqlType, scale}); // getVendorTypeNumber() returns the same constant integer values as in java.sql.Types registerOutParameter(paramterIndex, sqlType.getVendorTypeNumber(), scale); @@ -2426,13 +2301,12 @@ public void registerOutParameter(int paramterIndex, } @Override - public void registerOutParameter(int paramterIndex, - SQLType sqlType, - int precision, + public void registerOutParameter(int paramterIndex, SQLType sqlType, int precision, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {paramterIndex, sqlType, scale}); + loggerExternal.entering(getClassNameLogging(), "registerOutParameter", + new Object[] {paramterIndex, sqlType, scale}); // getVendorTypeNumber() returns the same constant integer values as in java.sql.Types registerOutParameter(paramterIndex, sqlType.getVendorTypeNumber(), precision, scale); @@ -2440,9 +2314,7 @@ public void registerOutParameter(int paramterIndex, } @Override - public void setObject(String parameterName, - Object value, - SQLType jdbcType) throws SQLServerException { + public void setObject(String parameterName, Object value, SQLType jdbcType) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setObject", new Object[] {parameterName, value, jdbcType}); @@ -2453,13 +2325,11 @@ public void setObject(String parameterName, } @Override - public void setObject(String parameterName, - Object value, - SQLType jdbcType, - int scale) throws SQLServerException { + public void setObject(String parameterName, Object value, SQLType jdbcType, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setObject", new Object[] {parameterName, value, jdbcType, scale}); + loggerExternal.entering(getClassNameLogging(), "setObject", + new Object[] {parameterName, value, jdbcType, scale}); // getVendorTypeNumber() returns the same constant integer values as in java.sql.Types setObject(parameterName, value, jdbcType.getVendorTypeNumber(), scale); @@ -2467,14 +2337,12 @@ public void setObject(String parameterName, } @Override - public void setObject(String parameterName, - Object value, - SQLType jdbcType, - int scale, + public void setObject(String parameterName, Object value, SQLType jdbcType, int scale, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setObject", new Object[] {parameterName, value, jdbcType, scale, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "setObject", + new Object[] {parameterName, value, jdbcType, scale, forceEncrypt}); // getVendorTypeNumber() returns the same constant integer values as in java.sql.Types setObject(parameterName, value, jdbcType.getVendorTypeNumber(), scale, forceEncrypt); @@ -2482,12 +2350,11 @@ public void setObject(String parameterName, } @Override - public void registerOutParameter(String parameterName, - SQLType sqlType, - String typeName) throws SQLServerException { + public void registerOutParameter(String parameterName, SQLType sqlType, String typeName) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {parameterName, sqlType, typeName}); + loggerExternal.entering(getClassNameLogging(), "registerOutParameter", + new Object[] {parameterName, sqlType, typeName}); // getVendorTypeNumber() returns the same constant integer values as in java.sql.Types registerOutParameter(parameterName, sqlType.getVendorTypeNumber(), typeName); @@ -2495,12 +2362,11 @@ public void registerOutParameter(String parameterName, } @Override - public void registerOutParameter(String parameterName, - SQLType sqlType, - int scale) throws SQLServerException { + public void registerOutParameter(String parameterName, SQLType sqlType, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {parameterName, sqlType, scale}); + loggerExternal.entering(getClassNameLogging(), "registerOutParameter", + new Object[] {parameterName, sqlType, scale}); // getVendorTypeNumber() returns the same constant integer values as in java.sql.Types registerOutParameter(parameterName, sqlType.getVendorTypeNumber(), scale); @@ -2508,13 +2374,12 @@ public void registerOutParameter(String parameterName, } @Override - public void registerOutParameter(String parameterName, - SQLType sqlType, - int precision, + public void registerOutParameter(String parameterName, SQLType sqlType, int precision, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {parameterName, sqlType, scale}); + loggerExternal.entering(getClassNameLogging(), "registerOutParameter", + new Object[] {parameterName, sqlType, scale}); // getVendorTypeNumber() returns the same constant integer values as in java.sql.Types registerOutParameter(parameterName, sqlType.getVendorTypeNumber(), precision, scale); @@ -2522,11 +2387,11 @@ public void registerOutParameter(String parameterName, } @Override - public void registerOutParameter(String parameterName, - SQLType sqlType) throws SQLServerException { + public void registerOutParameter(String parameterName, SQLType sqlType) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {parameterName, sqlType}); + loggerExternal.entering(getClassNameLogging(), "registerOutParameter", + new Object[] {parameterName, sqlType}); // getVendorTypeNumber() returns the same constant integer values as in java.sql.Types registerOutParameter(parameterName, sqlType.getVendorTypeNumber()); diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerClob.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerClob.java index 31b8d0837..b59fd9062 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerClob.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerClob.java @@ -1,15 +1,12 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; -import static java.nio.charset.StandardCharsets.UTF_16LE; import static java.nio.charset.StandardCharsets.US_ASCII; +import static java.nio.charset.StandardCharsets.UTF_16LE; import java.io.BufferedInputStream; import java.io.BufferedReader; @@ -25,17 +22,16 @@ import java.io.Writer; import java.sql.Clob; import java.sql.SQLException; -import java.sql.SQLFeatureNotSupportedException; import java.text.MessageFormat; import java.util.ArrayList; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.logging.Logger; + /** - * SQLServerClob represents a character LOB object and implements java.sql.Clob. + * Represents a character LOB object and implements java.sql.Clob. */ - public class SQLServerClob extends SQLServerClobBase implements Clob { /** * Always refresh SerialVersionUID when prompted @@ -47,17 +43,16 @@ public class SQLServerClob extends SQLServerClobBase implements Clob { private static final Logger logger = Logger.getLogger("com.microsoft.sqlserver.jdbc.internals.SQLServerClob"); /** - * Create a new CLOB + * Constructs a SQLServerClob. * * @param connection - * the database connection this blob is implemented on + * the database connection this blob is implemented on * @param data - * the CLOB's data + * the CLOB's data * @deprecated Use {@link SQLServerConnection#createClob()} instead. */ @Deprecated - public SQLServerClob(SQLServerConnection connection, - String data) { + public SQLServerClob(SQLServerConnection connection, String data) { super(connection, data, (null == connection) ? null : connection.getDatabaseCollation(), logger, null); if (null == data) @@ -68,8 +63,7 @@ public SQLServerClob(SQLServerConnection connection, super(connection, "", connection.getDatabaseCollation(), logger, null); } - SQLServerClob(BaseInputStream stream, - TypeInfo typeInfo) throws SQLServerException, UnsupportedEncodingException { + SQLServerClob(BaseInputStream stream, TypeInfo typeInfo) throws SQLServerException, UnsupportedEncodingException { super(null, stream, typeInfo.getSQLCollation(), logger, typeInfo); } @@ -89,14 +83,12 @@ public Reader getCharacterStream() throws SQLException { } @Override - public Reader getCharacterStream(long pos, - long length) throws SQLException { + public Reader getCharacterStream(long pos, long length) throws SQLException { return super.getCharacterStream(pos, length); } @Override - public String getSubString(long pos, - int length) throws SQLException { + public String getSubString(long pos, int length) throws SQLException { return super.getSubString(pos, length); } @@ -111,14 +103,12 @@ void fillFromStream() throws SQLException { } @Override - public long position(Clob searchstr, - long start) throws SQLException { + public long position(Clob searchstr, long start) throws SQLException { return super.position(searchstr, start); } @Override - public long position(String searchstr, - long start) throws SQLException { + public long position(String searchstr, long start) throws SQLException { return super.position(searchstr, start); } @@ -138,16 +128,12 @@ public Writer setCharacterStream(long pos) throws SQLException { } @Override - public int setString(long pos, - String s) throws SQLException { + public int setString(long pos, String s) throws SQLException { return super.setString(pos, s); } @Override - public int setString(long pos, - String str, - int offset, - int len) throws SQLException { + public int setString(long pos, String str, int offset, int len) throws SQLException { return super.setString(pos, str, offset, len); } @@ -157,6 +143,7 @@ final JDBCType getJdbcType() { } } + abstract class SQLServerClobBase extends SQLServerLob implements Serializable { /** * Always refresh SerialVersionUID when prompted @@ -173,20 +160,19 @@ abstract class SQLServerClobBase extends SQLServerLob implements Serializable { private final TypeInfo typeInfo; - // Active streams which must be closed when the Clob/NClob is closed - // - // Initial size of the array is based on an assumption that a Clob/NClob - // object is - // typically used either for input or output, and then only once. The array - // size - // grows automatically if multiple streams are used. + /** + * Active streams which must be closed when the Clob/NClob is closed. Initial size of the array is based on an + * assumption that a Clob/NClob object is typically used either for input or output, and then only once. The array + * size grows automatically if multiple streams are used. + */ private ArrayList activeStreams = new ArrayList<>(1); transient SQLServerConnection con; private final Logger logger; - final private String traceID = getClass().getName().substring(1 + getClass().getName().lastIndexOf('.')) + ":" + nextInstanceID(); + final private String traceID = getClass().getName().substring(1 + getClass().getName().lastIndexOf('.')) + ":" + + nextInstanceID(); final public String toString() { return traceID; @@ -209,29 +195,25 @@ private String getDisplayClassName() { } /** - * Create a new CLOB from a String + * Constructs a new CLOB from a String. * * @param connection - * SQLServerConnection + * SQLServerConnection * @param data - * the CLOB data + * the CLOB data * @param collation - * the data collation + * the data collation * @param logger - * logger information + * logger information * @param typeInfo - * the column TYPE_INFO + * the column TYPE_INFO */ - SQLServerClobBase(SQLServerConnection connection, - Object data, - SQLCollation collation, - Logger logger, + SQLServerClobBase(SQLServerConnection connection, Object data, SQLCollation collation, Logger logger, TypeInfo typeInfo) { this.con = connection; if (data instanceof BaseInputStream) { activeStreams.add((Closeable) data); - } - else { + } else { this.value = (String) data; } this.sqlCollation = collation; @@ -246,11 +228,11 @@ private String getDisplayClassName() { /** * Frees this Clob/NClob object and releases the resources that it holds. * - * After free() has been called, any attempt to invoke a method other than free() will result in a SQLException being thrown. If free() is called - * multiple times, the subsequent calls to free are treated as a no-op. + * After free() has been called, any attempt to invoke a method other than free() will result in a SQLException + * being thrown. If free() is called multiple times, the subsequent calls to free are treated as a no-op. * * @throws SQLException - * when an error occurs + * when an error occurs */ public void free() throws SQLException { if (!isClosed) { @@ -260,9 +242,9 @@ public void free() throws SQLException { for (Closeable stream : activeStreams) { try { stream.close(); - } - catch (IOException ioException) { - logger.fine(toString() + " ignored IOException closing stream " + stream + ": " + ioException.getMessage()); + } catch (IOException ioException) { + logger.fine(toString() + " ignored IOException closing stream " + stream + ": " + + ioException.getMessage()); } } activeStreams = null; @@ -281,15 +263,16 @@ public void free() throws SQLException { private void checkClosed() throws SQLServerException { if (isClosed) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_isFreed")); - SQLServerException.makeFromDriverError(con, null, form.format(new Object[] {getDisplayClassName()}), null, true); + SQLServerException.makeFromDriverError(con, null, form.format(new Object[] {getDisplayClassName()}), null, + true); } } /** - * Materialize the CLOB as an ASCII stream. + * Returns the CLOB as an ASCII stream. * * @throws SQLException - * when an error occurs + * when an error occurs * @return the data as an input stream */ public InputStream getAsciiStream() throws SQLException { @@ -299,16 +282,17 @@ public InputStream getAsciiStream() throws SQLException { DataTypes.throwConversionError(getDisplayClassName(), "AsciiStream"); getStringFromStream(); - InputStream getterStream = new BufferedInputStream(new ReaderInputStream(new StringReader(value), US_ASCII, value.length())); + InputStream getterStream = new BufferedInputStream( + new ReaderInputStream(new StringReader(value), US_ASCII, value.length())); activeStreams.add(getterStream); return getterStream; } /** - * Retrieves the CLOB value designated by this Clob object as a java.io.Reader object (or as a stream of characters). + * Returns the CLOB value designated by this Clob object as a java.io.Reader object (or as a stream of characters). * * @throws SQLException - * if there is an error accessing the CLOB value + * if there is an error accessing the CLOB value * @return a java.io.Reader object containing the CLOB data */ public Reader getCharacterStream() throws SQLException { @@ -318,8 +302,7 @@ public Reader getCharacterStream() throws SQLException { if (null == value && !activeStreams.isEmpty()) { InputStream inputStream = (InputStream) activeStreams.get(0); getterStream = new BufferedReader(new InputStreamReader(inputStream, UTF_16LE)); - } - else { + } else { getterStream = new StringReader(value); activeStreams.add(getterStream); } @@ -327,36 +310,35 @@ public Reader getCharacterStream() throws SQLException { } /** - * Returns the Clob data as a java.io.Reader object or as a stream of characters with the specified position and length. + * Returns the Clob data as a java.io.Reader object or as a stream of characters with the specified position and + * length. * * @param pos - * A long that indicates the offset to the first character of the partial value to be retrieved. + * A long that indicates the offset to the first character of the partial value to be retrieved. * @param length - * A long that indicates the length in characters of the partial value to be retrieved. + * A long that indicates the length in characters of the partial value to be retrieved. * @return A Reader object that contains the Clob data. * @throws SQLException - * when an error occurs. + * when an error occurs. */ - public Reader getCharacterStream(long pos, - long length) throws SQLException { + public Reader getCharacterStream(long pos, long length) throws SQLException { SQLServerException.throwFeatureNotSupportedException(); return null; } /** - * Retrieves a copy of the specified substring in the CLOB value designated by this Clob object. The substring begins at position pos and has up - * to length consecutive characters. + * Returns a copy of the specified substring in the CLOB value designated by this Clob object. The substring begins + * at position pos and has up to length consecutive characters. * * @param pos - * - the first character of the substring to be extracted. The first character is at position 1. + * - the first character of the substring to be extracted. The first character is at position 1. * @param length - * - the number of consecutive characters to be copied; the value for length must be 0 or greater + * - the number of consecutive characters to be copied; the value for length must be 0 or greater * @return a String that is the specified substring in the CLOB value designated by this Clob object * @throws SQLException - * - if there is an error accessing the CLOB value; if pos is less than 1 or length is less than 0 + * - if there is an error accessing the CLOB value; if pos is less than 1 or length is less than 0 */ - public String getSubString(long pos, - int length) throws SQLException { + public String getSubString(long pos, int length) throws SQLException { checkClosed(); getStringFromStream(); @@ -391,10 +373,10 @@ public String getSubString(long pos, } /** - * Retrieves the number of characters in the CLOB value designated by this Clob object. + * Returns the number of characters in the CLOB value designated by this Clob object. * * @throws SQLException - * when an error occurs + * when an error occurs * @return length of the CLOB in characters */ public long length() throws SQLException { @@ -407,7 +389,7 @@ public long length() throws SQLException { } /** - * Function for the result set to maintain clobs it has created + * Provides functionality for the result set to maintain clobs it has created. * * @throws SQLException */ @@ -418,7 +400,7 @@ void fillFromStream() throws SQLException { } /** - * Converts the stream to String + * Converts the stream to String. * * @throws SQLServerException */ @@ -427,8 +409,7 @@ private void getStringFromStream() throws SQLServerException { BaseInputStream stream = (BaseInputStream) activeStreams.get(0); try { stream.reset(); - } - catch (IOException e) { + } catch (IOException e) { throw new SQLServerException(e.getMessage(), null, 0, e); } value = new String((stream).getBytes(), typeInfo.getCharset()); @@ -436,18 +417,18 @@ private void getStringFromStream() throws SQLServerException { } /** - * Retrieves the character position at which the specified Clob object searchstr appears in this Clob object. The search begins at position start. + * Returns the character position at which the specified Clob object searchstr appears in this Clob object. The + * search begins at position start. * * @param searchstr - * - the Clob for which to search + * - the Clob for which to search * @param start - * - the position at which to begin searching; the first position is 1 + * - the position at which to begin searching; the first position is 1 * @return the position at which the Clob object appears or -1 if it is not present; the first position is 1 * @throws SQLException - * - if there is an error accessing the CLOB value or if start is less than 1 + * - if there is an error accessing the CLOB value or if start is less than 1 */ - public long position(Clob searchstr, - long start) throws SQLException { + public long position(Clob searchstr, long start) throws SQLException { checkClosed(); getStringFromStream(); @@ -464,19 +445,18 @@ public long position(Clob searchstr, } /** - * Retrieves the character position at which the specified substring searchstr appears in the SQL CLOB value represented by this Clob object. The - * search begins at position start. + * Returns the character position at which the specified substring searchstr appears in the SQL CLOB value + * represented by this Clob object. The search begins at position start. * * @param searchstr - * - the substring for which to search + * - the substring for which to search * @param start - * - the position at which to begin searching; the first position is 1 + * - the position at which to begin searching; the first position is 1 * @return the position at which the substring appears or -1 if it is not present; the first position is 1 * @throws SQLException - * - if there is an error accessing the CLOB value or if start is less than 1 + * - if there is an error accessing the CLOB value or if start is less than 1 */ - public long position(String searchstr, - long start) throws SQLException { + public long position(String searchstr, long start) throws SQLException { checkClosed(); getStringFromStream(); @@ -505,9 +485,9 @@ public long position(String searchstr, * Truncates the CLOB value that this Clob designates to have a length of len characters. * * @param len - * the length, in characters, to which the CLOB value should be truncated + * the length, in characters, to which the CLOB value should be truncated * @throws SQLException - * when an error occurs + * when an error occurs */ public void truncate(long len) throws SQLException { checkClosed(); @@ -524,12 +504,13 @@ public void truncate(long len) throws SQLException { } /** - * Retrieves a stream to be used to write Ascii characters to the CLOB value that this Clob object represents, starting at position pos. + * Returns a stream to be used to write Ascii characters to the CLOB value that this Clob object represents, + * starting at position pos. * * @param pos - * the position at which to start writing to this CLOB object + * the position at which to start writing to this CLOB object * @throws SQLException - * when an error occurs + * when an error occurs * @return the stream to which ASCII encoded characters can be written */ public java.io.OutputStream setAsciiStream(long pos) throws SQLException { @@ -545,12 +526,13 @@ public java.io.OutputStream setAsciiStream(long pos) throws SQLException { } /** - * Retrieves a stream to be used to write a stream of Unicode characters to the CLOB value that this Clob object represents, at position pos. + * Returns a stream to be used to write a stream of Unicode characters to the CLOB value that this Clob object + * represents, at position pos. * * @param pos - * the position at which to start writing to the CLOB value + * the position at which to start writing to the CLOB value * @throws SQLException - * when an error occurs + * when an error occurs * @return a stream to which Unicode encoded characters can be written */ public java.io.Writer setCharacterStream(long pos) throws SQLException { @@ -569,51 +551,51 @@ public java.io.Writer setCharacterStream(long pos) throws SQLException { * Writes the given Java String to the CLOB value that this Clob object designates at the position pos. * * @param pos - * the position at which to start writing to the CLOB + * the position at which to start writing to the CLOB * @param s - * the string to be written to the CLOB value that this Clob designates + * the string to be written to the CLOB value that this Clob designates * @throws SQLException - * when an error occurs + * when an error occurs * @return the number of characters written */ - public int setString(long pos, - String s) throws SQLException { + public int setString(long pos, String s) throws SQLException { checkClosed(); if (null == s) - SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_cantSetNull"), null, true); + SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_cantSetNull"), null, + true); return setString(pos, s, 0, s.length()); } /** - * Writes len characters of str, starting at character offset, to the CLOB value that this Clob represents. The string will overwrite the existing - * characters in the Clob object starting at the position pos. If the end of the Clob value is reached while writing the given string, then the - * length of the Clob value will be increased to accomodate the extra characters. + * Writes len characters of str, starting at character offset, to the CLOB value that this Clob represents. The + * string will overwrite the existing characters in the Clob object starting at the position pos. If the end of the + * Clob value is reached while writing the given string, then the length of the Clob value will be increased to + * accomodate the extra characters. * - * SQL Server behavior: If the value specified for pos is greater than then length+1 of the CLOB value then a SQLException is thrown. + * SQL Server behavior: If the value specified for pos is greater than then length+1 of the CLOB value then a + * SQLException is thrown. * * @param pos - * - the position at which to start writing to this CLOB object; The first position is 1 + * - the position at which to start writing to this CLOB object; The first position is 1 * @param str - * - the string to be written to the CLOB value that this Clob object represents + * - the string to be written to the CLOB value that this Clob object represents * @param offset - * - the offset (0-based) into str to start reading the characters to be written + * - the offset (0-based) into str to start reading the characters to be written * @param len - * - the number of characters to be written + * - the number of characters to be written * @return the number of characters written * @throws SQLException - * - if there is an error accessing the CLOB value or if pos is less than 1 + * - if there is an error accessing the CLOB value or if pos is less than 1 */ - public int setString(long pos, - String str, - int offset, - int len) throws SQLException { + public int setString(long pos, String str, int offset, int len) throws SQLException { checkClosed(); getStringFromStream(); if (null == str) - SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_cantSetNull"), null, true); + SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_cantSetNull"), null, + true); // Offset must be within incoming string str boundary. if (offset < 0 || offset > str.length()) { @@ -681,22 +663,17 @@ public int setString(long pos, } } -// SQLServerClobWriter is a simple java.io.Writer interface implementing class -// that -// forwards all calls to SQLServerClob.setString. This class is returned to -// caller by -// SQLServerClob class when setCharacterStream is called. -// -// SQLServerClobWriter starts writing at postion streamPos and continues to -// write -// in a forward only manner. There is no reset with java.io.Writer. -// + +/** + * Provides a simple java.io.Writer interface that forwards all calls to SQLServerClob.setString.\ This class is + * returned to caller by SQLServerClob class when setCharacterStream is called. SQLServerClobWriter starts writing at + * postion streamPos and continues to write in a forward only manner. There is no reset with java.io.Writer. + */ final class SQLServerClobWriter extends java.io.Writer { private SQLServerClobBase parentClob = null; private long streamPos; - SQLServerClobWriter(SQLServerClobBase parentClob, - long streamPos) { + SQLServerClobWriter(SQLServerClobBase parentClob, long streamPos) { this.parentClob = parentClob; this.streamPos = streamPos; } @@ -707,9 +684,7 @@ public void write(char[] cbuf) throws IOException { write(new String(cbuf)); } - public void write(char[] cbuf, - int off, - int len) throws IOException { + public void write(char[] cbuf, int off, int len) throws IOException { if (null == cbuf) return; write(new String(cbuf, off, len)); @@ -721,9 +696,7 @@ public void write(int b) throws java.io.IOException { write(new String(c)); } - public void write(String str, - int off, - int len) throws IOException { + public void write(String str, int off, int len) throws IOException { checkClosed(); try { // Call parent's setString and update position. @@ -731,8 +704,7 @@ public void write(String str, // this to an IOException here. int charsWritten = parentClob.setString(streamPos, str, off, len); streamPos += charsWritten; - } - catch (SQLException ex) { + } catch (SQLException ex) { throw new IOException(ex.getMessage()); } } @@ -758,22 +730,17 @@ private void checkClosed() throws IOException { } } -// SQLServerClobAsciiOutputStream is a simple java.io.OutputStream interface -// implementing class that -// forwards all calls to SQLServerClob.setString. This class is returned to -// caller by -// SQLServerClob class when setAsciiStream is called. -// -// SQLServerClobAsciiOutputStream starts writing at character postion streamPos -// and continues to write -// in a forward only manner. Reset/mark are not supported. -// + +/** + * Provides a simple java.io.OutputStream interface that forwards all calls to SQLServerClob.setString. This class is + * returned to caller by SQLServerClob class when setAsciiStream is called. SQLServerClobAsciiOutputStream starts + * writing at character postion streamPos and continues to write in a forward only manner. Reset/mark are not supported. + */ final class SQLServerClobAsciiOutputStream extends java.io.OutputStream { private SQLServerClobBase parentClob = null; private long streamPos; - SQLServerClobAsciiOutputStream(SQLServerClobBase parentClob, - long streamPos) { + SQLServerClobAsciiOutputStream(SQLServerClobBase parentClob, long streamPos) { this.parentClob = parentClob; this.streamPos = streamPos; } @@ -784,9 +751,7 @@ public void write(byte[] b) throws IOException { write(b, 0, b.length); } - public void write(byte[] b, - int off, - int len) throws IOException { + public void write(byte[] b, int off, int len) throws IOException { if (null == b) return; try { @@ -798,8 +763,7 @@ public void write(byte[] b, // this to an IOException here. int charsWritten = parentClob.setString(streamPos, s); streamPos += charsWritten; - } - catch (SQLException ex) { + } catch (SQLException ex) { throw new IOException(ex.getMessage()); } } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncryptionAzureKeyVaultProvider.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncryptionAzureKeyVaultProvider.java index 201f13c7b..5b3e25eab 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncryptionAzureKeyVaultProvider.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncryptionAzureKeyVaultProvider.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -33,14 +30,16 @@ import okhttp3.OkHttpClient; import retrofit2.Retrofit; + /** - * Provides implementation similar to certificate store provider. A CEK encrypted with certificate store provider should be decryptable by this - * provider and vice versa. + * Provides implementation similar to certificate store provider. A CEK encrypted with certificate store provider should + * be decryptable by this provider and vice versa. * - * Envelope Format for the encrypted column encryption key version + keyPathLength + ciphertextLength + keyPath + ciphertext + signature version: A - * single byte indicating the format version. keyPathLength: Length of the keyPath. ciphertextLength: ciphertext length keyPath: keyPath used to - * encrypt the column encryption key. This is only used for troubleshooting purposes and is not verified during decryption. ciphertext: Encrypted - * column encryption key signature: Signature of the entire byte array. Signature is validated before decrypting the column encryption key. + * Envelope Format for the encrypted column encryption key version + keyPathLength + ciphertextLength + keyPath + + * ciphertext + signature version: A single byte indicating the format version. keyPathLength: Length of the keyPath. + * ciphertextLength: ciphertext length keyPath: keyPath used to encrypt the column encryption key. This is only used for + * troubleshooting purposes and is not verified during decryption. ciphertext: Encrypted column encryption key + * signature: Signature of the entire byte array. Signature is validated before decrypting the column encryption key. */ public class SQLServerColumnEncryptionAzureKeyVaultProvider extends SQLServerColumnEncryptionKeyStoreProvider { @@ -73,76 +72,79 @@ public String getName() { } /** - * Constructor that takes a callback function to authenticate to AAD. This is used by KeyVaultClient at runtime to authenticate to Azure Key - * Vault. + * Constructs a SQLServerColumnEncryptionAzureKeyVaultProvider with a callback function to authenticate to AAD and + * an executor service.. This is used by KeyVaultClient at runtime to authenticate to Azure Key Vault. * - * This constructor is present to maintain backwards compatibility with 6.0 version of the driver. Deprecated for removal in next stable release. + * This constructor is present to maintain backwards compatibility with 6.0 version of the driver. Deprecated for + * removal in next stable release. * * @param authenticationCallback - * - Callback function used for authenticating to AAD. + * - Callback function used for authenticating to AAD. * @param executorService - * - The ExecutorService, previously used to create the keyVaultClient, but not in use anymore. - This parameter can be passed as 'null' + * - The ExecutorService, previously used to create the keyVaultClient, but not in use anymore. - This + * parameter can be passed as 'null' * @throws SQLServerException - * when an error occurs + * when an error occurs */ @Deprecated - public SQLServerColumnEncryptionAzureKeyVaultProvider(SQLServerKeyVaultAuthenticationCallback authenticationCallback, + public SQLServerColumnEncryptionAzureKeyVaultProvider( + SQLServerKeyVaultAuthenticationCallback authenticationCallback, ExecutorService executorService) throws SQLServerException { this(authenticationCallback); } /** - * Constructor that takes a callback function to authenticate to AAD. This is used by KeyVaultClient at runtime to authenticate to Azure Key - * Vault. + * Constructs a SQLServerColumnEncryptionAzureKeyVaultProvider with a callback function to authenticate to AAD. This + * is used by KeyVaultClient at runtime to authenticate to Azure Key Vault. * * @param authenticationCallback - * - Callback function used for authenticating to AAD. + * - Callback function used for authenticating to AAD. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public SQLServerColumnEncryptionAzureKeyVaultProvider(SQLServerKeyVaultAuthenticationCallback authenticationCallback) throws SQLServerException { + public SQLServerColumnEncryptionAzureKeyVaultProvider( + SQLServerKeyVaultAuthenticationCallback authenticationCallback) throws SQLServerException { if (null == authenticationCallback) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_NullValue")); Object[] msgArgs1 = {"SQLServerKeyVaultAuthenticationCallback"}; throw new SQLServerException(form.format(msgArgs1), null); } credentials = new KeyVaultCredential(authenticationCallback); - RestClient restClient = new RestClient.Builder(new OkHttpClient.Builder(), new Retrofit.Builder()).withBaseUrl(baseUrl) - .withCredentials(credentials).withSerializerAdapter(new AzureJacksonAdapter()) + RestClient restClient = new RestClient.Builder(new OkHttpClient.Builder(), new Retrofit.Builder()) + .withBaseUrl(baseUrl).withCredentials(credentials).withSerializerAdapter(new AzureJacksonAdapter()) .withResponseBuilderFactory(new AzureResponseBuilder.Factory()).build(); keyVaultClient = new KeyVaultClient(restClient); } /** - * Constructor that authenticates to AAD. This is used by KeyVaultClient at runtime to authenticate to Azure Key Vault. + * Constructs a SQLServerColumnEncryptionAzureKeyVaultProvider with a client id and client key to authenticate to + * AAD. This is used by KeyVaultClient at runtime to authenticate to Azure Key Vault. * * @param clientId - * Identifier of the client requesting the token. + * Identifier of the client requesting the token. * @param clientKey - * Key of the client requesting the token. + * Key of the client requesting the token. * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public SQLServerColumnEncryptionAzureKeyVaultProvider(String clientId, - String clientKey) throws SQLServerException { + public SQLServerColumnEncryptionAzureKeyVaultProvider(String clientId, String clientKey) throws SQLServerException { credentials = new KeyVaultCredential(clientId, clientKey); keyVaultClient = new KeyVaultClient(credentials); } /** - * This function uses the asymmetric key specified by the key path and decrypts an encrypted CEK with RSA encryption algorithm. + * Decryptes an encrypted CEK with RSA encryption algorithm using the asymmetric key specified by the key path * * @param masterKeyPath - * - Complete path of an asymmetric key in AKV + * - Complete path of an asymmetric key in AKV * @param encryptionAlgorithm - * - Asymmetric Key Encryption Algorithm + * - Asymmetric Key Encryption Algorithm * @param encryptedColumnEncryptionKey - * - Encrypted Column Encryption Key + * - Encrypted Column Encryption Key * @return Plain text column encryption key */ @Override - public byte[] decryptColumnEncryptionKey(String masterKeyPath, - String encryptionAlgorithm, + public byte[] decryptColumnEncryptionKey(String masterKeyPath, String encryptionAlgorithm, byte[] encryptedColumnEncryptionKey) throws SQLServerException { // Validate the input parameters @@ -166,13 +168,16 @@ public byte[] decryptColumnEncryptionKey(String masterKeyPath, // Format is // version + keyPathLength + ciphertextLength + keyPath + ciphertext + signature // - // keyPath is present in the encrypted column encryption key for identifying the original source of the asymmetric key pair and + // keyPath is present in the encrypted column encryption key for identifying the original source of the + // asymmetric key pair and // we will not validate it against the data contained in the CMK metadata (masterKeyPath). // Validate the version byte if (encryptedColumnEncryptionKey[0] != firstVersion[0]) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidEcryptionAlgorithmVersion")); - Object[] msgArgs = {String.format("%02X ", encryptedColumnEncryptionKey[0]), String.format("%02X ", firstVersion[0])}; + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_InvalidEcryptionAlgorithmVersion")); + Object[] msgArgs = {String.format("%02X ", encryptedColumnEncryptionKey[0]), + String.format("%02X ", firstVersion[0])}; throw new SQLServerException(this, form.format(msgArgs), null, 0, false); } @@ -218,13 +223,13 @@ public byte[] decryptColumnEncryptionKey(String masterKeyPath, // Compute the hash to validate the signature byte[] hash = new byte[encryptedColumnEncryptionKey.length - signature.length]; - System.arraycopy(encryptedColumnEncryptionKey, 0, hash, 0, encryptedColumnEncryptionKey.length - signature.length); + System.arraycopy(encryptedColumnEncryptionKey, 0, hash, 0, + encryptedColumnEncryptionKey.length - signature.length); MessageDigest md = null; try { md = MessageDigest.getInstance("SHA-256"); - } - catch (NoSuchAlgorithmException e) { + } catch (NoSuchAlgorithmException e) { throw new SQLServerException(SQLServerException.getErrString("R_NoSHA256Algorithm"), e); } md.update(hash); @@ -247,12 +252,12 @@ public byte[] decryptColumnEncryptionKey(String masterKeyPath, return decryptedCEK; } - private short convertTwoBytesToShort(byte[] input, - int index) throws SQLServerException { + private short convertTwoBytesToShort(byte[] input, int index) throws SQLServerException { short shortVal; if (index + 1 >= input.length) { - throw new SQLServerException(null, SQLServerException.getErrString("R_ByteToShortConversion"), null, 0, false); + throw new SQLServerException(null, SQLServerException.getErrString("R_ByteToShortConversion"), null, 0, + false); } ByteBuffer byteBuffer = ByteBuffer.allocate(2); byteBuffer.order(ByteOrder.LITTLE_ENDIAN); @@ -264,19 +269,18 @@ private short convertTwoBytesToShort(byte[] input, } /** - * This function uses the asymmetric key specified by the key path and encrypts CEK with RSA encryption algorithm. + * Encrypts CEK with RSA encryption algorithm using the asymmetric key specified by the key path. * * @param masterKeyPath - * - Complete path of an asymmetric key in AKV + * - Complete path of an asymmetric key in AKV * @param encryptionAlgorithm - * - Asymmetric Key Encryption Algorithm + * - Asymmetric Key Encryption Algorithm * @param columnEncryptionKey - * - Plain text column encryption key + * - Plain text column encryption key * @return Encrypted column encryption key */ @Override - public byte[] encryptColumnEncryptionKey(String masterKeyPath, - String encryptionAlgorithm, + public byte[] encryptColumnEncryptionKey(String masterKeyPath, String encryptionAlgorithm, byte[] columnEncryptionKey) throws SQLServerException { // Validate the input parameters @@ -323,7 +327,8 @@ public byte[] encryptColumnEncryptionKey(String masterKeyPath, // Compute hash // SHA-2-256(version + keyPathLength + ciphertextLength + keyPath + ciphertext) - byte[] dataToHash = new byte[version.length + keyPathLength.length + cipherTextLength.length + masterKeyPathBytes.length + cipherText.length]; + byte[] dataToHash = new byte[version.length + keyPathLength.length + cipherTextLength.length + + masterKeyPathBytes.length + cipherText.length]; int destinationPosition = version.length; System.arraycopy(version, 0, dataToHash, 0, version.length); @@ -341,8 +346,7 @@ public byte[] encryptColumnEncryptionKey(String masterKeyPath, MessageDigest md = null; try { md = MessageDigest.getInstance("SHA-256"); - } - catch (NoSuchAlgorithmException e) { + } catch (NoSuchAlgorithmException e) { throw new SQLServerException(SQLServerException.getErrString("R_NoSHA256Algorithm"), e); } md.update(dataToHash); @@ -361,8 +365,8 @@ public byte[] encryptColumnEncryptionKey(String masterKeyPath, // Construct the encrypted column encryption key // EncryptedColumnEncryptionKey = version + keyPathLength + ciphertextLength + keyPath + ciphertext + signature - int encryptedColumnEncryptionKeyLength = version.length + cipherTextLength.length + keyPathLength.length + cipherText.length - + masterKeyPathBytes.length + signedHash.length; + int encryptedColumnEncryptionKeyLength = version.length + cipherTextLength.length + keyPathLength.length + + cipherText.length + masterKeyPathBytes.length + signedHash.length; byte[] encryptedColumnEncryptionKey = new byte[encryptedColumnEncryptionKeyLength]; // Copy version byte @@ -393,17 +397,18 @@ public byte[] encryptColumnEncryptionKey(String masterKeyPath, } /** - * This function validates that the encryption algorithm is RSA_OAEP and if it is not, then throws an exception + * Validates that the encryption algorithm is RSA_OAEP and if it is not, then throws an exception. * * @param encryptionAlgorithm - * - Asymmetric key encryptio algorithm + * - Asymmetric key encryptio algorithm * @return The encryption algorithm that is going to be used. * @throws SQLServerException */ private String validateEncryptionAlgorithm(String encryptionAlgorithm) throws SQLServerException { if (null == encryptionAlgorithm) { - throw new SQLServerException(null, SQLServerException.getErrString("R_NullKeyEncryptionAlgorithm"), null, 0, false); + throw new SQLServerException(null, SQLServerException.getErrString("R_NullKeyEncryptionAlgorithm"), null, 0, + false); } // Transform to standard format (dash instead of underscore) to support both "RSA_OAEP" and "RSA-OAEP" @@ -432,13 +437,11 @@ private void ValidateNonEmptyAKVPath(String masterKeyPath) throws SQLServerExcep MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_AKVPathNull")); Object[] msgArgs = {masterKeyPath}; throw new SQLServerException(null, form.format(msgArgs), null, 0, false); - } - else { + } else { URI parsedUri = null; try { parsedUri = new URI(masterKeyPath); - } - catch (URISyntaxException e) { + } catch (URISyntaxException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_AKVURLInvalid")); Object[] msgArgs = {masterKeyPath}; throw new SQLServerException(form.format(msgArgs), null, 0, e); @@ -456,44 +459,43 @@ private void ValidateNonEmptyAKVPath(String masterKeyPath) throws SQLServerExcep } /** - * Encrypt the text using specified Azure Key Vault key. + * Encrypts the text using specified Azure Key Vault key. * * @param masterKeyPath - * - Azure Key Vault key url. + * - Azure Key Vault key url. * @param encryptionAlgorithm - * - Encryption Algorithm. + * - Encryption Algorithm. * @param columnEncryptionKey - * - Plain text Column Encryption Key. + * - Plain text Column Encryption Key. * @return Returns an encrypted blob or throws an exception if there are any errors. * @throws SQLServerException */ - private byte[] AzureKeyVaultWrap(String masterKeyPath, - String encryptionAlgorithm, + private byte[] AzureKeyVaultWrap(String masterKeyPath, String encryptionAlgorithm, byte[] columnEncryptionKey) throws SQLServerException { if (null == columnEncryptionKey) { throw new SQLServerException(SQLServerException.getErrString("R_CEKNull"), null); } JsonWebKeyEncryptionAlgorithm jsonEncryptionAlgorithm = new JsonWebKeyEncryptionAlgorithm(encryptionAlgorithm); - KeyOperationResult wrappedKey = keyVaultClient.wrapKey(masterKeyPath, jsonEncryptionAlgorithm, columnEncryptionKey); + KeyOperationResult wrappedKey = keyVaultClient.wrapKey(masterKeyPath, jsonEncryptionAlgorithm, + columnEncryptionKey); return wrappedKey.result(); } /** - * Encrypt the text using specified Azure Key Vault key. + * Encrypts the text using specified Azure Key Vault key. * * @param masterKeyPath - * - Azure Key Vault key url. + * - Azure Key Vault key url. * @param encryptionAlgorithm - * - Encrypted Column Encryption Key. + * - Encrypted Column Encryption Key. * @param encryptedColumnEncryptionKey - * - Encrypted Column Encryption Key. + * - Encrypted Column Encryption Key. * @return Returns the decrypted plaintext Column Encryption Key or throws an exception if there are any errors. * @throws SQLServerException */ - private byte[] AzureKeyVaultUnWrap(String masterKeyPath, - String encryptionAlgorithm, + private byte[] AzureKeyVaultUnWrap(String masterKeyPath, String encryptionAlgorithm, byte[] encryptedColumnEncryptionKey) throws SQLServerException { if (null == encryptedColumnEncryptionKey) { throw new SQLServerException(SQLServerException.getErrString("R_EncryptedCEKNull"), null); @@ -504,7 +506,8 @@ private byte[] AzureKeyVaultUnWrap(String masterKeyPath, } JsonWebKeyEncryptionAlgorithm jsonEncryptionAlgorithm = new JsonWebKeyEncryptionAlgorithm(encryptionAlgorithm); - KeyOperationResult unwrappedKey = keyVaultClient.unwrapKey(masterKeyPath, jsonEncryptionAlgorithm, encryptedColumnEncryptionKey); + KeyOperationResult unwrappedKey = keyVaultClient.unwrapKey(masterKeyPath, jsonEncryptionAlgorithm, + encryptedColumnEncryptionKey); return unwrappedKey.result(); } @@ -513,17 +516,17 @@ private byte[] AzureKeyVaultUnWrap(String masterKeyPath, * Generates signature based on RSA PKCS#v1.5 scheme using a specified Azure Key Vault Key URL. * * @param dataToSign - * - Text to sign. + * - Text to sign. * @param masterKeyPath - * - Azure Key Vault key url. + * - Azure Key Vault key url. * @return Signature * @throws SQLServerException */ - private byte[] AzureKeyVaultSignHashedData(byte[] dataToSign, - String masterKeyPath) throws SQLServerException { + private byte[] AzureKeyVaultSignHashedData(byte[] dataToSign, String masterKeyPath) throws SQLServerException { assert ((null != dataToSign) && (0 != dataToSign.length)); - KeyOperationResult signedData = keyVaultClient.sign(masterKeyPath, JsonWebKeySignatureAlgorithm.RS256, dataToSign); + KeyOperationResult signedData = keyVaultClient.sign(masterKeyPath, JsonWebKeySignatureAlgorithm.RS256, + dataToSign); return signedData.result(); } @@ -534,29 +537,29 @@ private byte[] AzureKeyVaultSignHashedData(byte[] dataToSign, * @param dataToVerify * @param signature * @param masterKeyPath - * - Azure Key Vault key url. + * - Azure Key Vault key url. * @return true if signature is valid, false if it is not valid * @throws SQLServerException */ - private boolean AzureKeyVaultVerifySignature(byte[] dataToVerify, - byte[] signature, + private boolean AzureKeyVaultVerifySignature(byte[] dataToVerify, byte[] signature, String masterKeyPath) throws SQLServerException { assert ((null != dataToVerify) && (0 != dataToVerify.length)); assert ((null != signature) && (0 != signature.length)); - KeyVerifyResult valid = keyVaultClient.verify(masterKeyPath, JsonWebKeySignatureAlgorithm.RS256, dataToVerify, signature); + KeyVerifyResult valid = keyVaultClient.verify(masterKeyPath, JsonWebKeySignatureAlgorithm.RS256, dataToVerify, + signature); return valid.value(); } /** - * Gets the public Key size in bytes + * Returns the public Key size in bytes. * * @param masterKeyPath - * - Azure Key Vault Key path + * - Azure Key Vault Key path * @return Key size in bytes * @throws SQLServerException - * when an error occurs + * when an error occurs */ private int getAKVKeySize(String masterKeyPath) throws SQLServerException { KeyBundle retrievedKey = keyVaultClient.getKey(masterKeyPath); @@ -569,7 +572,8 @@ private int getAKVKeySize(String masterKeyPath) throws SQLServerException { throw new SQLServerException(null, form.format(msgArgs), null, 0, false); } - if (!"RSA".equalsIgnoreCase(retrievedKey.key().kty().toString()) && !"RSA-HSM".equalsIgnoreCase(retrievedKey.key().kty().toString())) { + if (!"RSA".equalsIgnoreCase(retrievedKey.key().kty().toString()) + && !"RSA-HSM".equalsIgnoreCase(retrievedKey.key().kty().toString())) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_NonRSAKey")); Object[] msgArgs = {retrievedKey.key().kty().toString()}; throw new SQLServerException(null, form.format(msgArgs), null, 0, false); diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncryptionCertificateStoreProvider.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncryptionCertificateStoreProvider.java index 5f8bc8001..1f87ecbe0 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncryptionCertificateStoreProvider.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncryptionCertificateStoreProvider.java @@ -1,246 +1,238 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.nio.file.Path; -import java.security.Key; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.UnrecoverableKeyException; -import java.security.cert.CertificateEncodingException; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.text.MessageFormat; -import java.util.Base64; -import java.util.Enumeration; -import java.util.Locale; - - -/** - * The implementation of the key store provider for the Windows Certificate Store. This class enables using keys stored in the Windows Certificate - * Store as column master keys. - * - */ -public final class SQLServerColumnEncryptionCertificateStoreProvider extends SQLServerColumnEncryptionKeyStoreProvider { - static final private java.util.logging.Logger windowsCertificateStoreLogger = java.util.logging.Logger - .getLogger("com.microsoft.sqlserver.jdbc.SQLServerColumnEncryptionCertificateStoreProvider"); - - static boolean isWindows; - - String name = "MSSQL_CERTIFICATE_STORE"; - - static final String localMachineDirectory = "LocalMachine"; - static final String currentUserDirectory = "CurrentUser"; - static final String myCertificateStore = "My"; - - static { - if (System.getProperty("os.name").toLowerCase(Locale.ENGLISH).startsWith("windows")) { - isWindows = true; - } - else { - isWindows = false; - } - } - private Path keyStoreDirectoryPath = null; - - public SQLServerColumnEncryptionCertificateStoreProvider() { - windowsCertificateStoreLogger.entering(SQLServerColumnEncryptionCertificateStoreProvider.class.getName(), - "SQLServerColumnEncryptionCertificateStoreProvider"); - } - - public void setName(String name) { - this.name = name; - } - - public String getName() { - return this.name; - } - - public byte[] encryptColumnEncryptionKey(String masterKeyPath, - String encryptionAlgorithm, - byte[] plainTextColumnEncryptionKey) throws SQLServerException { - throw new SQLServerException(null, SQLServerException.getErrString("R_InvalidWindowsCertificateStoreEncryption"), null, 0, false); - } - - private byte[] decryptColumnEncryptionKeyWindows(String masterKeyPath, - String encryptionAlgorithm, - byte[] encryptedColumnEncryptionKey) throws SQLServerException { - try { - return AuthenticationJNI.DecryptColumnEncryptionKey(masterKeyPath, encryptionAlgorithm, encryptedColumnEncryptionKey); - } - catch (DLLException e) { - DLLException.buildException(e.GetErrCode(), e.GetParam1(), e.GetParam2(), e.GetParam3()); - return null; - } - } - - private CertificateDetails getCertificateDetails(String masterKeyPath) throws SQLServerException { - String storeLocation = null; - - String[] certParts = masterKeyPath.split("/"); - - // Validate certificate path - // Certificate path should only contain 3 parts (Certificate Location, Certificate Store Name and Thumbprint) - if (certParts.length > 3) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_AECertpathBad")); - Object[] msgArgs = {masterKeyPath}; - throw new SQLServerException(form.format(msgArgs), null); - } - - // Extract the store location where the cert is stored - if (certParts.length > 2) { - if (certParts[0].equalsIgnoreCase(localMachineDirectory)) { - storeLocation = localMachineDirectory; - } - else if (certParts[0].equalsIgnoreCase(currentUserDirectory)) { - storeLocation = currentUserDirectory; - } - else { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_AECertLocBad")); - Object[] msgArgs = {certParts[0], masterKeyPath}; - throw new SQLServerException(form.format(msgArgs), null); - } - } - - // Parse the certificate store name. Only store name "My" is supported. - if (certParts.length > 1) { - if (!certParts[certParts.length - 2].equalsIgnoreCase(myCertificateStore)) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_AECertStoreBad")); - Object[] msgArgs = {certParts[certParts.length - 2], masterKeyPath}; - throw new SQLServerException(form.format(msgArgs), null); - } - } - - // Get thumpbrint - String thumbprint = certParts[certParts.length - 1]; - if ((null == thumbprint) || (0 == thumbprint.length())) { - // An empty thumbprint specified - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_AECertHashEmpty")); - Object[] msgArgs = {masterKeyPath}; - throw new SQLServerException(form.format(msgArgs), null); - } - - // Find the certificate and return - return getCertificateByThumbprint(storeLocation, thumbprint, masterKeyPath); - } - - private String getThumbPrint(X509Certificate cert) throws NoSuchAlgorithmException, CertificateEncodingException { - MessageDigest md = MessageDigest.getInstance("SHA-1"); - byte[] der = cert.getEncoded(); - md.update(der); - byte[] digest = md.digest(); - return Base64.getEncoder().encodeToString(digest); - } - - private CertificateDetails getCertificateByThumbprint(String storeLocation, - String thumbprint, - String masterKeyPath) throws SQLServerException { - FileInputStream fis; - - if ((null == keyStoreDirectoryPath)) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_AEKeyPathEmptyOrReserved")); - Object[] msgArgs = {keyStoreDirectoryPath}; - throw new SQLServerException(form.format(msgArgs), null); - } - - Path keyStoreFullPath = keyStoreDirectoryPath.resolve(storeLocation); - - KeyStore keyStore = null; - try { - keyStore = KeyStore.getInstance("PKCS12"); - } - catch (KeyStoreException e) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_CertificateError")); - Object[] msgArgs = {masterKeyPath, name}; - throw new SQLServerException(this, form.format(msgArgs), null, 0, false); - } - - File keyStoreDirectory = keyStoreFullPath.toFile(); - File[] listOfFiles = keyStoreDirectory.listFiles(); - - if ((null == listOfFiles) || (0 == listOfFiles.length)) { - throw new SQLServerException(SQLServerException.getErrString("R_KeyStoreNotFound"), null); - } - - for (File f : listOfFiles) { - - if (f.isDirectory()) { - continue; - } - - char[] password = "".toCharArray(); - try { - fis = new FileInputStream(f); - keyStore.load(fis, password); - } - catch (IOException | CertificateException | NoSuchAlgorithmException e) { - // Cannot parse the current file, continue to the next. - continue; - } - - // If we are here, we were able to load a PKCS12 file. - try { - for (Enumeration enumeration = keyStore.aliases(); enumeration.hasMoreElements();) { - - String alias = enumeration.nextElement(); - - X509Certificate publicCertificate = (X509Certificate) keyStore.getCertificate(alias); - - if (thumbprint.matches(getThumbPrint(publicCertificate))) { - // Found the right certificate - Key keyPrivate = null; - try { - keyPrivate = keyStore.getKey(alias, "".toCharArray()); - if (null == keyPrivate) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_UnrecoverableKeyAE")); - Object[] msgArgs = {masterKeyPath}; - throw new SQLServerException(this, form.format(msgArgs), null, 0, false); - } - } - catch (UnrecoverableKeyException | NoSuchAlgorithmException | KeyStoreException e) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_UnrecoverableKeyAE")); - Object[] msgArgs = {masterKeyPath}; - throw new SQLServerException(this, form.format(msgArgs), null, 0, false); - } - return new CertificateDetails(publicCertificate, keyPrivate); - } - }// end of for for alias - } - catch (CertificateException | NoSuchAlgorithmException | KeyStoreException e) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_CertificateError")); - Object[] msgArgs = {masterKeyPath, name}; - throw new SQLServerException(form.format(msgArgs), e); - } - } - // Looped over all files, haven't found the certificate - throw new SQLServerException(SQLServerException.getErrString("R_KeyStoreNotFound"), null); - } - - public byte[] decryptColumnEncryptionKey(String masterKeyPath, - String encryptionAlgorithm, - byte[] encryptedColumnEncryptionKey) throws SQLServerException { - windowsCertificateStoreLogger.entering(SQLServerColumnEncryptionCertificateStoreProvider.class.getName(), "decryptColumnEncryptionKey", - "Decrypting Column Encryption Key."); - byte[] plainCek; - if (isWindows) { - plainCek = decryptColumnEncryptionKeyWindows(masterKeyPath, encryptionAlgorithm, encryptedColumnEncryptionKey); - } - else { - throw new SQLServerException(SQLServerException.getErrString("R_notSupported"), null); - } - windowsCertificateStoreLogger.exiting(SQLServerColumnEncryptionCertificateStoreProvider.class.getName(), "decryptColumnEncryptionKey", - "Finished decrypting Column Encryption Key."); - return plainCek; - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.file.Path; +import java.security.Key; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.text.MessageFormat; +import java.util.Base64; +import java.util.Enumeration; +import java.util.Locale; + + +/** + * Provides the implementation of the key store provider for the Windows Certificate Store. This class enables using + * keys stored in the Windows Certificate Store as column master keys. + * + */ +public final class SQLServerColumnEncryptionCertificateStoreProvider extends SQLServerColumnEncryptionKeyStoreProvider { + static final private java.util.logging.Logger windowsCertificateStoreLogger = java.util.logging.Logger + .getLogger("com.microsoft.sqlserver.jdbc.SQLServerColumnEncryptionCertificateStoreProvider"); + + static boolean isWindows; + + String name = "MSSQL_CERTIFICATE_STORE"; + + static final String localMachineDirectory = "LocalMachine"; + static final String currentUserDirectory = "CurrentUser"; + static final String myCertificateStore = "My"; + + static { + if (System.getProperty("os.name").toLowerCase(Locale.ENGLISH).startsWith("windows")) { + isWindows = true; + } else { + isWindows = false; + } + } + private Path keyStoreDirectoryPath = null; + + /** + * Constructs a SQLServerColumnEncryptionCertificateStoreProvider. + */ + public SQLServerColumnEncryptionCertificateStoreProvider() { + windowsCertificateStoreLogger.entering(SQLServerColumnEncryptionCertificateStoreProvider.class.getName(), + "SQLServerColumnEncryptionCertificateStoreProvider"); + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + + public byte[] encryptColumnEncryptionKey(String masterKeyPath, String encryptionAlgorithm, + byte[] plainTextColumnEncryptionKey) throws SQLServerException { + throw new SQLServerException(null, + SQLServerException.getErrString("R_InvalidWindowsCertificateStoreEncryption"), null, 0, false); + } + + private byte[] decryptColumnEncryptionKeyWindows(String masterKeyPath, String encryptionAlgorithm, + byte[] encryptedColumnEncryptionKey) throws SQLServerException { + try { + return AuthenticationJNI.DecryptColumnEncryptionKey(masterKeyPath, encryptionAlgorithm, + encryptedColumnEncryptionKey); + } catch (DLLException e) { + DLLException.buildException(e.GetErrCode(), e.GetParam1(), e.GetParam2(), e.GetParam3()); + return null; + } + } + + private CertificateDetails getCertificateDetails(String masterKeyPath) throws SQLServerException { + String storeLocation = null; + + String[] certParts = masterKeyPath.split("/"); + + // Validate certificate path + // Certificate path should only contain 3 parts (Certificate Location, Certificate Store Name and Thumbprint) + if (certParts.length > 3) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_AECertpathBad")); + Object[] msgArgs = {masterKeyPath}; + throw new SQLServerException(form.format(msgArgs), null); + } + + // Extract the store location where the cert is stored + if (certParts.length > 2) { + if (certParts[0].equalsIgnoreCase(localMachineDirectory)) { + storeLocation = localMachineDirectory; + } else if (certParts[0].equalsIgnoreCase(currentUserDirectory)) { + storeLocation = currentUserDirectory; + } else { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_AECertLocBad")); + Object[] msgArgs = {certParts[0], masterKeyPath}; + throw new SQLServerException(form.format(msgArgs), null); + } + } + + // Parse the certificate store name. Only store name "My" is supported. + if (certParts.length > 1) { + if (!certParts[certParts.length - 2].equalsIgnoreCase(myCertificateStore)) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_AECertStoreBad")); + Object[] msgArgs = {certParts[certParts.length - 2], masterKeyPath}; + throw new SQLServerException(form.format(msgArgs), null); + } + } + + // Get thumpbrint + String thumbprint = certParts[certParts.length - 1]; + if ((null == thumbprint) || (0 == thumbprint.length())) { + // An empty thumbprint specified + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_AECertHashEmpty")); + Object[] msgArgs = {masterKeyPath}; + throw new SQLServerException(form.format(msgArgs), null); + } + + // Find the certificate and return + return getCertificateByThumbprint(storeLocation, thumbprint, masterKeyPath); + } + + private String getThumbPrint(X509Certificate cert) throws NoSuchAlgorithmException, CertificateEncodingException { + MessageDigest md = MessageDigest.getInstance("SHA-1"); + byte[] der = cert.getEncoded(); + md.update(der); + byte[] digest = md.digest(); + return Base64.getEncoder().encodeToString(digest); + } + + private CertificateDetails getCertificateByThumbprint(String storeLocation, String thumbprint, + String masterKeyPath) throws SQLServerException { + FileInputStream fis; + + if ((null == keyStoreDirectoryPath)) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_AEKeyPathEmptyOrReserved")); + Object[] msgArgs = {keyStoreDirectoryPath}; + throw new SQLServerException(form.format(msgArgs), null); + } + + Path keyStoreFullPath = keyStoreDirectoryPath.resolve(storeLocation); + + KeyStore keyStore = null; + try { + keyStore = KeyStore.getInstance("PKCS12"); + } catch (KeyStoreException e) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_CertificateError")); + Object[] msgArgs = {masterKeyPath, name}; + throw new SQLServerException(this, form.format(msgArgs), null, 0, false); + } + + File keyStoreDirectory = keyStoreFullPath.toFile(); + File[] listOfFiles = keyStoreDirectory.listFiles(); + + if ((null == listOfFiles) || (0 == listOfFiles.length)) { + throw new SQLServerException(SQLServerException.getErrString("R_KeyStoreNotFound"), null); + } + + for (File f : listOfFiles) { + + if (f.isDirectory()) { + continue; + } + + char[] password = "".toCharArray(); + try { + fis = new FileInputStream(f); + keyStore.load(fis, password); + } catch (IOException | CertificateException | NoSuchAlgorithmException e) { + // Cannot parse the current file, continue to the next. + continue; + } + + // If we are here, we were able to load a PKCS12 file. + try { + for (Enumeration enumeration = keyStore.aliases(); enumeration.hasMoreElements();) { + + String alias = enumeration.nextElement(); + + X509Certificate publicCertificate = (X509Certificate) keyStore.getCertificate(alias); + + if (thumbprint.matches(getThumbPrint(publicCertificate))) { + // Found the right certificate + Key keyPrivate = null; + try { + keyPrivate = keyStore.getKey(alias, "".toCharArray()); + if (null == keyPrivate) { + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_UnrecoverableKeyAE")); + Object[] msgArgs = {masterKeyPath}; + throw new SQLServerException(this, form.format(msgArgs), null, 0, false); + } + } catch (UnrecoverableKeyException | NoSuchAlgorithmException | KeyStoreException e) { + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_UnrecoverableKeyAE")); + Object[] msgArgs = {masterKeyPath}; + throw new SQLServerException(this, form.format(msgArgs), null, 0, false); + } + return new CertificateDetails(publicCertificate, keyPrivate); + } + } // end of for for alias + } catch (CertificateException | NoSuchAlgorithmException | KeyStoreException e) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_CertificateError")); + Object[] msgArgs = {masterKeyPath, name}; + throw new SQLServerException(form.format(msgArgs), e); + } + } + // Looped over all files, haven't found the certificate + throw new SQLServerException(SQLServerException.getErrString("R_KeyStoreNotFound"), null); + } + + public byte[] decryptColumnEncryptionKey(String masterKeyPath, String encryptionAlgorithm, + byte[] encryptedColumnEncryptionKey) throws SQLServerException { + windowsCertificateStoreLogger.entering(SQLServerColumnEncryptionCertificateStoreProvider.class.getName(), + "decryptColumnEncryptionKey", "Decrypting Column Encryption Key."); + byte[] plainCek; + if (isWindows) { + plainCek = decryptColumnEncryptionKeyWindows(masterKeyPath, encryptionAlgorithm, + encryptedColumnEncryptionKey); + } else { + throw new SQLServerException(SQLServerException.getErrString("R_notSupported"), null); + } + windowsCertificateStoreLogger.exiting(SQLServerColumnEncryptionCertificateStoreProvider.class.getName(), + "decryptColumnEncryptionKey", "Finished decrypting Column Encryption Key."); + return plainCek; + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncryptionJavaKeyStoreProvider.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncryptionJavaKeyStoreProvider.java index 4de4f19b1..b4ee6be76 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncryptionJavaKeyStoreProvider.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncryptionJavaKeyStoreProvider.java @@ -1,328 +1,321 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -import static java.nio.charset.StandardCharsets.UTF_16LE; - -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.security.InvalidKeyException; -import java.security.Key; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.Signature; -import java.security.SignatureException; -import java.security.UnrecoverableKeyException; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.text.MessageFormat; - -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; - -/** - * - * The implementation of the key store provider for Java Key Store. This class enables using certificates stored in the Java keystore as column master - * keys. - * - */ -public class SQLServerColumnEncryptionJavaKeyStoreProvider extends SQLServerColumnEncryptionKeyStoreProvider { - String name = "MSSQL_JAVA_KEYSTORE"; - String keyStorePath = null; - char[] keyStorePwd = null; - - static final private java.util.logging.Logger javaKeyStoreLogger = java.util.logging.Logger - .getLogger("com.microsoft.sqlserver.jdbc.SQLServerColumnEncryptionJavaKeyStoreProvider"); - - public void setName(String name) { - this.name = name; - } - - public String getName() { - return this.name; - } - - /** - * Key store provider for the Java Key Store. - * - * @param keyStoreLocation - * specifies the location of the keystore - * @param keyStoreSecret - * specifies the secret used for keystore - * @throws SQLServerException - * when an error occurs - */ - public SQLServerColumnEncryptionJavaKeyStoreProvider(String keyStoreLocation, - char[] keyStoreSecret) throws SQLServerException { - javaKeyStoreLogger.entering(SQLServerColumnEncryptionJavaKeyStoreProvider.class.getName(), "SQLServerColumnEncryptionJavaKeyStoreProvider"); - - if ((null == keyStoreLocation) || (0 == keyStoreLocation.length())) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidConnectionSetting")); - Object[] msgArgs = {"keyStoreLocation", keyStoreLocation}; - throw new SQLServerException(form.format(msgArgs), null); - } - - this.keyStorePath = keyStoreLocation; - - if (javaKeyStoreLogger.isLoggable(java.util.logging.Level.FINE)) { - javaKeyStoreLogger.fine("Path of key store provider is set."); - } - - // Password can be null or empty, PKCS12 type allows that. - if (null == keyStoreSecret) { - keyStoreSecret = "".toCharArray(); - } - - this.keyStorePwd = new char[keyStoreSecret.length]; - System.arraycopy(keyStoreSecret, 0, this.keyStorePwd, 0, keyStoreSecret.length); - - if (javaKeyStoreLogger.isLoggable(java.util.logging.Level.FINE)) { - javaKeyStoreLogger.fine("Password for key store provider is set."); - } - - javaKeyStoreLogger.exiting(SQLServerColumnEncryptionJavaKeyStoreProvider.class.getName(), "SQLServerColumnEncryptionJavaKeyStoreProvider"); - } - - @Override - public byte[] decryptColumnEncryptionKey(String masterKeyPath, - String encryptionAlgorithm, - byte[] encryptedColumnEncryptionKey) throws SQLServerException { - javaKeyStoreLogger.entering(SQLServerColumnEncryptionJavaKeyStoreProvider.class.getName(), "decryptColumnEncryptionKey", - "Decrypting Column Encryption Key."); - - KeyStoreProviderCommon.validateNonEmptyMasterKeyPath(masterKeyPath); - CertificateDetails certificateDetails = getCertificateDetails(masterKeyPath); - byte[] plainCEK = KeyStoreProviderCommon.decryptColumnEncryptionKey(masterKeyPath, encryptionAlgorithm, encryptedColumnEncryptionKey, - certificateDetails); - - javaKeyStoreLogger.exiting(SQLServerColumnEncryptionJavaKeyStoreProvider.class.getName(), "decryptColumnEncryptionKey", - "Finished decrypting Column Encryption Key."); - return plainCEK; - } - - private CertificateDetails getCertificateDetails(String masterKeyPath) throws SQLServerException { - FileInputStream fis = null; - KeyStore keyStore = null; - CertificateDetails certificateDetails = null; - - try { - if (null == masterKeyPath || 0 == masterKeyPath.length()) { - throw new SQLServerException(null, SQLServerException.getErrString("R_InvalidMasterKeyDetails"), null, 0, false); - } - - try { - // Try to load JKS first, if fails try PKCS12 - keyStore = KeyStore.getInstance("JKS"); - fis = new FileInputStream(keyStorePath); - keyStore.load(fis, keyStorePwd); - } - catch (IOException e) { - if (null != fis) - fis.close(); - - // Loading as JKS failed, try to load as PKCS12 - keyStore = KeyStore.getInstance("PKCS12"); - fis = new FileInputStream(keyStorePath); - keyStore.load(fis, keyStorePwd); - } - - certificateDetails = getCertificateDetailsByAlias(keyStore, masterKeyPath); - } - catch (FileNotFoundException fileNotFound) { - throw new SQLServerException(this, SQLServerException.getErrString("R_KeyStoreNotFound"), null, 0, false); - } - catch (IOException | CertificateException | NoSuchAlgorithmException | KeyStoreException e) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidKeyStoreFile")); - Object[] msgArgs = {keyStorePath}; - throw new SQLServerException(form.format(msgArgs), e); - } - finally { - try { - if (null != fis) - fis.close(); - } - // Ignore the exception as we are cleaning up. - catch (IOException e) { - } - } - - return certificateDetails; - } - - private CertificateDetails getCertificateDetailsByAlias(KeyStore keyStore, - String alias) throws SQLServerException { - try { - X509Certificate publicCertificate = (X509Certificate) keyStore.getCertificate(alias); - Key keyPrivate = keyStore.getKey(alias, keyStorePwd); - if (null == publicCertificate) { - // Certificate not found. Throw an exception. - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_CertificateNotFoundForAlias")); - Object[] msgArgs = {alias, "MSSQL_JAVA_KEYSTORE"}; - throw new SQLServerException(this, form.format(msgArgs), null, 0, false); - } - - // found certificate but corresponding private key not found, throw exception - if (null == keyPrivate) { - throw new UnrecoverableKeyException(); - } - - return new CertificateDetails(publicCertificate, keyPrivate); - } - catch (UnrecoverableKeyException unrecoverableKeyException) { - - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_UnrecoverableKeyAE")); - Object[] msgArgs = {alias}; - throw new SQLServerException(this, form.format(msgArgs), null, 0, false); - } - catch (NoSuchAlgorithmException | KeyStoreException e) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_CertificateError")); - Object[] msgArgs = {alias, name}; - throw new SQLServerException(form.format(msgArgs), e); - } - } - - @Override - public byte[] encryptColumnEncryptionKey(String masterKeyPath, - String encryptionAlgorithm, - byte[] plainTextColumnEncryptionKey) throws SQLServerException { - javaKeyStoreLogger.entering(SQLServerColumnEncryptionJavaKeyStoreProvider.class.getName(), - Thread.currentThread().getStackTrace()[1].getMethodName(), "Encrypting Column Encryption Key."); - - byte[] version = KeyStoreProviderCommon.version; - KeyStoreProviderCommon.validateNonEmptyMasterKeyPath(masterKeyPath); - - if (null == plainTextColumnEncryptionKey) { - - throw new SQLServerException(null, SQLServerException.getErrString("R_NullColumnEncryptionKey"), null, 0, false); - - } - else if (0 == plainTextColumnEncryptionKey.length) { - - throw new SQLServerException(null, SQLServerException.getErrString("R_EmptyColumnEncryptionKey"), null, 0, false); - - } - - KeyStoreProviderCommon.validateEncryptionAlgorithm(encryptionAlgorithm, true); - - CertificateDetails certificateDetails = getCertificateDetails(masterKeyPath); - byte[] cipherText = encryptRSAOAEP(plainTextColumnEncryptionKey, certificateDetails); - byte[] cipherTextLength = getLittleEndianBytesFromShort((short) cipherText.length); - byte[] masterKeyPathBytes = masterKeyPath.toLowerCase().getBytes(UTF_16LE); - - byte[] keyPathLength = getLittleEndianBytesFromShort((short) masterKeyPathBytes.length); - - byte[] dataToSign = new byte[version.length + keyPathLength.length + cipherTextLength.length + masterKeyPathBytes.length + cipherText.length]; - int destinationPosition = version.length; - System.arraycopy(version, 0, dataToSign, 0, version.length); - - System.arraycopy(keyPathLength, 0, dataToSign, destinationPosition, keyPathLength.length); - destinationPosition += keyPathLength.length; - - System.arraycopy(cipherTextLength, 0, dataToSign, destinationPosition, cipherTextLength.length); - destinationPosition += cipherTextLength.length; - - System.arraycopy(masterKeyPathBytes, 0, dataToSign, destinationPosition, masterKeyPathBytes.length); - destinationPosition += masterKeyPathBytes.length; - - System.arraycopy(cipherText, 0, dataToSign, destinationPosition, cipherText.length); - byte[] signedHash = rsaSignHashedData(dataToSign, certificateDetails); - - int encryptedColumnEncryptionKeyLength = version.length + cipherTextLength.length + keyPathLength.length + cipherText.length - + masterKeyPathBytes.length + signedHash.length; - byte[] encryptedColumnEncryptionKey = new byte[encryptedColumnEncryptionKeyLength]; - - int currentIndex = 0; - System.arraycopy(version, 0, encryptedColumnEncryptionKey, currentIndex, version.length); - currentIndex += version.length; - - System.arraycopy(keyPathLength, 0, encryptedColumnEncryptionKey, currentIndex, keyPathLength.length); - currentIndex += keyPathLength.length; - - System.arraycopy(cipherTextLength, 0, encryptedColumnEncryptionKey, currentIndex, cipherTextLength.length); - currentIndex += cipherTextLength.length; - - System.arraycopy(masterKeyPathBytes, 0, encryptedColumnEncryptionKey, currentIndex, masterKeyPathBytes.length); - currentIndex += masterKeyPathBytes.length; - - System.arraycopy(cipherText, 0, encryptedColumnEncryptionKey, currentIndex, cipherText.length); - currentIndex += cipherText.length; - - System.arraycopy(signedHash, 0, encryptedColumnEncryptionKey, currentIndex, signedHash.length); - - javaKeyStoreLogger.exiting(SQLServerColumnEncryptionJavaKeyStoreProvider.class.getName(), - Thread.currentThread().getStackTrace()[1].getMethodName(), "Finished encrypting Column Encryption Key."); - return encryptedColumnEncryptionKey; - - } - - /** - * Encrypt plainText with the certificate provided - * - * @param plainText - * plain CEK to be encrypted - * @param certificateDetails - * @return encrypted CEK - * @throws SQLServerException - */ - private byte[] encryptRSAOAEP(byte[] plainText, - CertificateDetails certificateDetails) throws SQLServerException { - byte[] cipherText = null; - try { - Cipher rsa = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding"); - rsa.init(Cipher.ENCRYPT_MODE, certificateDetails.certificate.getPublicKey()); - rsa.update(plainText); - cipherText = rsa.doFinal(); - } - catch (InvalidKeyException | NoSuchAlgorithmException | IllegalBlockSizeException | NoSuchPaddingException | BadPaddingException e) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_EncryptionFailed")); - Object[] msgArgs = {e.getMessage()}; - throw new SQLServerException(this, form.format(msgArgs), null, 0, false); - } - - return cipherText; - - } - - private byte[] rsaSignHashedData(byte[] dataToSign, - CertificateDetails certificateDetails) throws SQLServerException { - Signature signature; - byte[] signedHash = null; - - try { - signature = Signature.getInstance("SHA256withRSA"); - signature.initSign((PrivateKey) certificateDetails.privateKey); - signature.update(dataToSign); - signedHash = signature.sign(); - } - catch (InvalidKeyException | NoSuchAlgorithmException | SignatureException e) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_EncryptionFailed")); - Object[] msgArgs = {e.getMessage()}; - throw new SQLServerException(this, form.format(msgArgs), null, 0, false); - - } - return signedHash; - - } - - private byte[] getLittleEndianBytesFromShort(short value) { - ByteBuffer byteBuffer = ByteBuffer.allocate(2); - byteBuffer.order(ByteOrder.LITTLE_ENDIAN); - byte[] byteValue = byteBuffer.putShort(value).array(); - return byteValue; - - } - -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +import static java.nio.charset.StandardCharsets.UTF_16LE; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.text.MessageFormat; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; + + +/** + * + * Provides the implementation of the key store provider for Java Key Store. This class enables using certificates + * stored in the Java keystore as column master keys. + * + */ +public class SQLServerColumnEncryptionJavaKeyStoreProvider extends SQLServerColumnEncryptionKeyStoreProvider { + String name = "MSSQL_JAVA_KEYSTORE"; + String keyStorePath = null; + char[] keyStorePwd = null; + + static final private java.util.logging.Logger javaKeyStoreLogger = java.util.logging.Logger + .getLogger("com.microsoft.sqlserver.jdbc.SQLServerColumnEncryptionJavaKeyStoreProvider"); + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return this.name; + } + + /** + * Constructs a SQLServerColumnEncryptionJavaKeyStoreProvider for the Java Key Store. + * + * @param keyStoreLocation + * specifies the location of the keystore + * @param keyStoreSecret + * specifies the secret used for keystore + * @throws SQLServerException + * when an error occurs + */ + public SQLServerColumnEncryptionJavaKeyStoreProvider(String keyStoreLocation, + char[] keyStoreSecret) throws SQLServerException { + javaKeyStoreLogger.entering(SQLServerColumnEncryptionJavaKeyStoreProvider.class.getName(), + "SQLServerColumnEncryptionJavaKeyStoreProvider"); + + if ((null == keyStoreLocation) || (0 == keyStoreLocation.length())) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidConnectionSetting")); + Object[] msgArgs = {"keyStoreLocation", keyStoreLocation}; + throw new SQLServerException(form.format(msgArgs), null); + } + + this.keyStorePath = keyStoreLocation; + + if (javaKeyStoreLogger.isLoggable(java.util.logging.Level.FINE)) { + javaKeyStoreLogger.fine("Path of key store provider is set."); + } + + // Password can be null or empty, PKCS12 type allows that. + if (null == keyStoreSecret) { + keyStoreSecret = "".toCharArray(); + } + + this.keyStorePwd = new char[keyStoreSecret.length]; + System.arraycopy(keyStoreSecret, 0, this.keyStorePwd, 0, keyStoreSecret.length); + + if (javaKeyStoreLogger.isLoggable(java.util.logging.Level.FINE)) { + javaKeyStoreLogger.fine("Password for key store provider is set."); + } + + javaKeyStoreLogger.exiting(SQLServerColumnEncryptionJavaKeyStoreProvider.class.getName(), + "SQLServerColumnEncryptionJavaKeyStoreProvider"); + } + + @Override + public byte[] decryptColumnEncryptionKey(String masterKeyPath, String encryptionAlgorithm, + byte[] encryptedColumnEncryptionKey) throws SQLServerException { + javaKeyStoreLogger.entering(SQLServerColumnEncryptionJavaKeyStoreProvider.class.getName(), + "decryptColumnEncryptionKey", "Decrypting Column Encryption Key."); + + KeyStoreProviderCommon.validateNonEmptyMasterKeyPath(masterKeyPath); + CertificateDetails certificateDetails = getCertificateDetails(masterKeyPath); + byte[] plainCEK = KeyStoreProviderCommon.decryptColumnEncryptionKey(masterKeyPath, encryptionAlgorithm, + encryptedColumnEncryptionKey, certificateDetails); + + javaKeyStoreLogger.exiting(SQLServerColumnEncryptionJavaKeyStoreProvider.class.getName(), + "decryptColumnEncryptionKey", "Finished decrypting Column Encryption Key."); + return plainCEK; + } + + private CertificateDetails getCertificateDetails(String masterKeyPath) throws SQLServerException { + FileInputStream fis = null; + KeyStore keyStore = null; + CertificateDetails certificateDetails = null; + + try { + if (null == masterKeyPath || 0 == masterKeyPath.length()) { + throw new SQLServerException(null, SQLServerException.getErrString("R_InvalidMasterKeyDetails"), null, + 0, false); + } + + try { + // Try to load JKS first, if fails try PKCS12 + keyStore = KeyStore.getInstance("JKS"); + fis = new FileInputStream(keyStorePath); + keyStore.load(fis, keyStorePwd); + } catch (IOException e) { + if (null != fis) + fis.close(); + + // Loading as JKS failed, try to load as PKCS12 + keyStore = KeyStore.getInstance("PKCS12"); + fis = new FileInputStream(keyStorePath); + keyStore.load(fis, keyStorePwd); + } + + certificateDetails = getCertificateDetailsByAlias(keyStore, masterKeyPath); + } catch (FileNotFoundException fileNotFound) { + throw new SQLServerException(this, SQLServerException.getErrString("R_KeyStoreNotFound"), null, 0, false); + } catch (IOException | CertificateException | NoSuchAlgorithmException | KeyStoreException e) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidKeyStoreFile")); + Object[] msgArgs = {keyStorePath}; + throw new SQLServerException(form.format(msgArgs), e); + } finally { + try { + if (null != fis) + fis.close(); + } + // Ignore the exception as we are cleaning up. + catch (IOException e) {} + } + + return certificateDetails; + } + + private CertificateDetails getCertificateDetailsByAlias(KeyStore keyStore, String alias) throws SQLServerException { + try { + X509Certificate publicCertificate = (X509Certificate) keyStore.getCertificate(alias); + Key keyPrivate = keyStore.getKey(alias, keyStorePwd); + if (null == publicCertificate) { + // Certificate not found. Throw an exception. + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_CertificateNotFoundForAlias")); + Object[] msgArgs = {alias, "MSSQL_JAVA_KEYSTORE"}; + throw new SQLServerException(this, form.format(msgArgs), null, 0, false); + } + + // found certificate but corresponding private key not found, throw exception + if (null == keyPrivate) { + throw new UnrecoverableKeyException(); + } + + return new CertificateDetails(publicCertificate, keyPrivate); + } catch (UnrecoverableKeyException unrecoverableKeyException) { + + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_UnrecoverableKeyAE")); + Object[] msgArgs = {alias}; + throw new SQLServerException(this, form.format(msgArgs), null, 0, false); + } catch (NoSuchAlgorithmException | KeyStoreException e) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_CertificateError")); + Object[] msgArgs = {alias, name}; + throw new SQLServerException(form.format(msgArgs), e); + } + } + + @Override + public byte[] encryptColumnEncryptionKey(String masterKeyPath, String encryptionAlgorithm, + byte[] plainTextColumnEncryptionKey) throws SQLServerException { + javaKeyStoreLogger.entering(SQLServerColumnEncryptionJavaKeyStoreProvider.class.getName(), + Thread.currentThread().getStackTrace()[1].getMethodName(), "Encrypting Column Encryption Key."); + + byte[] version = KeyStoreProviderCommon.version; + KeyStoreProviderCommon.validateNonEmptyMasterKeyPath(masterKeyPath); + + if (null == plainTextColumnEncryptionKey) { + + throw new SQLServerException(null, SQLServerException.getErrString("R_NullColumnEncryptionKey"), null, 0, + false); + + } else if (0 == plainTextColumnEncryptionKey.length) { + + throw new SQLServerException(null, SQLServerException.getErrString("R_EmptyColumnEncryptionKey"), null, 0, + false); + + } + + KeyStoreProviderCommon.validateEncryptionAlgorithm(encryptionAlgorithm, true); + + CertificateDetails certificateDetails = getCertificateDetails(masterKeyPath); + byte[] cipherText = encryptRSAOAEP(plainTextColumnEncryptionKey, certificateDetails); + byte[] cipherTextLength = getLittleEndianBytesFromShort((short) cipherText.length); + byte[] masterKeyPathBytes = masterKeyPath.toLowerCase().getBytes(UTF_16LE); + + byte[] keyPathLength = getLittleEndianBytesFromShort((short) masterKeyPathBytes.length); + + byte[] dataToSign = new byte[version.length + keyPathLength.length + cipherTextLength.length + + masterKeyPathBytes.length + cipherText.length]; + int destinationPosition = version.length; + System.arraycopy(version, 0, dataToSign, 0, version.length); + + System.arraycopy(keyPathLength, 0, dataToSign, destinationPosition, keyPathLength.length); + destinationPosition += keyPathLength.length; + + System.arraycopy(cipherTextLength, 0, dataToSign, destinationPosition, cipherTextLength.length); + destinationPosition += cipherTextLength.length; + + System.arraycopy(masterKeyPathBytes, 0, dataToSign, destinationPosition, masterKeyPathBytes.length); + destinationPosition += masterKeyPathBytes.length; + + System.arraycopy(cipherText, 0, dataToSign, destinationPosition, cipherText.length); + byte[] signedHash = rsaSignHashedData(dataToSign, certificateDetails); + + int encryptedColumnEncryptionKeyLength = version.length + cipherTextLength.length + keyPathLength.length + + cipherText.length + masterKeyPathBytes.length + signedHash.length; + byte[] encryptedColumnEncryptionKey = new byte[encryptedColumnEncryptionKeyLength]; + + int currentIndex = 0; + System.arraycopy(version, 0, encryptedColumnEncryptionKey, currentIndex, version.length); + currentIndex += version.length; + + System.arraycopy(keyPathLength, 0, encryptedColumnEncryptionKey, currentIndex, keyPathLength.length); + currentIndex += keyPathLength.length; + + System.arraycopy(cipherTextLength, 0, encryptedColumnEncryptionKey, currentIndex, cipherTextLength.length); + currentIndex += cipherTextLength.length; + + System.arraycopy(masterKeyPathBytes, 0, encryptedColumnEncryptionKey, currentIndex, masterKeyPathBytes.length); + currentIndex += masterKeyPathBytes.length; + + System.arraycopy(cipherText, 0, encryptedColumnEncryptionKey, currentIndex, cipherText.length); + currentIndex += cipherText.length; + + System.arraycopy(signedHash, 0, encryptedColumnEncryptionKey, currentIndex, signedHash.length); + + javaKeyStoreLogger.exiting(SQLServerColumnEncryptionJavaKeyStoreProvider.class.getName(), + Thread.currentThread().getStackTrace()[1].getMethodName(), + "Finished encrypting Column Encryption Key."); + return encryptedColumnEncryptionKey; + + } + + /** + * Encrypt plainText with the certificate provided. + * + * @param plainText + * plain CEK to be encrypted + * @param certificateDetails + * @return encrypted CEK + * @throws SQLServerException + */ + private byte[] encryptRSAOAEP(byte[] plainText, CertificateDetails certificateDetails) throws SQLServerException { + byte[] cipherText = null; + try { + Cipher rsa = Cipher.getInstance("RSA/ECB/OAEPWithSHA-1AndMGF1Padding"); + rsa.init(Cipher.ENCRYPT_MODE, certificateDetails.certificate.getPublicKey()); + rsa.update(plainText); + cipherText = rsa.doFinal(); + } catch (InvalidKeyException | NoSuchAlgorithmException | IllegalBlockSizeException | NoSuchPaddingException + | BadPaddingException e) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_EncryptionFailed")); + Object[] msgArgs = {e.getMessage()}; + throw new SQLServerException(this, form.format(msgArgs), null, 0, false); + } + + return cipherText; + + } + + private byte[] rsaSignHashedData(byte[] dataToSign, + CertificateDetails certificateDetails) throws SQLServerException { + Signature signature; + byte[] signedHash = null; + + try { + signature = Signature.getInstance("SHA256withRSA"); + signature.initSign((PrivateKey) certificateDetails.privateKey); + signature.update(dataToSign); + signedHash = signature.sign(); + } catch (InvalidKeyException | NoSuchAlgorithmException | SignatureException e) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_EncryptionFailed")); + Object[] msgArgs = {e.getMessage()}; + throw new SQLServerException(this, form.format(msgArgs), null, 0, false); + + } + return signedHash; + + } + + private byte[] getLittleEndianBytesFromShort(short value) { + ByteBuffer byteBuffer = ByteBuffer.allocate(2); + byteBuffer.order(ByteOrder.LITTLE_ENDIAN); + byte[] byteValue = byteBuffer.putShort(value).array(); + return byteValue; + + } + +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncryptionKeyStoreProvider.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncryptionKeyStoreProvider.java index 705f9d3bc..6fd8b845f 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncryptionKeyStoreProvider.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncryptionKeyStoreProvider.java @@ -1,69 +1,65 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -/** - * - * Extend this class to implement a custom key store provider. - * - */ -public abstract class SQLServerColumnEncryptionKeyStoreProvider { - - /** - * Sets the name of this key store provider. - * - * @param name - * value to be set for the key store provider. - */ - public abstract void setName(String name); - - /** - * Retrieves the name of this key store provider. - * - * @return the name of this key store provider. - */ - public abstract String getName(); - - /** - * Base class method for decrypting the specified encrypted value of a column encryption key. The encrypted value is expected to be encrypted - * using the column master key with the specified key path and using the specified algorithm. - * - * @param masterKeyPath - * The column master key path. - * @param encryptionAlgorithm - * the specific encryption algorithm. - * @param encryptedColumnEncryptionKey - * the encrypted column encryption key - * @return the decrypted value of column encryption key. - * @throws SQLServerException - * when an error occurs while decrypting the CEK - */ - public abstract byte[] decryptColumnEncryptionKey(String masterKeyPath, - String encryptionAlgorithm, - byte[] encryptedColumnEncryptionKey) throws SQLServerException; - - /** - * Base class method for encrypting a column encryption key using the column master key with the specified key path and using the specified - * algorithm. - * - * @param masterKeyPath - * The column master key path. - * @param encryptionAlgorithm - * the specific encryption algorithm. - * @param columnEncryptionKey - * column encryption key to be encrypted. - * @return the encrypted column encryption key. - * @throws SQLServerException - * when an error occurs while encrypting the CEK - */ - public abstract byte[] encryptColumnEncryptionKey(String masterKeyPath, - String encryptionAlgorithm, - byte[] columnEncryptionKey) throws SQLServerException; - -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +/** + * + * Defines the abtract class for a SQL Server Column Encryption key store provider Extend this class to implement a + * custom key store provider. + * + */ +public abstract class SQLServerColumnEncryptionKeyStoreProvider { + + /** + * Sets the name of this key store provider. + * + * @param name + * value to be set for the key store provider. + */ + public abstract void setName(String name); + + /** + * Returns the name of this key store provider. + * + * @return the name of this key store provider. + */ + public abstract String getName(); + + /** + * Decrypts the specified encrypted value of a column encryption key. The encrypted value is expected to be + * encrypted using the column master key with the specified key path and using the specified algorithm. + * + * @param masterKeyPath + * The column master key path. + * @param encryptionAlgorithm + * the specific encryption algorithm. + * @param encryptedColumnEncryptionKey + * the encrypted column encryption key + * @return the decrypted value of column encryption key. + * @throws SQLServerException + * when an error occurs while decrypting the CEK + */ + public abstract byte[] decryptColumnEncryptionKey(String masterKeyPath, String encryptionAlgorithm, + byte[] encryptedColumnEncryptionKey) throws SQLServerException; + + /** + * Encrypts a column encryption key using the column master key with the specified key path and using the specified + * algorithm. + * + * @param masterKeyPath + * The column master key path. + * @param encryptionAlgorithm + * the specific encryption algorithm. + * @param columnEncryptionKey + * column encryption key to be encrypted. + * @return the encrypted column encryption key. + * @throws SQLServerException + * when an error occurs while encrypting the CEK + */ + public abstract byte[] encryptColumnEncryptionKey(String masterKeyPath, String encryptionAlgorithm, + byte[] columnEncryptionKey) throws SQLServerException; + +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java index 0c4b2bef9..18142be1d 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -47,59 +44,67 @@ import javax.sql.XAConnection; import org.ietf.jgss.GSSCredential; + +import mssql.googlecode.cityhash.CityHash; import mssql.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap; import mssql.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap.Builder; import mssql.googlecode.concurrentlinkedhashmap.EvictionListener; + /** - * SQLServerConnection implements a JDBC connection to SQL Server. SQLServerConnections support JDBC connection pooling and may be either physical - * JDBC connections or logical JDBC connections. + * Provides an implementation java.sql.connection interface that assists creating a JDBC connection to SQL Server. + * SQLServerConnections support JDBC connection pooling and may be either physical JDBC connections or logical JDBC + * connections. *

- * SQLServerConnection manages transaction control for all statements that were created from it. SQLServerConnection may participate in XA distributed - * transactions managed via an XAResource adapter. + * SQLServerConnection manages transaction control for all statements that were created from it. SQLServerConnection may + * participate in XA distributed transactions managed via an XAResource adapter. *

- * SQLServerConnection instantiates a new TDSChannel object for use by itself and all statement objects that are created under this connection. - * SQLServerConnection is thread safe. + * SQLServerConnection instantiates a new TDSChannel object for use by itself and all statement objects that are created + * under this connection. SQLServerConnection is thread safe. *

- * SQLServerConnection manages a pool of prepared statement handles. Prepared statements are prepared once and typically executed many times with - * different data values for their parameters. Prepared statements are also maintained across logical (pooled) connection closes. + * SQLServerConnection manages a pool of prepared statement handles. Prepared statements are prepared once and typically + * executed many times with different data values for their parameters. Prepared statements are also maintained across + * logical (pooled) connection closes. *

- * SQLServerConnection is not thread safe, however multiple statements created from a single connection can be processing simultaneously in concurrent - * threads. + * SQLServerConnection is not thread safe, however multiple statements created from a single connection can be + * processing simultaneously in concurrent threads. *

* This class's public functions need to be kept identical to the SQLServerConnectionPoolProxy's. *

- * The API javadoc for JDBC API methods that this class implements are not repeated here. Please see Sun's JDBC API interfaces javadoc for those - * details. + * The API javadoc for JDBC API methods that this class implements are not repeated here. Please see Sun's JDBC API + * interfaces javadoc for those details. + * + * NOTE: All the public functions in this class also need to be defined in SQLServerConnectionPoolProxy Declare all new + * custom (non-static) Public APIs in ISQLServerConnection interface such that they can also be implemented by + * SQLServerConnectionPoolProxy */ - -// NOTE: All the public functions in this class also need to be defined in SQLServerConnectionPoolProxy -// Declare all new custom (non-static) Public APIs in ISQLServerConnection interface such that they can also be implemented by -// SQLServerConnectionPoolProxy public class SQLServerConnection implements ISQLServerConnection, java.io.Serializable { /** - * Always refresh SerialVersionUID when prompted - */ - private static final long serialVersionUID = 1965647556064751510L; - - long timerExpire; + * Always refresh SerialVersionUID when prompted + */ + private static final long serialVersionUID = 1965647556064751510L; + + long timerExpire; boolean attemptRefreshTokenLocked = false; // Thresholds related to when prepared statement handles are cleaned-up. 1 == immediately. /** * The default for the prepared statement clean-up action threshold (i.e. when sp_unprepare is called). */ - static final int DEFAULT_SERVER_PREPARED_STATEMENT_DISCARD_THRESHOLD = 10; // Used to set the initial default, can be changed later. + static final int DEFAULT_SERVER_PREPARED_STATEMENT_DISCARD_THRESHOLD = 10; // Used to set the initial default, can + // be changed later. private int serverPreparedStatementDiscardThreshold = -1; // Current limit for this particular connection. /** - * The default for if prepared statements should execute sp_executesql before following the prepare, unprepare pattern. + * The default for if prepared statements should execute sp_executesql before following the prepare, unprepare + * pattern. + * + * Used to set the initial default, can be changed later. false == use sp_executesql -> sp_prepexec -> sp_execute -> + * batched -> sp_unprepare pattern, true == skip sp_executesql part of pattern. */ - static final boolean DEFAULT_ENABLE_PREPARE_ON_FIRST_PREPARED_STATEMENT_CALL = false; // Used to set the initial default, can be changed later. - // false == use sp_executesql -> sp_prepexec -> sp_execute - // -> batched -> sp_unprepare pattern, true == skip - // sp_executesql part of pattern. + static final boolean DEFAULT_ENABLE_PREPARE_ON_FIRST_PREPARED_STATEMENT_CALL = false; + private Boolean enablePrepareOnFirstPreparedStatementCall = null; // Current limit for this particular connection. // Handle the actual queue of discarded prepared statements. @@ -109,7 +114,9 @@ public class SQLServerConnection implements ISQLServerConnection, java.io.Serial private boolean fedAuthRequiredByUser = false; private boolean fedAuthRequiredPreLoginResponse = false; private boolean federatedAuthenticationRequested = false; - private boolean federatedAuthenticationInfoRequested = false; // Keep this distinct from _federatedAuthenticationRequested, since some fedauth + private boolean federatedAuthenticationInfoRequested = false; // Keep this distinct from + // _federatedAuthenticationRequested, since some + // fedauth // library types may not need more info private FederatedAuthenticationFeatureExtensionData fedAuthFeatureExtensionData = null; @@ -119,50 +126,50 @@ public class SQLServerConnection implements ISQLServerConnection, java.io.Serial private SqlFedAuthToken fedAuthToken = null; private String originalHostNameInCertificate = null; - + private Boolean isAzureDW = null; - static class Sha1HashKey implements java.io.Serializable { + static class CityHash128Key implements java.io.Serializable { /** * Always refresh SerialVersionUID when prompted */ private static final long serialVersionUID = 166788428640603097L; - private byte[] bytes; + String unhashedString; + private long[] segments; + private int hashCode; - Sha1HashKey(String sql, - String parametersDefinition) { - this(String.format("%s%s", sql, parametersDefinition)); + CityHash128Key(String sql, String parametersDefinition) { + this(sql + parametersDefinition); } - Sha1HashKey(String s) { - bytes = getSha1Digest().digest(s.getBytes()); + @SuppressWarnings("deprecation") + CityHash128Key(String s) { + unhashedString = s; + byte[] bytes = new byte[s.length()]; + s.getBytes(0, s.length(), bytes, 0); + segments = CityHash.cityHash128(bytes, 0, bytes.length); } public boolean equals(Object obj) { - if (!(obj instanceof Sha1HashKey)) + if (!(obj instanceof CityHash128Key)) return false; - return java.util.Arrays.equals(bytes, ((Sha1HashKey) obj).bytes); + return (java.util.Arrays.equals(segments, ((CityHash128Key) obj).segments)// checks if hash is equal, + // short-circuitting; + && this.unhashedString.equals(((CityHash128Key) obj).unhashedString));// checks if string is equal } public int hashCode() { - return java.util.Arrays.hashCode(bytes); - } - - private java.security.MessageDigest getSha1Digest() { - try { - return java.security.MessageDigest.getInstance("SHA-1"); - } - catch (final java.security.NoSuchAlgorithmException e) { - // This is not theoretically possible, but we're forced to catch it anyway - throw new RuntimeException(e); + if (0 == hashCode) { + hashCode = java.util.Arrays.hashCode(segments); } + return hashCode; } } /** - * Used to keep track of an individual prepared statement handle. + * Keeps track of an individual prepared statement handle. */ class PreparedStatementHandle { private int handle = 0; @@ -170,12 +177,9 @@ class PreparedStatementHandle { private boolean isDirectSql; private volatile boolean evictedFromCache; private volatile boolean explicitlyDiscarded; - private Sha1HashKey key; + private CityHash128Key key; - PreparedStatementHandle(Sha1HashKey key, - int handle, - boolean isDirectSql, - boolean isEvictedFromCache) { + PreparedStatementHandle(CityHash128Key key, int handle, boolean isDirectSql, boolean isEvictedFromCache) { this.key = key; this.handle = handle; this.isDirectSql = isDirectSql; @@ -205,13 +209,13 @@ private boolean isExplicitlyDiscarded() { return explicitlyDiscarded; } - /** Get the actual handle. */ + /** Returns the actual handle. */ int getHandle() { return handle; } - /** Get the cache key. */ - Sha1HashKey getKey() { + /** Returns the cache key. */ + CityHash128Key getKey() { return key; } @@ -220,9 +224,10 @@ boolean isDirectSql() { } /** - * Make sure handle cannot be re-used. + * Makes sure handle cannot be re-used. * - * @return false: Handle could not be discarded, it is in use. true: Handle was successfully put on path for discarding. + * @return false: Handle could not be discarded, it is in use. true: Handle was successfully put on path for + * discarding. */ private boolean tryDiscardHandle() { return handleRefCount.compareAndSet(0, -999); @@ -236,8 +241,8 @@ private boolean isDiscarded() { /** * Adds a new reference to this handle, i.e. re-using it. * - * @return false: Reference could not be added, statement has been discarded or does not have a handle associated with it. true: Reference was - * successfully added. + * @return false: Reference could not be added, statement has been discarded or does not have a handle + * associated with it. true: Reference was successfully added. */ boolean tryAddReference() { if (isDiscarded() || isExplicitlyDiscarded()) @@ -258,28 +263,29 @@ void removeReference() { static final private int PARSED_SQL_CACHE_SIZE = 100; /** Cache of parsed SQL meta data */ - static private ConcurrentLinkedHashMap parsedSQLCache; + static private ConcurrentLinkedHashMap parsedSQLCache; static { - parsedSQLCache = new Builder().maximumWeightedCapacity(PARSED_SQL_CACHE_SIZE).build(); + parsedSQLCache = new Builder() + .maximumWeightedCapacity(PARSED_SQL_CACHE_SIZE).build(); } - /** Get prepared statement cache entry if exists, if not parse and create a new one */ - static ParsedSQLCacheItem getCachedParsedSQL(Sha1HashKey key) { + /** Returns prepared statement cache entry if exists, if not parse and create a new one */ + static ParsedSQLCacheItem getCachedParsedSQL(CityHash128Key key) { return parsedSQLCache.get(key); } - /** Parse and create a information about parsed SQL text */ - static ParsedSQLCacheItem parseAndCacheSQL(Sha1HashKey key, - String sql) throws SQLServerException { + /** Parses and create a information about parsed SQL text */ + static ParsedSQLCacheItem parseAndCacheSQL(CityHash128Key key, String sql) throws SQLServerException { JDBCSyntaxTranslator translator = new JDBCSyntaxTranslator(); String parsedSql = translator.translate(sql); String procName = translator.getProcedureName(); // may return null boolean returnValueSyntax = translator.hasReturnValueSyntax(); - int paramCount = countParams(parsedSql); + int[] parameterPositions = locateParams(parsedSql); - ParsedSQLCacheItem cacheItem = new ParsedSQLCacheItem(parsedSql, paramCount, procName, returnValueSyntax); + ParsedSQLCacheItem cacheItem = new ParsedSQLCacheItem(parsedSql, parameterPositions, procName, + returnValueSyntax); parsedSQLCache.putIfAbsent(key, cacheItem); return cacheItem; } @@ -291,30 +297,31 @@ static ParsedSQLCacheItem parseAndCacheSQL(Sha1HashKey key, private int statementPoolingCacheSize = DEFAULT_STATEMENT_POOLING_CACHE_SIZE; /** Cache of prepared statement handles */ - private ConcurrentLinkedHashMap preparedStatementHandleCache; + private ConcurrentLinkedHashMap preparedStatementHandleCache; /** Cache of prepared statement parameter metadata */ - private ConcurrentLinkedHashMap parameterMetadataCache; + private ConcurrentLinkedHashMap parameterMetadataCache; /** * Checks whether statement pooling is enabled or disabled. The default is set to true; */ private boolean disableStatementPooling = true; /** - * Find statement parameters. + * Locates statement parameters. * * @param sql - * SQL text to parse for number of parameters to intialize. + * SQL text to parse for positions of parameters to intialize. */ - private static int countParams(String sql) { - int nParams = 0; + private static int[] locateParams(String sql) { + LinkedList parameterPositions = new LinkedList<>(); - // Figure out the expected number of parameters by counting the - // parameter placeholders in the SQL string. + // Locate the parameter placeholders in the SQL string. int offset = -1; - while ((offset = ParameterUtils.scanSQLForChar('?', sql, ++offset)) < sql.length()) - ++nParams; + while ((offset = ParameterUtils.scanSQLForChar('?', sql, ++offset)) < sql.length()) { + parameterPositions.add(offset); + } - return nParams; + // return as int[] + return parameterPositions.stream().mapToInt(Integer::valueOf).toArray(); } SqlFedAuthToken getAuthenticationResult() { @@ -322,7 +329,7 @@ SqlFedAuthToken getAuthenticationResult() { } /** - * Struct encapsulating the data to be sent to the server as part of Federated Authentication Feature Extension. + * Encapsulates the data to be sent to the server as part of Federated Authentication Feature Extension. */ class FederatedAuthenticationFeatureExtensionData { boolean fedAuthRequiredPreLoginResponse; @@ -330,8 +337,7 @@ class FederatedAuthenticationFeatureExtensionData { byte[] accessToken = null; SqlAuthentication authentication = null; - FederatedAuthenticationFeatureExtensionData(int libraryType, - String authenticationString, + FederatedAuthenticationFeatureExtensionData(int libraryType, String authenticationString, boolean fedAuthRequiredPreLoginResponse) throws SQLServerException { this.libraryType = libraryType; this.fedAuthRequiredPreLoginResponse = fedAuthRequiredPreLoginResponse; @@ -345,14 +351,14 @@ class FederatedAuthenticationFeatureExtensionData { break; default: assert (false); - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidConnectionSetting")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_InvalidConnectionSetting")); Object[] msgArgs = {"authentication", authenticationString}; throw new SQLServerException(null, form.format(msgArgs), null, 0, false); } } - FederatedAuthenticationFeatureExtensionData(int libraryType, - boolean fedAuthRequiredPreLoginResponse, + FederatedAuthenticationFeatureExtensionData(int libraryType, boolean fedAuthRequiredPreLoginResponse, byte[] accessToken) { this.libraryType = libraryType; this.fedAuthRequiredPreLoginResponse = fedAuthRequiredPreLoginResponse; @@ -380,22 +386,24 @@ class ActiveDirectoryAuthentication { } /** - * denotes the state of the SqlServerConnection + * Denotes the state of the SqlServerConnection. */ private enum State { - Initialized,// default value on calling SQLServerConnection constructor - Connected, // indicates that the TCP connection has completed - Opened, // indicates that the prelogin, login have completed, the database session established and the connection is ready for use. - Closed // indicates that the connection has been closed. + Initialized, // default value on calling SQLServerConnection constructor + Connected, // indicates that the TCP connection has completed + Opened, // indicates that the prelogin, login have completed, the database session established and the + // connection is ready for use. + Closed // indicates that the connection has been closed. } - private final static float TIMEOUTSTEP = 0.08F; // fraction of timeout to use for fast failover connections + private final static float TIMEOUTSTEP = 0.08F; // fraction of timeout to use for fast failover connections private final static float TIMEOUTSTEP_TNIR = 0.125F; - final static int TnirFirstAttemptTimeoutMs = 500; // fraction of timeout to use for fast failover connections + final static int TnirFirstAttemptTimeoutMs = 500; // fraction of timeout to use for fast failover connections /* - * Connection state variables. NB If new state is added then logical connections derived from a physical connection must inherit the same state. - * If state variables are added they must be added also in connection cloning method clone() + * Connection state variables. NB If new state is added then logical connections derived from a physical connection + * must inherit the same state. If state variables are added they must be added also in connection cloning method + * clone() */ private final static int INTERMITTENT_TLS_MAX_RETRY = 5; @@ -415,7 +423,8 @@ ServerPortPlaceHolder getRoutingInfo() { private static final String SET_NETWORK_TIMEOUT_PERM = "setNetworkTimeout"; // see connection properties doc (default is false). - private boolean sendStringParametersAsUnicode = SQLServerDriverBooleanProperty.SEND_STRING_PARAMETERS_AS_UNICODE.getDefaultValue(); + private boolean sendStringParametersAsUnicode = SQLServerDriverBooleanProperty.SEND_STRING_PARAMETERS_AS_UNICODE + .getDefaultValue(); private String hostName = null; @@ -429,7 +438,8 @@ final boolean useLastUpdateCount() { return lastUpdateCount; } - // Translates the serverName from Unicode to ASCII Compatible Encoding (ACE), as defined by the ToASCII operation of RFC 3490 + // Translates the serverName from Unicode to ASCII Compatible Encoding (ACE), as defined by the ToASCII operation of + // RFC 3490 private boolean serverNameAsACE = SQLServerDriverBooleanProperty.SERVER_NAME_AS_ACE.getDefaultValue(); boolean serverNameAsACE() { @@ -455,8 +465,8 @@ final ApplicationIntent getApplicationIntent() { return applicationIntent; } - private int nLockTimeout; // see connection properties doc - private String selectMethod; // see connection properties doc 4.0 new property + private int nLockTimeout; // see connection properties doc + private String selectMethod; // see connection properties doc 4.0 new property final String getSelectMethod() { return selectMethod; @@ -475,12 +485,12 @@ final int getQueryTimeoutSeconds() { } /** - * timeout value for canceling the query timeout + * Timeout value for canceling the query timeout. */ private int cancelQueryTimeoutSeconds; /** - * Retrieves the cancelTimeout in seconds + * Returns the cancelTimeout in seconds. * * @return */ @@ -493,34 +503,37 @@ final int getCancelQueryTimeoutSeconds() { final int getSocketTimeoutMilliseconds() { return socketTimeoutMilliseconds; } - + /** - * boolean value for deciding if the driver should use bulk copy API for batch inserts + * boolean value for deciding if the driver should use bulk copy API for batch inserts. */ private boolean useBulkCopyForBatchInsert; /** - * Retrieves the useBulkCopyForBatchInsert value. + * Returns the useBulkCopyForBatchInsert value. + * * @return flag for using Bulk Copy API for batch insert operations. */ public boolean getUseBulkCopyForBatchInsert() { return useBulkCopyForBatchInsert; } - + /** * Specifies the flag for using Bulk Copy API for batch insert operations. - * @param useBulkCopyForBatchInsert boolean value for useBulkCopyForBatchInsert. + * + * @param useBulkCopyForBatchInsert + * boolean value for useBulkCopyForBatchInsert. */ public void setUseBulkCopyForBatchInsert(boolean useBulkCopyForBatchInsert) { this.useBulkCopyForBatchInsert = useBulkCopyForBatchInsert; } - + boolean userSetTNIR = true; private boolean sendTimeAsDatetime = SQLServerDriverBooleanProperty.SEND_TIME_AS_DATETIME.getDefaultValue(); @Override - public synchronized final boolean getSendTimeAsDatetime() { + public final boolean getSendTimeAsDatetime() { return !isKatmaiOrLater() || sendTimeAsDatetime; } @@ -584,7 +597,7 @@ boolean getServerSupportsColumnEncryption() { boolean getServerSupportsDataClassification() { return serverSupportsDataClassification; } - + static boolean isWindows; static Map globalSystemColumnEncryptionKeyStoreProviders = new HashMap<>(); static { @@ -592,8 +605,7 @@ boolean getServerSupportsDataClassification() { isWindows = true; SQLServerColumnEncryptionCertificateStoreProvider provider = new SQLServerColumnEncryptionCertificateStoreProvider(); globalSystemColumnEncryptionKeyStoreProviders.put(provider.getName(), provider); - } - else { + } else { isWindows = false; } } @@ -605,9 +617,9 @@ boolean getServerSupportsDataClassification() { * Registers key store providers in the globalCustomColumnEncryptionKeyStoreProviders. * * @param clientKeyStoreProviders - * a map containing the store providers information. + * a map containing the store providers information. * @throws SQLServerException - * when an error occurs + * when an error occurs */ public static synchronized void registerColumnEncryptionKeyStoreProviders( Map clientKeyStoreProviders) throws SQLServerException { @@ -615,11 +627,13 @@ public static synchronized void registerColumnEncryptionKeyStoreProviders( "Registering Column Encryption Key Store Providers"); if (null == clientKeyStoreProviders) { - throw new SQLServerException(null, SQLServerException.getErrString("R_CustomKeyStoreProviderMapNull"), null, 0, false); + throw new SQLServerException(null, SQLServerException.getErrString("R_CustomKeyStoreProviderMapNull"), null, + 0, false); } if (null != globalCustomColumnEncryptionKeyStoreProviders) { - throw new SQLServerException(null, SQLServerException.getErrString("R_CustomKeyStoreProviderSetOnce"), null, 0, false); + throw new SQLServerException(null, SQLServerException.getErrString("R_CustomKeyStoreProviderSetOnce"), null, + 0, false); } globalCustomColumnEncryptionKeyStoreProviders = new HashMap<>(); @@ -627,15 +641,18 @@ public static synchronized void registerColumnEncryptionKeyStoreProviders( for (Map.Entry entry : clientKeyStoreProviders.entrySet()) { String providerName = entry.getKey(); if (null == providerName || 0 == providerName.length()) { - throw new SQLServerException(null, SQLServerException.getErrString("R_EmptyCustomKeyStoreProviderName"), null, 0, false); + throw new SQLServerException(null, SQLServerException.getErrString("R_EmptyCustomKeyStoreProviderName"), + null, 0, false); } if ((providerName.substring(0, 6).equalsIgnoreCase(RESERVED_PROVIDER_NAME_PREFIX))) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidCustomKeyStoreProviderName")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_InvalidCustomKeyStoreProviderName")); Object[] msgArgs = {providerName, RESERVED_PROVIDER_NAME_PREFIX}; throw new SQLServerException(null, form.format(msgArgs), null, 0, false); } if (null == entry.getValue()) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_CustomKeyStoreProviderValueNull")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_CustomKeyStoreProviderValueNull")); Object[] msgArgs = {providerName, RESERVED_PROVIDER_NAME_PREFIX}; throw new SQLServerException(null, form.format(msgArgs), null, 0, false); } @@ -643,11 +660,14 @@ public static synchronized void registerColumnEncryptionKeyStoreProviders( } loggerExternal.exiting(SQLServerConnection.class.getName(), "registerColumnEncryptionKeyStoreProviders", - "Number of Key store providers that are registered:" + globalCustomColumnEncryptionKeyStoreProviders.size()); + "Number of Key store providers that are registered:" + + globalCustomColumnEncryptionKeyStoreProviders.size()); } - static synchronized SQLServerColumnEncryptionKeyStoreProvider getGlobalSystemColumnEncryptionKeyStoreProvider(String providerName) { - if (null != globalSystemColumnEncryptionKeyStoreProviders && globalSystemColumnEncryptionKeyStoreProviders.containsKey(providerName)) { + static synchronized SQLServerColumnEncryptionKeyStoreProvider getGlobalSystemColumnEncryptionKeyStoreProvider( + String providerName) { + if (null != globalSystemColumnEncryptionKeyStoreProviders + && globalSystemColumnEncryptionKeyStoreProviders.containsKey(providerName)) { return globalSystemColumnEncryptionKeyStoreProviders.get(providerName); } return null; @@ -669,18 +689,21 @@ synchronized String getAllSystemColumnEncryptionKeyStoreProviders() { return keyStores; } - static synchronized SQLServerColumnEncryptionKeyStoreProvider getGlobalCustomColumnEncryptionKeyStoreProvider(String providerName) { - if (null != globalCustomColumnEncryptionKeyStoreProviders && globalCustomColumnEncryptionKeyStoreProviders.containsKey(providerName)) { + static synchronized SQLServerColumnEncryptionKeyStoreProvider getGlobalCustomColumnEncryptionKeyStoreProvider( + String providerName) { + if (null != globalCustomColumnEncryptionKeyStoreProviders + && globalCustomColumnEncryptionKeyStoreProviders.containsKey(providerName)) { return globalCustomColumnEncryptionKeyStoreProviders.get(providerName); } return null; } - synchronized SQLServerColumnEncryptionKeyStoreProvider getSystemColumnEncryptionKeyStoreProvider(String providerName) { - if ((null != systemColumnEncryptionKeyStoreProvider) && (systemColumnEncryptionKeyStoreProvider.containsKey(providerName))) { + synchronized SQLServerColumnEncryptionKeyStoreProvider getSystemColumnEncryptionKeyStoreProvider( + String providerName) { + if ((null != systemColumnEncryptionKeyStoreProvider) + && (systemColumnEncryptionKeyStoreProvider.containsKey(providerName))) { return systemColumnEncryptionKeyStoreProvider.get(providerName); - } - else { + } else { return null; } } @@ -692,10 +715,12 @@ synchronized SQLServerColumnEncryptionKeyStoreProvider getSystemColumnEncryption * Sets Trusted Master Key Paths in the columnEncryptionTrustedMasterKeyPaths. * * @param trustedKeyPaths - * all master key paths that are trusted + * all master key paths that are trusted */ - public static synchronized void setColumnEncryptionTrustedMasterKeyPaths(Map> trustedKeyPaths) { - loggerExternal.entering(SQLServerConnection.class.getName(), "setColumnEncryptionTrustedMasterKeyPaths", "Setting Trusted Master Key Paths"); + public static synchronized void setColumnEncryptionTrustedMasterKeyPaths( + Map> trustedKeyPaths) { + loggerExternal.entering(SQLServerConnection.class.getName(), "setColumnEncryptionTrustedMasterKeyPaths", + "Setting Trusted Master Key Paths"); // Use upper case for server and instance names. columnEncryptionTrustedMasterKeyPaths.clear(); @@ -711,9 +736,9 @@ public static synchronized void setColumnEncryptionTrustedMasterKeyPaths(Map trustedKeyPaths) { @@ -731,7 +756,7 @@ public static synchronized void updateColumnEncryptionTrustedMasterKeyPaths(Stri * Removes the trusted Master key Path from the columnEncryptionTrustedMasterKeyPaths. * * @param server - * String server name + * String server name */ public static synchronized void removeColumnEncryptionTrustedMasterKeyPaths(String server) { loggerExternal.entering(SQLServerConnection.class.getName(), "removeColumnEncryptionTrustedMasterKeyPaths", @@ -745,12 +770,13 @@ public static synchronized void removeColumnEncryptionTrustedMasterKeyPaths(Stri } /** - * Retrieves the Trusted Master Key Paths. + * Returns the Trusted Master Key Paths. * * @return columnEncryptionTrustedMasterKeyPaths. */ public static synchronized Map> getColumnEncryptionTrustedMasterKeyPaths() { - loggerExternal.entering(SQLServerConnection.class.getName(), "getColumnEncryptionTrustedMasterKeyPaths", "Getting Trusted Master Key Paths"); + loggerExternal.entering(SQLServerConnection.class.getName(), "getColumnEncryptionTrustedMasterKeyPaths", + "Getting Trusted Master Key Paths"); Map> masterKeyPathCopy = new HashMap<>(); @@ -764,13 +790,11 @@ public static synchronized Map> getColumnEncryptionTrustedM return masterKeyPathCopy; } - static synchronized List getColumnEncryptionTrustedMasterKeyPaths(String server, - Boolean[] hasEntry) { + static synchronized List getColumnEncryptionTrustedMasterKeyPaths(String server, Boolean[] hasEntry) { if (columnEncryptionTrustedMasterKeyPaths.containsKey(server)) { hasEntry[0] = true; return columnEncryptionTrustedMasterKeyPaths.get(server); - } - else { + } else { hasEntry[0] = false; return null; } @@ -784,8 +808,8 @@ static synchronized List getColumnEncryptionTrustedMasterKeyPaths(String // This is the current connect place holder this should point one of the primary or failover place holder ServerPortPlaceHolder currentConnectPlaceHolder = null; - String sqlServerVersion; // SQL Server version string - boolean xopenStates; // XOPEN or SQL 92 state codes? + String sqlServerVersion; // SQL Server version string + boolean xopenStates; // XOPEN or SQL 92 state codes? private boolean databaseAutoCommitMode; private boolean inXATransaction = false; // Set to true when in an XA transaction. private byte[] transactionDescriptor = new byte[8]; @@ -798,7 +822,7 @@ final boolean rolledBackTransaction() { return rolledBackTransaction; } - private State state = State.Initialized; // connection state + private State state = State.Initialized; // connection state private void setState(State state) { this.state = state; @@ -811,7 +835,7 @@ final boolean isSessionUnAvailable() { return !(state.equals(State.Opened)); } - final static int maxDecimalPrecision = 38; // @@max_precision for SQL 2000 and 2005 is 38. + final static int maxDecimalPrecision = 38; // @@max_precision for SQL 2000 and 2005 is 38. final static int defaultDecimalPrecision = 18; final String traceID; @@ -835,7 +859,7 @@ final void setMaxFieldSize(int limit) throws SQLServerException { final void initResettableValues() { rolledBackTransaction = false; transactionIsolationLevel = Connection.TRANSACTION_READ_COMMITTED;// default isolation level - maxFieldSize = 0; // default: 0 --> no limit + maxFieldSize = 0; // default: 0 --> no limit maxRows = 0; // default: 0 --> no limit nLockTimeout = -1; databaseAutoCommitMode = true;// auto commit mode @@ -859,26 +883,27 @@ final void setMaxRows(int limit) throws SQLServerException { } } - private SQLCollation databaseCollation; // Default database collation read from ENVCHANGE_SQLCOLLATION token. + private SQLCollation databaseCollation; // Default database collation read from ENVCHANGE_SQLCOLLATION token. final SQLCollation getDatabaseCollation() { return databaseCollation; } - static private final AtomicInteger baseConnectionID = new AtomicInteger(0); // connection id dispenser + static private final AtomicInteger baseConnectionID = new AtomicInteger(0); // connection id dispenser // This is the current catalog - private String sCatalog = "master"; // the database catalog + private String sCatalog = "master"; // the database catalog // This is the catalog immediately after login. private String originalCatalog = "master"; private int transactionIsolationLevel; private SQLServerPooledConnection pooledConnectionParent; private DatabaseMetaData databaseMetaData; // the meta data for this connection - private int nNextSavePointId = 10000; // first save point id + private int nNextSavePointId = 10000; // first save point id static final private java.util.logging.Logger connectionlogger = java.util.logging.Logger .getLogger("com.microsoft.sqlserver.jdbc.internals.SQLServerConnection"); - static final private java.util.logging.Logger loggerExternal = java.util.logging.Logger.getLogger("com.microsoft.sqlserver.jdbc.Connection"); + static final private java.util.logging.Logger loggerExternal = java.util.logging.Logger + .getLogger("com.microsoft.sqlserver.jdbc.Connection"); private final String loggingClassName; // there are three ways to get a failover partner @@ -948,7 +973,7 @@ final boolean attachConnId() { @SuppressWarnings("unused") SQLServerConnection(String parentInfo) throws SQLServerException { - int connectionID = nextConnectionID(); // sequential connection id + int connectionID = nextConnectionID(); // sequential connection id traceID = "ConnectionID:" + connectionID; loggingClassName = "com.microsoft.sqlserver.jdbc.SQLServerConnection:" + connectionID; if (connectionlogger.isLoggable(Level.FINE)) @@ -971,9 +996,9 @@ final void setAssociatedProxy(SQLServerConnectionPoolProxy proxy) { } /* - * This function is used by the functions that return a connection object to outside world. E.g. stmt.getConnection, these functions should return - * the proxy not the actual physical connection when the physical connection is pooled and the user should be accessing the connection functions - * via the proxy object. + * Provides functionality to return a connection object to outside world. E.g. stmt.getConnection, these functions + * should return the proxy not the actual physical connection when the physical connection is pooled and the user + * should be accessing the connection functions via the proxy object. */ final Connection getConnection() { if (null != proxy) @@ -988,7 +1013,7 @@ final void resetPooledConnection() { } /** - * Generate the next unique connection id. + * Generates the next unique connection id. * * @return the next conn id */ @@ -1005,7 +1030,7 @@ String getClassNameLogging() { } /** - * This is a helper function to provide an ID string suitable for tracing. + * Provides a helper function to return an ID string suitable for tracing. */ @Override public String toString() { @@ -1016,13 +1041,15 @@ public String toString() { } /** - * Check if the connection is closed Create a new connection if it's a fedauth connection and the access token is going to expire. + * Checks if the connection is closed Create a new connection if it's a fedauth connection and the access token is + * going to expire. * * @throws SQLServerException */ void checkClosed() throws SQLServerException { if (isSessionUnAvailable()) { - SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_connectionIsClosed"), null, false); + SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_connectionIsClosed"), + null, false); } if (null != fedAuthToken) { @@ -1033,20 +1060,19 @@ void checkClosed() throws SQLServerException { } /** - * Check if a string property is enabled. + * Returns if a string property is enabled. * * @param propName - * the string property name + * the string property name * @param propValue - * the string property value. + * the string property value. * @return false if p == null (meaning take default). * @return true if p == "true" (case-insensitive). * @return false if p == "false" (case-insensitive). * @exception SQLServerException - * thrown if value is not recognized. + * thrown if value is not recognized. */ - private boolean booleanPropertyOn(String propName, - String propValue) throws SQLServerException { + private boolean booleanPropertyOn(String propName, String propValue) throws SQLServerException { // Null means take the default of false. if (null == propValue) return false; @@ -1068,16 +1094,16 @@ private boolean booleanPropertyOn(String propName, final static int MAX_SQL_LOGIN_NAME_WCHARS = 128; /** - * Validates propName against maximum allowed length MAX_SQL_LOGIN_NAME_WCHARS. Throws exception if name length exceeded. + * Validates propName against maximum allowed length MAX_SQL_LOGIN_NAME_WCHARS. Throws exception if name length + * exceeded. * * @param propName - * the name of the property. + * the name of the property. * @param propValue - * the value of the property. + * the value of the property. * @throws SQLServerException */ - void ValidateMaxSQLLoginName(String propName, - String propValue) throws SQLServerException { + void ValidateMaxSQLLoginName(String propName, String propValue) throws SQLServerException { if (propValue != null && propValue.length() > MAX_SQL_LOGIN_NAME_WCHARS) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_propertyMaximumExceedsChars")); Object[] msgArgs = {propName, Integer.toString(MAX_SQL_LOGIN_NAME_WCHARS)}; @@ -1085,22 +1111,19 @@ void ValidateMaxSQLLoginName(String propName, } } - Connection connect(Properties propsIn, - SQLServerPooledConnection pooledConnection) throws SQLServerException { + Connection connect(Properties propsIn, SQLServerPooledConnection pooledConnection) throws SQLServerException { int loginTimeoutSeconds = 0; // Will be set during the first retry attempt. long start = System.currentTimeMillis(); for (int retryAttempt = 0;;) { try { return connectInternal(propsIn, pooledConnection); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { // Catch only the TLS 1.2 specific intermittent error. if (SQLServerException.DRIVER_ERROR_INTERMITTENT_TLS_FAILED != e.getDriverErrorCode()) { // Re-throw all other exceptions. throw e; - } - else { + } else { // Special handling of the retry logic for TLS 1.2 intermittent issue. // If timeout is not set yet, set it once. @@ -1108,8 +1131,9 @@ Connection connect(Properties propsIn, // We do not need to check for exceptions here, as the connection properties are already // verified during the first try. Also, we would like to do this calculation // only for the TLS 1.2 exception case. - loginTimeoutSeconds = SQLServerDriverIntProperty.LOGIN_TIMEOUT.getDefaultValue(); // if the user does not specify a default - // timeout, default is 15 per spec + // if the user does not specify a default timeout, default is 15 per spec + loginTimeoutSeconds = SQLServerDriverIntProperty.LOGIN_TIMEOUT.getDefaultValue(); + String sPropValue = propsIn.getProperty(SQLServerDriverIntProperty.LOGIN_TIMEOUT.toString()); if (null != sPropValue && sPropValue.length() > 0) { int sPropValueInt = Integer.parseInt(sPropValue); @@ -1125,19 +1149,18 @@ Connection connect(Properties propsIn, if (INTERMITTENT_TLS_MAX_RETRY < retryAttempt) { // Re-throw the exception if we have reached the maximum retry attempts. if (connectionlogger.isLoggable(Level.FINE)) { - connectionlogger.fine( - "Connection failed during SSL handshake. Maximum retry attempt (" + INTERMITTENT_TLS_MAX_RETRY + ") reached. "); + connectionlogger.fine("Connection failed during SSL handshake. Maximum retry attempt (" + + INTERMITTENT_TLS_MAX_RETRY + ") reached. "); } throw e; - } - else if (elapsedSeconds >= loginTimeoutSeconds) { + } else if (elapsedSeconds >= loginTimeoutSeconds) { // Re-throw the exception if we do not have any time left to retry. if (connectionlogger.isLoggable(Level.FINE)) { - connectionlogger.fine("Connection failed during SSL handshake. Not retrying as timeout expired."); + connectionlogger + .fine("Connection failed during SSL handshake. Not retrying as timeout expired."); } throw e; - } - else { + } else { // Retry the connection. if (connectionlogger.isLoggable(Level.FINE)) { connectionlogger.fine( @@ -1150,33 +1173,33 @@ else if (elapsedSeconds >= loginTimeoutSeconds) { } } - private void registerKeyStoreProviderOnConnection(String keyStoreAuth, - String keyStoreSecret, + private void registerKeyStoreProviderOnConnection(String keyStoreAuth, String keyStoreSecret, String keyStoreLocation) throws SQLServerException { if (null == keyStoreAuth) { // secret and location must be null too. if ((null != keyStoreSecret)) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_keyStoreAuthenticationNotSet")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_keyStoreAuthenticationNotSet")); Object[] msgArgs = {"keyStoreSecret"}; throw new SQLServerException(form.format(msgArgs), null); } if (null != keyStoreLocation) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_keyStoreAuthenticationNotSet")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_keyStoreAuthenticationNotSet")); Object[] msgArgs = {"keyStoreLocation"}; throw new SQLServerException(form.format(msgArgs), null); } - } - else { + } else { KeyStoreAuthentication keyStoreAuthentication = KeyStoreAuthentication.valueOfString(keyStoreAuth); switch (keyStoreAuthentication) { case JavaKeyStorePassword: // both secret and location must be set for JKS. if ((null == keyStoreSecret) || (null == keyStoreLocation)) { - throw new SQLServerException(SQLServerException.getErrString("R_keyStoreSecretOrLocationNotSet"), null); - } - else { - SQLServerColumnEncryptionJavaKeyStoreProvider provider = new SQLServerColumnEncryptionJavaKeyStoreProvider(keyStoreLocation, - keyStoreSecret.toCharArray()); + throw new SQLServerException( + SQLServerException.getErrString("R_keyStoreSecretOrLocationNotSet"), null); + } else { + SQLServerColumnEncryptionJavaKeyStoreProvider provider = new SQLServerColumnEncryptionJavaKeyStoreProvider( + keyStoreLocation, keyStoreSecret.toCharArray()); systemColumnEncryptionKeyStoreProvider.put(provider.getName(), provider); } break; @@ -1189,12 +1212,13 @@ private void registerKeyStoreProviderOnConnection(String keyStoreAuth, } /** - * Establish a physical database connection based on the user specified connection properties. Logon to the database. + * Establish a physical database connection based on the user specified connection properties. Logon to the + * database. * * @param propsIn - * the connection properties + * the connection properties * @param pooledConnection - * a parent pooled connection if this is a logical connection + * a parent pooled connection if this is a logical connection * @throws SQLServerException * @return the database connection */ @@ -1205,11 +1229,13 @@ Connection connectInternal(Properties propsIn, pooledConnectionParent = pooledConnection; - String hostNameInCertificate = activeConnectionProperties.getProperty(SQLServerDriverStringProperty.HOSTNAME_IN_CERTIFICATE.toString()); + String hostNameInCertificate = activeConnectionProperties + .getProperty(SQLServerDriverStringProperty.HOSTNAME_IN_CERTIFICATE.toString()); // hostNameInCertificate property can change when redirection is involved, so maintain this value // for every instance of SQLServerConnection. - if (null == originalHostNameInCertificate && null != hostNameInCertificate && !hostNameInCertificate.isEmpty()) { + if (null == originalHostNameInCertificate && null != hostNameInCertificate + && !hostNameInCertificate.isEmpty()) { originalHostNameInCertificate = activeConnectionProperties .getProperty(SQLServerDriverStringProperty.HOSTNAME_IN_CERTIFICATE.toString()); } @@ -1220,7 +1246,7 @@ Connection connectInternal(Properties propsIn, activeConnectionProperties.setProperty(SQLServerDriverStringProperty.HOSTNAME_IN_CERTIFICATE.toString(), originalHostNameInCertificate); } - + String sPropKey; String sPropValue; @@ -1244,14 +1270,13 @@ Connection connectInternal(Properties propsIn, sPropValue = activeConnectionProperties.getProperty(sPropKey); ValidateMaxSQLLoginName(sPropKey, sPropValue); - int loginTimeoutSeconds = SQLServerDriverIntProperty.LOGIN_TIMEOUT.getDefaultValue(); // if the user does not specify a default timeout, - // default is 15 per spec + // if the user does not specify a default timeout, default is 15 per spec + int loginTimeoutSeconds = SQLServerDriverIntProperty.LOGIN_TIMEOUT.getDefaultValue(); sPropValue = activeConnectionProperties.getProperty(SQLServerDriverIntProperty.LOGIN_TIMEOUT.toString()); if (null != sPropValue && sPropValue.length() > 0) { try { loginTimeoutSeconds = Integer.parseInt(sPropValue); - } - catch (NumberFormatException e) { + } catch (NumberFormatException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidTimeOut")); Object[] msgArgs = {sPropValue}; SQLServerException.makeFromDriverError(this, this, form.format(msgArgs), null, false); @@ -1264,7 +1289,8 @@ Connection connectInternal(Properties propsIn, } } - // Translates the serverName from Unicode to ASCII Compatible Encoding (ACE), as defined by the ToASCII operation of RFC 3490. + // Translates the serverName from Unicode to ASCII Compatible Encoding (ACE), as defined by the ToASCII + // operation of RFC 3490. sPropKey = SQLServerDriverBooleanProperty.SERVER_NAME_AS_ACE.toString(); sPropValue = activeConnectionProperties.getProperty(sPropKey); if (sPropValue == null) { @@ -1301,9 +1327,9 @@ Connection connectInternal(Properties propsIn, if (true == serverNameAsACE) { try { sPropValue = java.net.IDN.toASCII(sPropValue); - } - catch (IllegalArgumentException ex) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidConnectionSetting")); + } catch (IllegalArgumentException ex) { + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_InvalidConnectionSetting")); Object[] msgArgs = {"serverNameAsACE", sPropValue}; throw new SQLServerException(form.format(msgArgs), ex); } @@ -1380,7 +1406,8 @@ Connection connectInternal(Properties propsIn, sPropValue = activeConnectionProperties.getProperty(sPropKey); if (sPropValue == null) { userSetTNIR = false; - sPropValue = Boolean.toString(SQLServerDriverBooleanProperty.TRANSPARENT_NETWORK_IP_RESOLUTION.getDefaultValue()); + sPropValue = Boolean + .toString(SQLServerDriverBooleanProperty.TRANSPARENT_NETWORK_IP_RESOLUTION.getDefaultValue()); activeConnectionProperties.setProperty(sPropKey, sPropValue); } transparentNetworkIPResolution = booleanPropertyOn(sPropKey, sPropValue); @@ -1398,13 +1425,15 @@ Connection connectInternal(Properties propsIn, sPropKey = SQLServerDriverBooleanProperty.TRUST_SERVER_CERTIFICATE.toString(); sPropValue = activeConnectionProperties.getProperty(sPropKey); if (sPropValue == null) { - sPropValue = Boolean.toString(SQLServerDriverBooleanProperty.TRUST_SERVER_CERTIFICATE.getDefaultValue()); + sPropValue = Boolean + .toString(SQLServerDriverBooleanProperty.TRUST_SERVER_CERTIFICATE.getDefaultValue()); activeConnectionProperties.setProperty(sPropKey, sPropValue); } trustServerCertificate = booleanPropertyOn(sPropKey, sPropValue); - trustManagerClass = activeConnectionProperties.getProperty(SQLServerDriverStringProperty.TRUST_MANAGER_CLASS.toString()); + trustManagerClass = activeConnectionProperties + .getProperty(SQLServerDriverStringProperty.TRUST_MANAGER_CLASS.toString()); trustManagerConstructorArg = activeConnectionProperties .getProperty(SQLServerDriverStringProperty.TRUST_MANAGER_CONSTRUCTOR_ARG.toString()); @@ -1414,8 +1443,7 @@ Connection connectInternal(Properties propsIn, sPropValue = SQLServerDriverStringProperty.SELECT_METHOD.getDefaultValue(); if ("cursor".equalsIgnoreCase(sPropValue) || "direct".equalsIgnoreCase(sPropValue)) { activeConnectionProperties.setProperty(sPropKey, sPropValue.toLowerCase(Locale.ENGLISH)); - } - else { + } else { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidselectMethod")); Object[] msgArgs = {sPropValue}; SQLServerException.makeFromDriverError(this, this, form.format(msgArgs), null, false); @@ -1427,8 +1455,7 @@ Connection connectInternal(Properties propsIn, sPropValue = SQLServerDriverStringProperty.RESPONSE_BUFFERING.getDefaultValue(); if ("full".equalsIgnoreCase(sPropValue) || "adaptive".equalsIgnoreCase(sPropValue)) { activeConnectionProperties.setProperty(sPropKey, sPropValue.toLowerCase(Locale.ENGLISH)); - } - else { + } else { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidresponseBuffering")); Object[] msgArgs = {sPropValue}; SQLServerException.makeFromDriverError(this, this, form.format(msgArgs), null, false); @@ -1452,13 +1479,14 @@ Connection connectInternal(Properties propsIn, // Must be set before DISABLE_STATEMENT_POOLING sPropKey = SQLServerDriverIntProperty.STATEMENT_POOLING_CACHE_SIZE.toString(); - if (activeConnectionProperties.getProperty(sPropKey) != null && activeConnectionProperties.getProperty(sPropKey).length() > 0) { + if (activeConnectionProperties.getProperty(sPropKey) != null + && activeConnectionProperties.getProperty(sPropKey).length() > 0) { try { int n = Integer.parseInt(activeConnectionProperties.getProperty(sPropKey)); this.setStatementPoolingCacheSize(n); - } - catch (NumberFormatException e) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_statementPoolingCacheSize")); + } catch (NumberFormatException e) { + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_statementPoolingCacheSize")); Object[] msgArgs = {activeConnectionProperties.getProperty(sPropKey)}; SQLServerException.makeFromDriverError(this, this, form.format(msgArgs), null, false); } @@ -1501,36 +1529,50 @@ Connection connectInternal(Properties propsIn, } authenticationString = SqlAuthentication.valueOfString(sPropValue).toString(); - if ((true == integratedSecurity) && (!authenticationString.equalsIgnoreCase(SqlAuthentication.NotSpecified.toString()))) { + if ((true == integratedSecurity) + && (!authenticationString.equalsIgnoreCase(SqlAuthentication.NotSpecified.toString()))) { if (connectionlogger.isLoggable(Level.SEVERE)) { - connectionlogger.severe(toString() + " " + SQLServerException.getErrString("R_SetAuthenticationWhenIntegratedSecurityTrue")); + connectionlogger.severe(toString() + " " + + SQLServerException.getErrString("R_SetAuthenticationWhenIntegratedSecurityTrue")); } - throw new SQLServerException(SQLServerException.getErrString("R_SetAuthenticationWhenIntegratedSecurityTrue"), null); + throw new SQLServerException( + SQLServerException.getErrString("R_SetAuthenticationWhenIntegratedSecurityTrue"), null); } if (authenticationString.equalsIgnoreCase(SqlAuthentication.ActiveDirectoryIntegrated.toString()) - && ((!activeConnectionProperties.getProperty(SQLServerDriverStringProperty.USER.toString()).isEmpty()) - || (!activeConnectionProperties.getProperty(SQLServerDriverStringProperty.PASSWORD.toString()).isEmpty()))) { + && ((!activeConnectionProperties.getProperty(SQLServerDriverStringProperty.USER.toString()) + .isEmpty()) + || (!activeConnectionProperties + .getProperty(SQLServerDriverStringProperty.PASSWORD.toString()).isEmpty()))) { if (connectionlogger.isLoggable(Level.SEVERE)) { - connectionlogger.severe(toString() + " " + SQLServerException.getErrString("R_IntegratedAuthenticationWithUserPassword")); + connectionlogger.severe(toString() + " " + + SQLServerException.getErrString("R_IntegratedAuthenticationWithUserPassword")); } - throw new SQLServerException(SQLServerException.getErrString("R_IntegratedAuthenticationWithUserPassword"), null); + throw new SQLServerException( + SQLServerException.getErrString("R_IntegratedAuthenticationWithUserPassword"), null); } if (authenticationString.equalsIgnoreCase(SqlAuthentication.ActiveDirectoryPassword.toString()) - && ((activeConnectionProperties.getProperty(SQLServerDriverStringProperty.USER.toString()).isEmpty()) - || (activeConnectionProperties.getProperty(SQLServerDriverStringProperty.PASSWORD.toString()).isEmpty()))) { + && ((activeConnectionProperties.getProperty(SQLServerDriverStringProperty.USER.toString()) + .isEmpty()) + || (activeConnectionProperties + .getProperty(SQLServerDriverStringProperty.PASSWORD.toString()).isEmpty()))) { if (connectionlogger.isLoggable(Level.SEVERE)) { - connectionlogger.severe(toString() + " " + SQLServerException.getErrString("R_NoUserPasswordForActivePassword")); + connectionlogger.severe( + toString() + " " + SQLServerException.getErrString("R_NoUserPasswordForActivePassword")); } - throw new SQLServerException(SQLServerException.getErrString("R_NoUserPasswordForActivePassword"), null); + throw new SQLServerException(SQLServerException.getErrString("R_NoUserPasswordForActivePassword"), + null); } if (authenticationString.equalsIgnoreCase(SqlAuthentication.SqlPassword.toString()) - && ((activeConnectionProperties.getProperty(SQLServerDriverStringProperty.USER.toString()).isEmpty()) - || (activeConnectionProperties.getProperty(SQLServerDriverStringProperty.PASSWORD.toString()).isEmpty()))) { + && ((activeConnectionProperties.getProperty(SQLServerDriverStringProperty.USER.toString()) + .isEmpty()) + || (activeConnectionProperties + .getProperty(SQLServerDriverStringProperty.PASSWORD.toString()).isEmpty()))) { if (connectionlogger.isLoggable(Level.SEVERE)) { - connectionlogger.severe(toString() + " " + SQLServerException.getErrString("R_NoUserPasswordForSqlPassword")); + connectionlogger.severe( + toString() + " " + SQLServerException.getErrString("R_NoUserPasswordForSqlPassword")); } throw new SQLServerException(SQLServerException.getErrString("R_NoUserPasswordForSqlPassword"), null); } @@ -1543,36 +1585,46 @@ Connection connectInternal(Properties propsIn, if ((null != accessTokenInByte) && 0 == accessTokenInByte.length) { if (connectionlogger.isLoggable(Level.SEVERE)) { - connectionlogger.severe(toString() + " " + SQLServerException.getErrString("R_AccessTokenCannotBeEmpty")); + connectionlogger + .severe(toString() + " " + SQLServerException.getErrString("R_AccessTokenCannotBeEmpty")); } throw new SQLServerException(SQLServerException.getErrString("R_AccessTokenCannotBeEmpty"), null); } if ((true == integratedSecurity) && (null != accessTokenInByte)) { if (connectionlogger.isLoggable(Level.SEVERE)) { - connectionlogger.severe(toString() + " " + SQLServerException.getErrString("R_SetAccesstokenWhenIntegratedSecurityTrue")); + connectionlogger.severe(toString() + " " + + SQLServerException.getErrString("R_SetAccesstokenWhenIntegratedSecurityTrue")); } - throw new SQLServerException(SQLServerException.getErrString("R_SetAccesstokenWhenIntegratedSecurityTrue"), null); + throw new SQLServerException( + SQLServerException.getErrString("R_SetAccesstokenWhenIntegratedSecurityTrue"), null); } - if ((!authenticationString.equalsIgnoreCase(SqlAuthentication.NotSpecified.toString())) && (null != accessTokenInByte)) { + if ((!authenticationString.equalsIgnoreCase(SqlAuthentication.NotSpecified.toString())) + && (null != accessTokenInByte)) { if (connectionlogger.isLoggable(Level.SEVERE)) { - connectionlogger.severe(toString() + " " + SQLServerException.getErrString("R_SetBothAuthenticationAndAccessToken")); + connectionlogger.severe(toString() + " " + + SQLServerException.getErrString("R_SetBothAuthenticationAndAccessToken")); } - throw new SQLServerException(SQLServerException.getErrString("R_SetBothAuthenticationAndAccessToken"), null); + throw new SQLServerException(SQLServerException.getErrString("R_SetBothAuthenticationAndAccessToken"), + null); } - if ((null != accessTokenInByte) && ((!activeConnectionProperties.getProperty(SQLServerDriverStringProperty.USER.toString()).isEmpty()) - || (!activeConnectionProperties.getProperty(SQLServerDriverStringProperty.PASSWORD.toString()).isEmpty()))) { + if ((null != accessTokenInByte) && ((!activeConnectionProperties + .getProperty(SQLServerDriverStringProperty.USER.toString()).isEmpty()) + || (!activeConnectionProperties.getProperty(SQLServerDriverStringProperty.PASSWORD.toString()) + .isEmpty()))) { if (connectionlogger.isLoggable(Level.SEVERE)) { - connectionlogger.severe(toString() + " " + SQLServerException.getErrString("R_AccessTokenWithUserPassword")); + connectionlogger.severe( + toString() + " " + SQLServerException.getErrString("R_AccessTokenWithUserPassword")); } throw new SQLServerException(SQLServerException.getErrString("R_AccessTokenWithUserPassword"), null); } // Turn off TNIR for FedAuth if user does not set TNIR explicitly if (!userSetTNIR) { - if ((!authenticationString.equalsIgnoreCase(SqlAuthentication.NotSpecified.toString())) || (null != accessTokenInByte)) { + if ((!authenticationString.equalsIgnoreCase(SqlAuthentication.NotSpecified.toString())) + || (null != accessTokenInByte)) { transparentNetworkIPResolution = false; } } @@ -1594,8 +1646,7 @@ Connection connectInternal(Properties propsIn, SQLServerException.makeFromDriverError(this, this, form.format(msgArgs), null, false); } } - } - catch (NumberFormatException e) { + } catch (NumberFormatException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidPortNumber")); Object[] msgArgs = {activeConnectionProperties.getProperty(sPropKey)}; SQLServerException.makeFromDriverError(this, this, form.format(msgArgs), null, false); @@ -1615,8 +1666,7 @@ Connection connectInternal(Properties propsIn, // 0 --> Use maximum size else if (0 == requestedPacketSize) requestedPacketSize = TDS.MAX_PACKET_SIZE; - } - catch (NumberFormatException e) { + } catch (NumberFormatException e) { // Ensure that an invalid prop value results in an invalid packet size that // is not acceptable to the server. requestedPacketSize = TDS.INVALID_PACKET_SIZE; @@ -1638,10 +1688,11 @@ else if (0 == requestedPacketSize) // assumes that the null property defaults to false. sPropKey = SQLServerDriverBooleanProperty.SEND_STRING_PARAMETERS_AS_UNICODE.toString(); if (null == activeConnectionProperties.getProperty(sPropKey)) { - sendStringParametersAsUnicode = SQLServerDriverBooleanProperty.SEND_STRING_PARAMETERS_AS_UNICODE.getDefaultValue(); - } - else { - sendStringParametersAsUnicode = booleanPropertyOn(sPropKey, activeConnectionProperties.getProperty(sPropKey)); + sendStringParametersAsUnicode = SQLServerDriverBooleanProperty.SEND_STRING_PARAMETERS_AS_UNICODE + .getDefaultValue(); + } else { + sendStringParametersAsUnicode = booleanPropertyOn(sPropKey, + activeConnectionProperties.getProperty(sPropKey)); } sPropKey = SQLServerDriverBooleanProperty.LAST_UPDATE_COUNT.toString(); @@ -1651,20 +1702,23 @@ else if (0 == requestedPacketSize) sPropKey = SQLServerDriverStringProperty.SELECT_METHOD.toString(); selectMethod = null; - if (activeConnectionProperties.getProperty(sPropKey) != null && activeConnectionProperties.getProperty(sPropKey).length() > 0) { + if (activeConnectionProperties.getProperty(sPropKey) != null + && activeConnectionProperties.getProperty(sPropKey).length() > 0) { selectMethod = activeConnectionProperties.getProperty(sPropKey); } sPropKey = SQLServerDriverStringProperty.RESPONSE_BUFFERING.toString(); responseBuffering = null; - if (activeConnectionProperties.getProperty(sPropKey) != null && activeConnectionProperties.getProperty(sPropKey).length() > 0) { + if (activeConnectionProperties.getProperty(sPropKey) != null + && activeConnectionProperties.getProperty(sPropKey).length() > 0) { responseBuffering = activeConnectionProperties.getProperty(sPropKey); } sPropKey = SQLServerDriverIntProperty.LOCK_TIMEOUT.toString(); int defaultLockTimeOut = SQLServerDriverIntProperty.LOCK_TIMEOUT.getDefaultValue(); nLockTimeout = defaultLockTimeOut; // Wait forever - if (activeConnectionProperties.getProperty(sPropKey) != null && activeConnectionProperties.getProperty(sPropKey).length() > 0) { + if (activeConnectionProperties.getProperty(sPropKey) != null + && activeConnectionProperties.getProperty(sPropKey).length() > 0) { try { int n = Integer.parseInt(activeConnectionProperties.getProperty(sPropKey)); if (n >= defaultLockTimeOut) @@ -1674,8 +1728,7 @@ else if (0 == requestedPacketSize) Object[] msgArgs = {activeConnectionProperties.getProperty(sPropKey)}; SQLServerException.makeFromDriverError(this, this, form.format(msgArgs), null, false); } - } - catch (NumberFormatException e) { + } catch (NumberFormatException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidLockTimeOut")); Object[] msgArgs = {activeConnectionProperties.getProperty(sPropKey)}; SQLServerException.makeFromDriverError(this, this, form.format(msgArgs), null, false); @@ -1685,19 +1738,19 @@ else if (0 == requestedPacketSize) sPropKey = SQLServerDriverIntProperty.QUERY_TIMEOUT.toString(); int defaultQueryTimeout = SQLServerDriverIntProperty.QUERY_TIMEOUT.getDefaultValue(); queryTimeoutSeconds = defaultQueryTimeout; // Wait forever - if (activeConnectionProperties.getProperty(sPropKey) != null && activeConnectionProperties.getProperty(sPropKey).length() > 0) { + if (activeConnectionProperties.getProperty(sPropKey) != null + && activeConnectionProperties.getProperty(sPropKey).length() > 0) { try { int n = Integer.parseInt(activeConnectionProperties.getProperty(sPropKey)); if (n >= defaultQueryTimeout) { queryTimeoutSeconds = n; - } - else { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidQueryTimeout")); + } else { + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_invalidQueryTimeout")); Object[] msgArgs = {activeConnectionProperties.getProperty(sPropKey)}; SQLServerException.makeFromDriverError(this, this, form.format(msgArgs), null, false); } - } - catch (NumberFormatException e) { + } catch (NumberFormatException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidQueryTimeout")); Object[] msgArgs = {activeConnectionProperties.getProperty(sPropKey)}; SQLServerException.makeFromDriverError(this, this, form.format(msgArgs), null, false); @@ -1707,19 +1760,19 @@ else if (0 == requestedPacketSize) sPropKey = SQLServerDriverIntProperty.SOCKET_TIMEOUT.toString(); int defaultSocketTimeout = SQLServerDriverIntProperty.SOCKET_TIMEOUT.getDefaultValue(); socketTimeoutMilliseconds = defaultSocketTimeout; // Wait forever - if (activeConnectionProperties.getProperty(sPropKey) != null && activeConnectionProperties.getProperty(sPropKey).length() > 0) { + if (activeConnectionProperties.getProperty(sPropKey) != null + && activeConnectionProperties.getProperty(sPropKey).length() > 0) { try { int n = Integer.parseInt(activeConnectionProperties.getProperty(sPropKey)); if (n >= defaultSocketTimeout) { socketTimeoutMilliseconds = n; - } - else { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidSocketTimeout")); + } else { + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_invalidSocketTimeout")); Object[] msgArgs = {activeConnectionProperties.getProperty(sPropKey)}; SQLServerException.makeFromDriverError(this, this, form.format(msgArgs), null, false); } - } - catch (NumberFormatException e) { + } catch (NumberFormatException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidSocketTimeout")); Object[] msgArgs = {activeConnectionProperties.getProperty(sPropKey)}; SQLServerException.makeFromDriverError(this, this, form.format(msgArgs), null, false); @@ -1729,7 +1782,8 @@ else if (0 == requestedPacketSize) sPropKey = SQLServerDriverIntProperty.CANCEL_QUERY_TIMEOUT.toString(); int cancelQueryTimeout = SQLServerDriverIntProperty.CANCEL_QUERY_TIMEOUT.getDefaultValue(); - if (activeConnectionProperties.getProperty(sPropKey) != null && activeConnectionProperties.getProperty(sPropKey).length() > 0) { + if (activeConnectionProperties.getProperty(sPropKey) != null + && activeConnectionProperties.getProperty(sPropKey).length() > 0) { try { int n = Integer.parseInt(activeConnectionProperties.getProperty(sPropKey)); if (n >= cancelQueryTimeout) { @@ -1737,28 +1791,29 @@ else if (0 == requestedPacketSize) if (queryTimeoutSeconds > defaultQueryTimeout) { cancelQueryTimeoutSeconds = n; } - } - else { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidCancelQueryTimeout")); + } else { + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_invalidCancelQueryTimeout")); Object[] msgArgs = {activeConnectionProperties.getProperty(sPropKey)}; SQLServerException.makeFromDriverError(this, this, form.format(msgArgs), null, false); } - } - catch (NumberFormatException e) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidCancelQueryTimeout")); + } catch (NumberFormatException e) { + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_invalidCancelQueryTimeout")); Object[] msgArgs = {activeConnectionProperties.getProperty(sPropKey)}; SQLServerException.makeFromDriverError(this, this, form.format(msgArgs), null, false); } } sPropKey = SQLServerDriverIntProperty.SERVER_PREPARED_STATEMENT_DISCARD_THRESHOLD.toString(); - if (activeConnectionProperties.getProperty(sPropKey) != null && activeConnectionProperties.getProperty(sPropKey).length() > 0) { + if (activeConnectionProperties.getProperty(sPropKey) != null + && activeConnectionProperties.getProperty(sPropKey).length() > 0) { try { int n = Integer.parseInt(activeConnectionProperties.getProperty(sPropKey)); setServerPreparedStatementDiscardThreshold(n); - } - catch (NumberFormatException e) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_serverPreparedStatementDiscardThreshold")); + } catch (NumberFormatException e) { + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_serverPreparedStatementDiscardThreshold")); Object[] msgArgs = {activeConnectionProperties.getProperty(sPropKey)}; SQLServerException.makeFromDriverError(this, this, form.format(msgArgs), null, false); } @@ -1769,20 +1824,19 @@ else if (0 == requestedPacketSize) if (null != sPropValue) { setEnablePrepareOnFirstPreparedStatementCall(booleanPropertyOn(sPropKey, sPropValue)); } - + sPropKey = SQLServerDriverBooleanProperty.USE_BULK_COPY_FOR_BATCH_INSERT.toString(); sPropValue = activeConnectionProperties.getProperty(sPropKey); if (null != sPropValue) { useBulkCopyForBatchInsert = booleanPropertyOn(sPropKey, sPropValue); } - + sPropKey = SQLServerDriverStringProperty.SSL_PROTOCOL.toString(); sPropValue = activeConnectionProperties.getProperty(sPropKey); if (null == sPropValue) { sPropValue = SQLServerDriverStringProperty.SSL_PROTOCOL.getDefaultValue(); activeConnectionProperties.setProperty(sPropKey, sPropValue); - } - else { + } else { activeConnectionProperties.setProperty(sPropKey, SSLProtocol.valueOfString(sPropValue).toString()); } @@ -1794,11 +1848,12 @@ else if (0 == requestedPacketSize) // failoverPartner and multiSubnetFailover=true cannot be used together if (multiSubnetFailover && failOverPartnerPropertyValue != null) { - SQLServerException.makeFromDriverError(this, this, SQLServerException.getErrString("R_dbMirroringWithMultiSubnetFailover"), null, - false); + SQLServerException.makeFromDriverError(this, this, + SQLServerException.getErrString("R_dbMirroringWithMultiSubnetFailover"), null, false); } - // transparentNetworkIPResolution is ignored if multiSubnetFailover or DBMirroring is true and user does not set TNIR explicitly + // transparentNetworkIPResolution is ignored if multiSubnetFailover or DBMirroring is true and user does not + // set TNIR explicitly if (multiSubnetFailover || (null != failOverPartnerPropertyValue)) { if (!userSetTNIR) { transparentNetworkIPResolution = false; @@ -1806,20 +1861,24 @@ else if (0 == requestedPacketSize) } // failoverPartner and applicationIntent=ReadOnly cannot be used together - if ((applicationIntent != null) && applicationIntent.equals(ApplicationIntent.READ_ONLY) && failOverPartnerPropertyValue != null) { - SQLServerException.makeFromDriverError(this, this, SQLServerException.getErrString("R_dbMirroringWithReadOnlyIntent"), null, false); + if ((applicationIntent != null) && applicationIntent.equals(ApplicationIntent.READ_ONLY) + && failOverPartnerPropertyValue != null) { + SQLServerException.makeFromDriverError(this, this, + SQLServerException.getErrString("R_dbMirroringWithReadOnlyIntent"), null, false); } // check to see failover specified without DB error here if not. if (null != activeConnectionProperties.getProperty(databaseNameProperty)) { // look to see if there exists a failover - fo = FailoverMapSingleton.getFailoverInfo(this, activeConnectionProperties.getProperty(serverNameProperty), - activeConnectionProperties.getProperty(instanceNameProperty), activeConnectionProperties.getProperty(databaseNameProperty)); - } - else { + fo = FailoverMapSingleton.getFailoverInfo(this, + activeConnectionProperties.getProperty(serverNameProperty), + activeConnectionProperties.getProperty(instanceNameProperty), + activeConnectionProperties.getProperty(databaseNameProperty)); + } else { // it is an error to specify failover without db. if (null != failOverPartnerPropertyValue) - SQLServerException.makeFromDriverError(this, this, SQLServerException.getErrString("R_failoverPartnerWithoutDB"), null, true); + SQLServerException.makeFromDriverError(this, this, + SQLServerException.getErrString("R_failoverPartnerWithoutDB"), null, true); } String mirror = null; @@ -1827,7 +1886,8 @@ else if (0 == requestedPacketSize) mirror = failOverPartnerPropertyValue; long startTime = System.currentTimeMillis(); - login(activeConnectionProperties.getProperty(serverNameProperty), instanceValue, nPort, mirror, fo, loginTimeoutSeconds, startTime); + login(activeConnectionProperties.getProperty(serverNameProperty), instanceValue, nPort, mirror, fo, + loginTimeoutSeconds, startTime); // If SSL is to be used for the duration of the connection, then make sure // that the final negotiated TDS packet size is no larger than the SSL record size. @@ -1837,8 +1897,9 @@ else if (0 == requestedPacketSize) if (tdsPacketSize > sslRecordSize) { if (connectionlogger.isLoggable(Level.FINER)) { - connectionlogger.finer(toString() + " Negotiated tdsPacketSize " + tdsPacketSize + " is too large for SSL with JRE " - + Util.SYSTEM_JRE + " (max size is " + sslRecordSize + ")"); + connectionlogger.finer(toString() + " Negotiated tdsPacketSize " + tdsPacketSize + + " is too large for SSL with JRE " + Util.SYSTEM_JRE + " (max size is " + sslRecordSize + + ")"); } MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_packetSizeTooBigForSSL")); Object[] msgArgs = {Integer.toString(sslRecordSize)}; @@ -1851,8 +1912,7 @@ else if (0 == requestedPacketSize) if (connectionlogger.isLoggable(Level.FINER)) { connectionlogger.finer(toString() + " End of connect"); } - } - finally { + } finally { // once we exit the connect function, the connection can be only in one of two // states, Opened or Closed(if an exception occurred) if (!state.equals(State.Opened)) { @@ -1866,22 +1926,17 @@ else if (0 == requestedPacketSize) } - // This function is used by non failover and failover cases. Even when we make a standard connection the server can provide us with its - // FO partner. - // If no FO information is available a standard connection is made. - // If the server returns a failover upon connection, we shall store the FO in our cache. - // - private void login(String primary, - String primaryInstanceName, - int primaryPortNumber, - String mirror, - FailoverInfo foActual, - int timeout, - long timerStart) throws SQLServerException { + /** + * This function is used by non failover and failover cases. Even when we make a standard connection the server can + * provide us with its FO partner. If no FO information is available a standard connection is made. If the server + * returns a failover upon connection, we shall store the FO in our cache. + */ + private void login(String primary, String primaryInstanceName, int primaryPortNumber, String mirror, + FailoverInfo foActual, int timeout, long timerStart) throws SQLServerException { // standardLogin would be false only for db mirroring scenarios. It would be true // for all other cases, including multiSubnetFailover final boolean isDBMirroring = null != mirror || null != foActual; - int sleepInterval = 100; // milliseconds to sleep (back off) between attempts. + int sleepInterval = 100; // milliseconds to sleep (back off) between attempts. long timeoutUnitInterval; boolean useFailoverHost = false; @@ -1894,8 +1949,7 @@ private void login(String primary, if (null != foActual) { tempFailover = foActual; useFailoverHost = foActual.getUseFailoverPartner(); - } - else { + } else { if (isDBMirroring) // Create a temporary class with the mirror info from the user tempFailover = new FailoverInfo(mirror, this, false); @@ -1912,17 +1966,16 @@ private void login(String primary, if (0 == timeout) { timeout = SQLServerDriverIntProperty.LOGIN_TIMEOUT.getDefaultValue(); } - long timerTimeout = timeout * 1000L; // ConnectTimeout is in seconds, we need timer millis + long timerTimeout = timeout * 1000L; // ConnectTimeout is in seconds, we need timer millis timerExpire = timerStart + timerTimeout; - // For non-dbmirroring, non-tnir and non-multisubnetfailover scenarios, full time out would be used as time slice. + // For non-dbmirroring, non-tnir and non-multisubnetfailover scenarios, full time out would be used as time + // slice. if (isDBMirroring || useParallel) { timeoutUnitInterval = (long) (TIMEOUTSTEP * timerTimeout); - } - else if (useTnir) { + } else if (useTnir) { timeoutUnitInterval = (long) (TIMEOUTSTEP_TNIR * timerTimeout); - } - else { + } else { timeoutUnitInterval = timerTimeout; } intervalExpire = timerStart + timeoutUnitInterval; @@ -1931,8 +1984,8 @@ else if (useTnir) { long intervalExpireFullTimeout = timerStart + timerTimeout; if (connectionlogger.isLoggable(Level.FINER)) { - connectionlogger.finer( - toString() + " Start time: " + timerStart + " Time out time: " + timerExpire + " Timeout Unit Interval: " + timeoutUnitInterval); + connectionlogger.finer(toString() + " Start time: " + timerStart + " Time out time: " + timerExpire + + " Timeout Unit Interval: " + timeoutUnitInterval); } // Initialize loop variables @@ -1961,23 +2014,23 @@ else if (useTnir) { currentFOPlaceHolder = tempFailover.failoverPermissionCheck(this, integratedSecurity); } currentConnectPlaceHolder = currentFOPlaceHolder; - } - else { + } else { if (routingInfo != null) { currentPrimaryPlaceHolder = routingInfo; routingInfo = null; - } - else if (null == currentPrimaryPlaceHolder) { - currentPrimaryPlaceHolder = primaryPermissionCheck(primary, primaryInstanceName, primaryPortNumber); + } else if (null == currentPrimaryPlaceHolder) { + currentPrimaryPlaceHolder = primaryPermissionCheck(primary, primaryInstanceName, + primaryPortNumber); } currentConnectPlaceHolder = currentPrimaryPlaceHolder; } // logging code if (connectionlogger.isLoggable(Level.FINE)) { - connectionlogger.fine(toString() + " This attempt server name: " + currentConnectPlaceHolder.getServerName() + " port: " - + currentConnectPlaceHolder.getPortNumber() + " InstanceName: " + currentConnectPlaceHolder.getInstanceName() - + " useParallel: " + useParallel); + connectionlogger + .fine(toString() + " This attempt server name: " + currentConnectPlaceHolder.getServerName() + + " port: " + currentConnectPlaceHolder.getPortNumber() + " InstanceName: " + + currentConnectPlaceHolder.getInstanceName() + " useParallel: " + useParallel); connectionlogger.fine(toString() + " This attempt endtime: " + intervalExpire); connectionlogger.fine(toString() + " This attempt No: " + attemptNumber); } @@ -1986,12 +2039,13 @@ else if (null == currentPrimaryPlaceHolder) { // Attempt login. // use Place holder to make sure that the failoverdemand is done. - connectHelper(currentConnectPlaceHolder, TimerRemaining(intervalExpire), timeout, useParallel, useTnir, (0 == attemptNumber), // Is - // this - // the - // TNIR - // first - // attempt + connectHelper(currentConnectPlaceHolder, TimerRemaining(intervalExpire), timeout, useParallel, useTnir, + (0 == attemptNumber), // Is + // this + // the + // TNIR + // first + // attempt TimerRemaining(intervalExpireFullTimeout)); // Only used when host resolves to >64 IPs if (isRoutedInCurrentAttempt) { @@ -2032,34 +2086,47 @@ else if (null == currentPrimaryPlaceHolder) { useParallel = false; useTnir = false; - // When connection is routed for read only application, remaining timer duration is used as a one full interval + // When connection is routed for read only application, remaining timer duration is used as a one + // full interval intervalExpire = timerExpire; // if timeout expired, throw. if (timerHasExpired(timerExpire)) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_tcpipConnectionFailed")); - Object[] msgArgs = {currentConnectPlaceHolder.getServerName(), Integer.toString(currentConnectPlaceHolder.getPortNumber()), + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_tcpipConnectionFailed")); + Object[] msgArgs = {currentConnectPlaceHolder.getServerName(), + Integer.toString(currentConnectPlaceHolder.getPortNumber()), SQLServerException.getErrString("R_timedOutBeforeRouting")}; String msg = form.format(msgArgs); terminate(SQLServerException.DRIVER_ERROR_UNSUPPORTED_CONFIG, msg); - } - else { + } else { continue; } - } - else + } else break; // leave the while loop -- we've successfully connected - } - catch (SQLServerException sqlex) { + } catch (SQLServerException sqlex) { if ((SQLServerException.LOGON_FAILED == sqlex.getErrorCode()) // actual logon failed, i.e. bad password - || (SQLServerException.PASSWORD_EXPIRED == sqlex.getErrorCode()) // actual logon failed, i.e. password isExpired - || (SQLServerException.USER_ACCOUNT_LOCKED == sqlex.getErrorCode()) // actual logon failed, i.e. user account locked - || (SQLServerException.DRIVER_ERROR_INVALID_TDS == sqlex.getDriverErrorCode()) // invalid TDS received from server - || (SQLServerException.DRIVER_ERROR_SSL_FAILED == sqlex.getDriverErrorCode()) // failure negotiating SSL - || (SQLServerException.DRIVER_ERROR_INTERMITTENT_TLS_FAILED == sqlex.getDriverErrorCode()) // failure TLS1.2 - || (SQLServerException.DRIVER_ERROR_UNSUPPORTED_CONFIG == sqlex.getDriverErrorCode()) // unsupported configuration (e.g. - // Sphinx, invalid packet size, etc.) - || (SQLServerException.ERROR_SOCKET_TIMEOUT == sqlex.getDriverErrorCode()) // socket timeout ocurred + || (SQLServerException.PASSWORD_EXPIRED == sqlex.getErrorCode()) // actual logon failed, i.e. + // password isExpired + || (SQLServerException.USER_ACCOUNT_LOCKED == sqlex.getErrorCode()) // actual logon failed, i.e. + // user account locked + || (SQLServerException.DRIVER_ERROR_INVALID_TDS == sqlex.getDriverErrorCode()) // invalid TDS + // received from + // server + || (SQLServerException.DRIVER_ERROR_SSL_FAILED == sqlex.getDriverErrorCode()) // failure + // negotiating SSL + || (SQLServerException.DRIVER_ERROR_INTERMITTENT_TLS_FAILED == sqlex.getDriverErrorCode()) // failure + // TLS1.2 + || (SQLServerException.DRIVER_ERROR_UNSUPPORTED_CONFIG == sqlex.getDriverErrorCode()) // unsupported + // configuration + // (e.g. + // Sphinx, + // invalid + // packet + // size, + // etc.) + || (SQLServerException.ERROR_SOCKET_TIMEOUT == sqlex.getDriverErrorCode()) // socket timeout + // ocurred || timerHasExpired(timerExpire)// no more time to try again || (state.equals(State.Connected) && !isDBMirroring) // for non-dbmirroring cases, do not retry after tcp socket connection succeeds @@ -2068,15 +2135,15 @@ else if (null == currentPrimaryPlaceHolder) { // close the connection and throw the error back close(); throw sqlex; - } - else { + } else { // Close the TDS channel from the failed connection attempt so that we don't // hold onto network resources any longer than necessary. if (null != tdsChannel) tdsChannel.close(); } - // For standard connections and MultiSubnetFailover connections, change the sleep interval after every attempt. + // For standard connections and MultiSubnetFailover connections, change the sleep interval after every + // attempt. // For DB Mirroring, we only sleep after every other attempt. if (!isDBMirroring || 1 == attemptNumber % 2) { // Check sleep interval to make sure we won't exceed the timeout @@ -2099,8 +2166,7 @@ else if (null == currentPrimaryPlaceHolder) { } try { Thread.sleep(sleepInterval); - } - catch (InterruptedException e) { + } catch (InterruptedException e) { // re-interrupt the current thread, in order to restore the thread's interrupt status. Thread.currentThread().interrupt(); } @@ -2112,11 +2178,9 @@ else if (null == currentPrimaryPlaceHolder) { if (useParallel) { intervalExpire = System.currentTimeMillis() + (timeoutUnitInterval * (attemptNumber + 1)); - } - else if (isDBMirroring) { + } else if (isDBMirroring) { intervalExpire = System.currentTimeMillis() + (timeoutUnitInterval * ((attemptNumber / 2) + 1)); - } - else if (useTnir) { + } else if (useTnir) { long timeSlice = timeoutUnitInterval * (1 << attemptNumber); // In case the timeout for the first slice is less than 500 ms then bump it up to 500 ms @@ -2125,11 +2189,11 @@ else if (useTnir) { } intervalExpire = System.currentTimeMillis() + timeSlice; - } - else + } else intervalExpire = timerExpire; // Due to the below condition and the timerHasExpired check in catch block, - // the multiSubnetFailover case or any other standardLogin case where timeOutInterval is full timeout would also be handled correctly. + // the multiSubnetFailover case or any other standardLogin case where timeOutInterval is full timeout would + // also be handled correctly. if (intervalExpire > timerExpire) { intervalExpire = timerExpire; } @@ -2147,7 +2211,9 @@ else if (useTnir) { curserverinfo = curserverinfo + currentFOPlaceHolder.getInstanceName(); } MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidPartnerConfiguration")); - Object[] msgArgs = {activeConnectionProperties.getProperty(SQLServerDriverStringProperty.DATABASE_NAME.toString()), curserverinfo}; + Object[] msgArgs = { + activeConnectionProperties.getProperty(SQLServerDriverStringProperty.DATABASE_NAME.toString()), + curserverinfo}; terminate(SQLServerException.DRIVER_ERROR_UNSUPPORTED_CONFIG, form.format(msgArgs)); } @@ -2166,29 +2232,31 @@ else if (useTnir) { if (null == tempFailover) tempFailover = new FailoverInfo(failoverPartnerServerProvided, this, false); - // if the failover is not from the map already out this in the map, if it is from the map just make sure that we change the + // if the failover is not from the map already out this in the map, if it is from the map just make sure + // that we change the if (null != foActual) { // We must wait for CompleteLogin to finish for to have the // env change from the server to know its designated failover // partner; saved in failoverPartnerServerProvided foActual.failoverAdd(this, useFailoverHost, failoverPartnerServerProvided); - } - else { + } else { String databaseNameProperty = SQLServerDriverStringProperty.DATABASE_NAME.toString(); String instanceNameProperty = SQLServerDriverStringProperty.INSTANCE_NAME.toString(); String serverNameProperty = SQLServerDriverStringProperty.SERVER_NAME.toString(); if (connectionlogger.isLoggable(Level.FINE)) { - connectionlogger - .fine(toString() + " adding new failover info server: " + activeConnectionProperties.getProperty(serverNameProperty) - + " instance: " + activeConnectionProperties.getProperty(instanceNameProperty) + " database: " - + activeConnectionProperties.getProperty(databaseNameProperty) + " server provided failover: " - + failoverPartnerServerProvided); + connectionlogger.fine(toString() + " adding new failover info server: " + + activeConnectionProperties.getProperty(serverNameProperty) + " instance: " + + activeConnectionProperties.getProperty(instanceNameProperty) + " database: " + + activeConnectionProperties.getProperty(databaseNameProperty) + + " server provided failover: " + failoverPartnerServerProvided); } tempFailover.failoverAdd(this, useFailoverHost, failoverPartnerServerProvided); - FailoverMapSingleton.putFailoverInfo(this, primary, activeConnectionProperties.getProperty(instanceNameProperty), - activeConnectionProperties.getProperty(databaseNameProperty), tempFailover, useFailoverHost, failoverPartnerServerProvided); + FailoverMapSingleton.putFailoverInfo(this, primary, + activeConnectionProperties.getProperty(instanceNameProperty), + activeConnectionProperties.getProperty(databaseNameProperty), tempFailover, useFailoverHost, + failoverPartnerServerProvided); } } } @@ -2209,8 +2277,7 @@ void resetNonRoutingEnvchangeValues() { // This code should be similar to the code in FailOverInfo class's failoverPermissionCheck // Only difference is that this gets the instance port if the port number is zero where as failover // does not have port number available. - ServerPortPlaceHolder primaryPermissionCheck(String primary, - String primaryInstanceName, + ServerPortPlaceHolder primaryPermissionCheck(String primary, String primaryInstanceName, int primaryPortNumber) throws SQLServerException { String instancePort; // look to see primary port number is specified @@ -2224,12 +2291,12 @@ ServerPortPlaceHolder primaryPermissionCheck(String primary, primaryPortNumber = Integer.parseInt(instancePort); if ((primaryPortNumber < 0) || (primaryPortNumber > 65535)) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidPortNumber")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_invalidPortNumber")); Object[] msgArgs = {Integer.toString(primaryPortNumber)}; SQLServerException.makeFromDriverError(this, this, form.format(msgArgs), null, false); } - } - else + } else primaryPortNumber = DEFAULTPORT; } @@ -2238,13 +2305,13 @@ ServerPortPlaceHolder primaryPermissionCheck(String primary, Object[] msgArgs = {primaryPortNumber}; SQLServerException.makeFromDriverError(this, this, form.format(msgArgs), null, false); } - } - else + } else primaryPortNumber = DEFAULTPORT; } // now we have determined the right port set the connection property back - activeConnectionProperties.setProperty(SQLServerDriverIntProperty.PORT_NUMBER.toString(), String.valueOf(primaryPortNumber)); + activeConnectionProperties.setProperty(SQLServerDriverIntProperty.PORT_NUMBER.toString(), + String.valueOf(primaryPortNumber)); return new ServerPortPlaceHolder(primary, primaryPortNumber, primaryInstanceName, integratedSecurity); } @@ -2267,38 +2334,37 @@ static int TimerRemaining(long timerExpire) { } /** - * This is a helper function to connect this gets the port of the server to connect and the server name to connect and the timeout This function - * achieves one connection attempt Create a prepared statement for internal use by the driver. + * This is a helper function to connect this gets the port of the server to connect and the server name to connect + * and the timeout This function achieves one connection attempt Create a prepared statement for internal use by the + * driver. * * @param serverInfo * @param timeOutSliceInMillis - * -timeout value in milli seconds for one try + * -timeout value in milli seconds for one try * @param timeOutFullInSeconds - * - whole timeout value specified by the user in seconds + * - whole timeout value specified by the user in seconds * @param useParallel - * - It is used to indicate whether a parallel algorithm should be tried or not for resolving a hostName. Note that useParallel is set - * to false for a routed connection even if multiSubnetFailover is set to true. + * - It is used to indicate whether a parallel algorithm should be tried or not for resolving a hostName. + * Note that useParallel is set to false for a routed connection even if multiSubnetFailover is set to true. * @param useTnir * @param isTnirFirstAttempt * @param timeOutsliceInMillisForFullTimeout * @throws SQLServerException */ - private void connectHelper(ServerPortPlaceHolder serverInfo, - int timeOutsliceInMillis, - int timeOutFullInSeconds, - boolean useParallel, - boolean useTnir, - boolean isTnirFirstAttempt, + private void connectHelper(ServerPortPlaceHolder serverInfo, int timeOutsliceInMillis, int timeOutFullInSeconds, + boolean useParallel, boolean useTnir, boolean isTnirFirstAttempt, int timeOutsliceInMillisForFullTimeout) throws SQLServerException { // Make the initial tcp-ip connection. if (connectionlogger.isLoggable(Level.FINE)) { - connectionlogger.fine(toString() + " Connecting with server: " + serverInfo.getServerName() + " port: " + serverInfo.getPortNumber() - + " Timeout slice: " + timeOutsliceInMillis + " Timeout Full: " + timeOutFullInSeconds); + connectionlogger.fine(toString() + " Connecting with server: " + serverInfo.getServerName() + " port: " + + serverInfo.getPortNumber() + " Timeout slice: " + timeOutsliceInMillis + " Timeout Full: " + + timeOutFullInSeconds); } // Before opening the TDSChannel, calculate local hostname - // as the InetAddress.getLocalHost() takes more than usual time in certain OS and JVM combination, it avoids connection loss + // as the InetAddress.getLocalHost() takes more than usual time in certain OS and JVM combination, it avoids + // connection loss hostName = activeConnectionProperties.getProperty(SQLServerDriverStringProperty.WORKSTATION_ID.toString()); if (StringUtils.isEmpty(hostName)) { hostName = Util.lookupHostName(); @@ -2307,11 +2373,11 @@ private void connectHelper(ServerPortPlaceHolder serverInfo, // if the timeout is infinite slices are infinite too. tdsChannel = new TDSChannel(this); if (0 == timeOutFullInSeconds) - tdsChannel.open(serverInfo.getServerName(), serverInfo.getPortNumber(), 0, useParallel, useTnir, isTnirFirstAttempt, - timeOutsliceInMillisForFullTimeout); + tdsChannel.open(serverInfo.getServerName(), serverInfo.getPortNumber(), 0, useParallel, useTnir, + isTnirFirstAttempt, timeOutsliceInMillisForFullTimeout); else - tdsChannel.open(serverInfo.getServerName(), serverInfo.getPortNumber(), timeOutsliceInMillis, useParallel, useTnir, isTnirFirstAttempt, - timeOutsliceInMillisForFullTimeout); + tdsChannel.open(serverInfo.getServerName(), serverInfo.getPortNumber(), timeOutsliceInMillis, useParallel, + useTnir, isTnirFirstAttempt, timeOutsliceInMillisForFullTimeout); setState(State.Connected); @@ -2330,12 +2396,12 @@ private void connectHelper(ServerPortPlaceHolder serverInfo, } /** - * Negotiates prelogin information with the server + * Negotiates prelogin information with the server. */ - void Prelogin(String serverName, - int portNumber) throws SQLServerException { + void Prelogin(String serverName, int portNumber) throws SQLServerException { // Build a TDS Pre-Login packet to send to the server. - if ((!authenticationString.trim().equalsIgnoreCase(SqlAuthentication.NotSpecified.toString())) || (null != accessTokenInByte)) { + if ((!authenticationString.trim().equalsIgnoreCase(SqlAuthentication.NotSpecified.toString())) + || (null != accessTokenInByte)) { fedAuthRequiredByUser = true; } @@ -2350,8 +2416,7 @@ void Prelogin(String serverName, // we also needed to modify the offsets above, by adding 5 to each offset, // since the data session of each option is push 5 bytes behind. fedAuthOffset = 5; - } - else { + } else { messageLength = TDS.B_PRELOGIN_MESSAGE_LENGTH; fedAuthOffset = 0; } @@ -2363,9 +2428,9 @@ void Prelogin(String serverName, byte[] bufferHeader = { // Buffer Header TDS.PKT_PRELOGIN, // Message Type - TDS.STATUS_BIT_EOM, 0, messageLength, 0, 0, // SPID (not used) - 0, // Packet (not used) - 0, // Window (not used) + TDS.STATUS_BIT_EOM, 0, messageLength, 0, 0, // SPID (not used) + 0, // Packet (not used) + 0, // Window (not used) }; System.arraycopy(bufferHeader, 0, preloginRequest, preloginRequestOffset, bufferHeader.length); @@ -2377,7 +2442,8 @@ void Prelogin(String serverName, TDS.B_PRELOGIN_OPTION_ENCRYPTION, 0, (byte) (22 + fedAuthOffset), 0, 1, // B_FENCRYPTION TDS.B_PRELOGIN_OPTION_TRACEID, 0, (byte) (23 + fedAuthOffset), 0, 36, // ClientConnectionId + ActivityId }; - System.arraycopy(preloginOptionsBeforeFedAuth, 0, preloginRequest, preloginRequestOffset, preloginOptionsBeforeFedAuth.length); + System.arraycopy(preloginOptionsBeforeFedAuth, 0, preloginRequest, preloginRequestOffset, + preloginOptionsBeforeFedAuth.length); preloginRequestOffset = preloginRequestOffset + preloginOptionsBeforeFedAuth.length; if (fedAuthRequiredByUser) { @@ -2399,7 +2465,8 @@ void Prelogin(String serverName, requestedEncryptionLevel, // TRACEID Data Session (ClientConnectionId + ActivityId) - Initialize to 0 - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,}; + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,}; System.arraycopy(preloginOptionData, 0, preloginRequest, preloginRequestOffset, preloginOptionData.length); preloginRequestOffset = preloginRequestOffset + preloginOptionData.length; @@ -2420,9 +2487,9 @@ void Prelogin(String serverName, int offset; if (fedAuthRequiredByUser) { - offset = preloginRequest.length - 36 - 1; // point to the TRACEID Data Session (one more byte for fedauth data session) - } - else { + offset = preloginRequest.length - 36 - 1; // point to the TRACEID Data Session (one more byte for fedauth + // data session) + } else { offset = preloginRequest.length - 36; // point to the TRACEID Data Session } @@ -2439,7 +2506,8 @@ void Prelogin(String serverName, offset += 4; if (connectionlogger.isLoggable(Level.FINER)) { - connectionlogger.finer(toString() + " Requesting encryption level:" + TDS.getEncryptionLevel(requestedEncryptionLevel)); + connectionlogger.finer( + toString() + " Requesting encryption level:" + TDS.getEncryptionLevel(requestedEncryptionLevel)); connectionlogger.finer(toString() + " ActivityId " + activityId.toString()); } @@ -2450,13 +2518,13 @@ void Prelogin(String serverName, try { tdsChannel.write(preloginRequest, 0, preloginRequest.length); tdsChannel.flush(); - } - catch (SQLServerException e) { - connectionlogger.warning(toString() + preloginErrorLogString + " Error sending prelogin request: " + e.getMessage()); + } catch (SQLServerException e) { + connectionlogger.warning( + toString() + preloginErrorLogString + " Error sending prelogin request: " + e.getMessage()); throw e; } - ActivityCorrelator.setCurrentActivityIdSentFlag(); // indicate current ActivityId is sent + ActivityCorrelator.setCurrentActivityIdSentFlag(); // indicate current ActivityId is sent // Read the entire prelogin response int responseLength = preloginResponse.length; @@ -2467,9 +2535,9 @@ void Prelogin(String serverName, try { bytesRead = tdsChannel.read(preloginResponse, responseBytesRead, responseLength - responseBytesRead); - } - catch (SQLServerException e) { - connectionlogger.warning(toString() + preloginErrorLogString + " Error reading prelogin response: " + e.getMessage()); + } catch (SQLServerException e) { + connectionlogger.warning( + toString() + preloginErrorLogString + " Error reading prelogin response: " + e.getMessage()); throw e; } @@ -2480,11 +2548,12 @@ void Prelogin(String serverName, // (and that we don't support with this driver). if (-1 == bytesRead) { if (connectionlogger.isLoggable(Level.WARNING)) { - connectionlogger.warning( - toString() + preloginErrorLogString + " Unexpected end of prelogin response after " + responseBytesRead + " bytes read"); + connectionlogger.warning(toString() + preloginErrorLogString + + " Unexpected end of prelogin response after " + responseBytesRead + " bytes read"); } MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_tcpipConnectionFailed")); - Object[] msgArgs = {serverName, Integer.toString(portNumber), SQLServerException.getErrString("R_notSQLServer")}; + Object[] msgArgs = {serverName, Integer.toString(portNumber), + SQLServerException.getErrString("R_notSQLServer")}; terminate(SQLServerException.DRIVER_ERROR_IO_FAILED, form.format(msgArgs)); } @@ -2503,10 +2572,12 @@ void Prelogin(String serverName, // Verify that the response is actually a response... if (TDS.PKT_REPLY != preloginResponse[0]) { if (connectionlogger.isLoggable(Level.WARNING)) { - connectionlogger.warning(toString() + preloginErrorLogString + " Unexpected response type:" + preloginResponse[0]); + connectionlogger.warning(toString() + preloginErrorLogString + " Unexpected response type:" + + preloginResponse[0]); } MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_tcpipConnectionFailed")); - Object[] msgArgs = {serverName, Integer.toString(portNumber), SQLServerException.getErrString("R_notSQLServer")}; + Object[] msgArgs = {serverName, Integer.toString(portNumber), + SQLServerException.getErrString("R_notSQLServer")}; terminate(SQLServerException.DRIVER_ERROR_IO_FAILED, form.format(msgArgs)); } @@ -2515,10 +2586,12 @@ void Prelogin(String serverName, // prelogin response items easily fit into a single 4K packet. if (TDS.STATUS_BIT_EOM != (TDS.STATUS_BIT_EOM & preloginResponse[1])) { if (connectionlogger.isLoggable(Level.WARNING)) { - connectionlogger.warning(toString() + preloginErrorLogString + " Unexpected response status:" + preloginResponse[1]); + connectionlogger.warning(toString() + preloginErrorLogString + " Unexpected response status:" + + preloginResponse[1]); } MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_tcpipConnectionFailed")); - Object[] msgArgs = {serverName, Integer.toString(portNumber), SQLServerException.getErrString("R_notSQLServer")}; + Object[] msgArgs = {serverName, Integer.toString(portNumber), + SQLServerException.getErrString("R_notSQLServer")}; terminate(SQLServerException.DRIVER_ERROR_IO_FAILED, form.format(msgArgs)); } @@ -2528,11 +2601,12 @@ void Prelogin(String serverName, if (responseLength >= preloginResponse.length) { if (connectionlogger.isLoggable(Level.WARNING)) { - connectionlogger.warning(toString() + preloginErrorLogString + " Response length:" + responseLength - + " is greater than allowed length:" + preloginResponse.length); + connectionlogger.warning(toString() + preloginErrorLogString + " Response length:" + + responseLength + " is greater than allowed length:" + preloginResponse.length); } MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_tcpipConnectionFailed")); - Object[] msgArgs = {serverName, Integer.toString(portNumber), SQLServerException.getErrString("R_notSQLServer")}; + Object[] msgArgs = {serverName, Integer.toString(portNumber), + SQLServerException.getErrString("R_notSQLServer")}; terminate(SQLServerException.DRIVER_ERROR_IO_FAILED, form.format(msgArgs)); } @@ -2568,7 +2642,8 @@ void Prelogin(String serverName, throwInvalidTDS(); } - int optionOffset = Util.readUnsignedShortBigEndian(preloginResponse, responseIndex) + TDS.PACKET_HEADER_SIZE; + int optionOffset = Util.readUnsignedShortBigEndian(preloginResponse, responseIndex) + + TDS.PACKET_HEADER_SIZE; responseIndex += 2; assert optionOffset >= 0; @@ -2578,8 +2653,8 @@ void Prelogin(String serverName, if (optionOffset + optionLength > responseLength) { if (connectionlogger.isLoggable(Level.WARNING)) { - connectionlogger.warning( - toString() + " Offset:" + optionOffset + " and length:" + optionLength + " exceed response length:" + responseLength); + connectionlogger.warning(toString() + " Offset:" + optionOffset + " and length:" + optionLength + + " exceed response length:" + responseLength); } throwInvalidTDS(); } @@ -2595,7 +2670,8 @@ void Prelogin(String serverName, if (6 != optionLength) { if (connectionlogger.isLoggable(Level.WARNING)) { - connectionlogger.warning(toString() + " Version option length:" + optionLength + " is incorrect. Correct value is 6."); + connectionlogger.warning(toString() + " Version option length:" + optionLength + + " is incorrect. Correct value is 6."); } throwInvalidTDS(); } @@ -2603,16 +2679,18 @@ void Prelogin(String serverName, serverMajorVersion = preloginResponse[optionOffset]; if (serverMajorVersion < 9) { if (connectionlogger.isLoggable(Level.WARNING)) { - connectionlogger - .warning(toString() + " Server major version:" + serverMajorVersion + " is not supported by this driver."); + connectionlogger.warning(toString() + " Server major version:" + serverMajorVersion + + " is not supported by this driver."); } - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_unsupportedServerVersion")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_unsupportedServerVersion")); Object[] msgArgs = {Integer.toString(preloginResponse[optionOffset])}; terminate(SQLServerException.DRIVER_ERROR_UNSUPPORTED_CONFIG, form.format(msgArgs)); } if (connectionlogger.isLoggable(Level.FINE)) - connectionlogger.fine(toString() + " Server returned major version:" + preloginResponse[optionOffset]); + connectionlogger + .fine(toString() + " Server returned major version:" + preloginResponse[optionOffset]); receivedVersionOption = true; break; @@ -2627,8 +2705,8 @@ void Prelogin(String serverName, if (1 != optionLength) { if (connectionlogger.isLoggable(Level.WARNING)) { - connectionlogger - .warning(toString() + " Encryption option length:" + optionLength + " is incorrect. Correct value is 1."); + connectionlogger.warning(toString() + " Encryption option length:" + optionLength + + " is incorrect. Correct value is 1."); } throwInvalidTDS(); } @@ -2637,33 +2715,40 @@ void Prelogin(String serverName, // If the server did not return a valid encryption level, terminate the connection. if (TDS.ENCRYPT_OFF != negotiatedEncryptionLevel && TDS.ENCRYPT_ON != negotiatedEncryptionLevel - && TDS.ENCRYPT_REQ != negotiatedEncryptionLevel && TDS.ENCRYPT_NOT_SUP != negotiatedEncryptionLevel) { + && TDS.ENCRYPT_REQ != negotiatedEncryptionLevel + && TDS.ENCRYPT_NOT_SUP != negotiatedEncryptionLevel) { if (connectionlogger.isLoggable(Level.WARNING)) { - connectionlogger.warning(toString() + " Server returned " + TDS.getEncryptionLevel(negotiatedEncryptionLevel)); + connectionlogger.warning(toString() + " Server returned " + + TDS.getEncryptionLevel(negotiatedEncryptionLevel)); } throwInvalidTDS(); } if (connectionlogger.isLoggable(Level.FINER)) - connectionlogger.finer(toString() + " Negotiated encryption level:" + TDS.getEncryptionLevel(negotiatedEncryptionLevel)); + connectionlogger.finer(toString() + " Negotiated encryption level:" + + TDS.getEncryptionLevel(negotiatedEncryptionLevel)); // If we requested SSL encryption and the server does not support it, then terminate the connection. if (TDS.ENCRYPT_ON == requestedEncryptionLevel && TDS.ENCRYPT_ON != negotiatedEncryptionLevel && TDS.ENCRYPT_REQ != negotiatedEncryptionLevel) { - terminate(SQLServerException.DRIVER_ERROR_SSL_FAILED, SQLServerException.getErrString("R_sslRequiredNoServerSupport")); + terminate(SQLServerException.DRIVER_ERROR_SSL_FAILED, + SQLServerException.getErrString("R_sslRequiredNoServerSupport")); } // If we say we don't support SSL and the server doesn't accept unencrypted connections, // then terminate the connection. - if (TDS.ENCRYPT_NOT_SUP == requestedEncryptionLevel && TDS.ENCRYPT_NOT_SUP != negotiatedEncryptionLevel) { + if (TDS.ENCRYPT_NOT_SUP == requestedEncryptionLevel + && TDS.ENCRYPT_NOT_SUP != negotiatedEncryptionLevel) { // If the server required an encrypted connection then terminate with an appropriate error. if (TDS.ENCRYPT_REQ == negotiatedEncryptionLevel) - terminate(SQLServerException.DRIVER_ERROR_SSL_FAILED, SQLServerException.getErrString("R_sslRequiredByServer")); + terminate(SQLServerException.DRIVER_ERROR_SSL_FAILED, + SQLServerException.getErrString("R_sslRequiredByServer")); if (connectionlogger.isLoggable(Level.WARNING)) { - connectionlogger - .warning(toString() + " Client requested encryption level: " + TDS.getEncryptionLevel(requestedEncryptionLevel) - + " Server returned unexpected encryption level: " + TDS.getEncryptionLevel(negotiatedEncryptionLevel)); + connectionlogger.warning(toString() + " Client requested encryption level: " + + TDS.getEncryptionLevel(requestedEncryptionLevel) + + " Server returned unexpected encryption level: " + + TDS.getEncryptionLevel(negotiatedEncryptionLevel)); } throwInvalidTDS(); } @@ -2673,17 +2758,21 @@ void Prelogin(String serverName, // Only 0x00 and 0x01 are accepted values from the server. if (0 != preloginResponse[optionOffset] && 1 != preloginResponse[optionOffset]) { if (connectionlogger.isLoggable(Level.SEVERE)) { - connectionlogger.severe(toString() + " Server sent an unexpected value for FedAuthRequired PreLogin Option. Value was " + connectionlogger.severe(toString() + + " Server sent an unexpected value for FedAuthRequired PreLogin Option. Value was " + preloginResponse[optionOffset]); } - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_FedAuthRequiredPreLoginResponseInvalidValue")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_FedAuthRequiredPreLoginResponseInvalidValue")); throw new SQLServerException(form.format(new Object[] {preloginResponse[optionOffset]}), null); } - // We must NOT use the response for the FEDAUTHREQUIRED PreLogin option, if the connection string option + // We must NOT use the response for the FEDAUTHREQUIRED PreLogin option, if the connection string + // option // was not using the new Authentication keyword or in other words, if Authentication=NotSpecified // Or AccessToken is not null, mean token based authentication is used. - if (((null != authenticationString) && (!authenticationString.equalsIgnoreCase(SqlAuthentication.NotSpecified.toString()))) + if (((null != authenticationString) + && (!authenticationString.equalsIgnoreCase(SqlAuthentication.NotSpecified.toString()))) || (null != accessTokenInByte)) { fedAuthRequiredPreLoginResponse = (preloginResponse[optionOffset] == 1); } @@ -2698,7 +2787,8 @@ void Prelogin(String serverName, if (!receivedVersionOption || TDS.ENCRYPT_INVALID == negotiatedEncryptionLevel) { if (connectionlogger.isLoggable(Level.WARNING)) { - connectionlogger.warning(toString() + " Prelogin response is missing version and/or encryption option."); + connectionlogger + .warning(toString() + " Prelogin response is missing version and/or encryption option."); } throwInvalidTDS(); } @@ -2718,27 +2808,25 @@ final void throwInvalidTDSToken(String tokenName) throws SQLServerException { /** * Terminates the connection and throws an exception detailing the reason for termination. * - * This method is similar to SQLServerException.makeFromDriverError, except that it always terminates the connection, and does so with the - * appropriate state code. + * This method is similar to SQLServerException.makeFromDriverError, except that it always terminates the + * connection, and does so with the appropriate state code. */ - final void terminate(int driverErrorCode, - String message) throws SQLServerException { + final void terminate(int driverErrorCode, String message) throws SQLServerException { terminate(driverErrorCode, message, null); } - final void terminate(int driverErrorCode, - String message, - Throwable throwable) throws SQLServerException { + final void terminate(int driverErrorCode, String message, Throwable throwable) throws SQLServerException { String state = this.state.equals(State.Opened) ? SQLServerException.EXCEPTION_XOPEN_CONNECTION_FAILURE - : SQLServerException.EXCEPTION_XOPEN_CONNECTION_CANT_ESTABLISH; + : SQLServerException.EXCEPTION_XOPEN_CONNECTION_CANT_ESTABLISH; if (!xopenStates) state = SQLServerException.mapFromXopen(state); - SQLServerException ex = new SQLServerException(this, SQLServerException.checkAndAppendClientConnId(message, this), state, // X/Open or SQL99 - // SQLState - 0, // database error number (0 -> driver error) - true); // include stack trace in log + SQLServerException ex = new SQLServerException(this, + SQLServerException.checkAndAppendClientConnId(message, this), state, // X/Open or SQL99 + // SQLState + 0, // database error number (0 -> driver error) + true); // include stack trace in log if (null != throwable) ex.initCause(throwable); @@ -2758,7 +2846,7 @@ final void terminate(int driverErrorCode, * Executes a command through the scheduler. * * @param newCommand - * the command to execute + * the command to execute */ boolean executeCommand(TDSCommand newCommand) throws SQLServerException { synchronized (schedulerLock) { @@ -2779,8 +2867,7 @@ boolean executeCommand(TDSCommand newCommand) throws SQLServerException { boolean commandComplete = false; try { commandComplete = newCommand.execute(tdsChannel.getWriter(), tdsChannel.getReader(newCommand)); - } - finally { + } finally { // We should never displace an existing currentCommand // assert null == currentCommand; @@ -2806,13 +2893,11 @@ void resetCurrentCommand() throws SQLServerException { /* * Executes a connection-level command */ - private void connectionCommand(String sql, - String logContext) throws SQLServerException { + private void connectionCommand(String sql, String logContext) throws SQLServerException { final class ConnectionCommand extends UninterruptableTDSCommand { final String sql; - ConnectionCommand(String sql, - String logContext) { + ConnectionCommand(String sql, String logContext) { super(logContext); this.sql = sql; } @@ -2840,10 +2925,10 @@ private String sqlStatementToInitialize() { } /** - * Return the syntax to set the database calatog to use. + * Sets the syntax to set the database calatog to use. * * @param sDB - * the new catalog + * the new catalog * @return the required syntax */ void setCatalogName(String sDB) { @@ -2855,7 +2940,7 @@ void setCatalogName(String sDB) { } /** - * Return the syntax to set the database isolation level. + * Returns the syntax to set the database isolation level. * * @return the required syntax */ @@ -2893,7 +2978,7 @@ String sqlStatementToSetTransactionIsolationLevel() throws SQLServerException { } /** - * Return the syntax to set the database commit mode. + * Returns the syntax to set the database commit mode. * * @return the required syntax */ @@ -2952,7 +3037,8 @@ public void setAutoCommit(boolean newAutoCommitMode) throws SQLServerException { commitPendingTransaction = "IF @@TRANCOUNT > 0 COMMIT TRAN "; if (connectionlogger.isLoggable(Level.FINER)) { - connectionlogger.finer(toString() + " Autocommitmode current :" + databaseAutoCommitMode + " new: " + newAutoCommitMode); + connectionlogger.finer( + toString() + " Autocommitmode current :" + databaseAutoCommitMode + " new: " + newAutoCommitMode); } rolledBackTransaction = false; @@ -2997,9 +3083,9 @@ public void rollback() throws SQLServerException { checkClosed(); if (databaseAutoCommitMode) { - SQLServerException.makeFromDriverError(this, this, SQLServerException.getErrString("R_cantInvokeRollback"), null, true); - } - else + SQLServerException.makeFromDriverError(this, this, SQLServerException.getErrString("R_cantInvokeRollback"), + null, true); + } else connectionCommand("IF @@TRANCOUNT > 0 ROLLBACK TRAN", "Connection.rollback"); loggerExternal.exiting(getClassNameLogging(), "rollback"); } @@ -3024,8 +3110,7 @@ public void abort(Executor executor) throws SQLException { try { SQLPermission perm = new SQLPermission(callAbortPerm); secMgr.checkPermission(perm); - } - catch (SecurityException ex) { + } catch (SecurityException ex) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_permissionDenied")); Object[] msgArgs = {callAbortPerm}; SQLServerException.makeFromDriverError(this, this, form.format(msgArgs), null, true); @@ -3034,7 +3119,7 @@ public void abort(Executor executor) throws SQLException { setState(State.Closed); - if (null != tdsChannel) + if (null != tdsChannel && null != executor) executor.execute(() -> tdsChannel.close()); loggerExternal.exiting(getClassNameLogging(), "abort"); @@ -3205,8 +3290,7 @@ private void addWarning(String warningString) { if (null == sqlWarnings) { sqlWarnings = warning; - } - else { + } else { sqlWarnings.setNextWarning(warning); } } @@ -3224,10 +3308,10 @@ public void clearWarnings() throws SQLServerException { // --------------------------JDBC 2.0----------------------------- @Override - public Statement createStatement(int resultSetType, - int resultSetConcurrency) throws SQLServerException { + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLServerException { if (loggerExternal.isLoggable(Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "createStatement", new Object[] {resultSetType, resultSetConcurrency}); + loggerExternal.entering(getClassNameLogging(), "createStatement", + new Object[] {resultSetType, resultSetConcurrency}); checkClosed(); Statement st = new SQLServerStatement(this, resultSetType, resultSetConcurrency, SQLServerStatementColumnEncryptionSetting.UseConnectionSetting); @@ -3239,11 +3323,11 @@ public Statement createStatement(int resultSetType, } @Override - public PreparedStatement prepareStatement(String sql, - int resultSetType, + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLServerException { if (loggerExternal.isLoggable(Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "prepareStatement", new Object[] {sql, resultSetType, resultSetConcurrency}); + loggerExternal.entering(getClassNameLogging(), "prepareStatement", + new Object[] {sql, resultSetType, resultSetConcurrency}); checkClosed(); PreparedStatement st = new SQLServerPreparedStatement(this, sql, resultSetType, resultSetConcurrency, @@ -3256,16 +3340,15 @@ public PreparedStatement prepareStatement(String sql, return st; } - private PreparedStatement prepareStatement(String sql, - int resultSetType, - int resultSetConcurrency, + private PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException { if (loggerExternal.isLoggable(Level.FINER)) loggerExternal.entering(getClassNameLogging(), "prepareStatement", new Object[] {sql, resultSetType, resultSetConcurrency, stmtColEncSetting}); checkClosed(); - PreparedStatement st = new SQLServerPreparedStatement(this, sql, resultSetType, resultSetConcurrency, stmtColEncSetting); + PreparedStatement st = new SQLServerPreparedStatement(this, sql, resultSetType, resultSetConcurrency, + stmtColEncSetting); if (requestStarted) { addOpenStatement(st); @@ -3276,11 +3359,11 @@ private PreparedStatement prepareStatement(String sql, } @Override - public CallableStatement prepareCall(String sql, - int resultSetType, + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLServerException { if (loggerExternal.isLoggable(Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "prepareCall", new Object[] {sql, resultSetType, resultSetConcurrency}); + loggerExternal.entering(getClassNameLogging(), "prepareCall", + new Object[] {sql, resultSetType, resultSetConcurrency}); checkClosed(); CallableStatement st = new SQLServerCallableStatement(this, sql, resultSetType, resultSetConcurrency, @@ -3323,7 +3406,8 @@ public java.util.Map> getTypeMap() throws SQLServerException { int writeAEFeatureRequest(boolean write, TDSWriter tdsWriter) throws SQLServerException /* if false just calculates the length */ { - // This includes the length of the terminator byte. If there are other extension features, re-adjust accordingly. + // This includes the length of the terminator byte. If there are other extension features, re-adjust + // accordingly. int len = 6; // (1byte = featureID, 4bytes = featureData length, 1 bytes = Version) if (write) { @@ -3334,12 +3418,11 @@ int writeAEFeatureRequest(boolean write, return len; } - int writeFedAuthFeatureRequest(boolean write, - TDSWriter tdsWriter, - FederatedAuthenticationFeatureExtensionData fedAuthFeatureExtensionData) throws SQLServerException { /* - * if false just calculates the - * length - */ + // if false just calculates the length + + int writeFedAuthFeatureRequest(boolean write, TDSWriter tdsWriter, + FederatedAuthenticationFeatureExtensionData fedAuthFeatureExtensionData) throws SQLServerException { + assert (fedAuthFeatureExtensionData.libraryType == TDS.TDS_FEDAUTH_LIBRARY_ADAL || fedAuthFeatureExtensionData.libraryType == TDS.TDS_FEDAUTH_LIBRARY_SECURITYTOKEN); @@ -3348,19 +3431,21 @@ int writeFedAuthFeatureRequest(boolean write, // set dataLen and totalLen switch (fedAuthFeatureExtensionData.libraryType) { case TDS.TDS_FEDAUTH_LIBRARY_ADAL: - dataLen = 2; // length of feature data = 1 byte for library and echo + 1 byte for workflow + dataLen = 2; // length of feature data = 1 byte for library and echo + 1 byte for workflow break; case TDS.TDS_FEDAUTH_LIBRARY_SECURITYTOKEN: assert null != fedAuthFeatureExtensionData.accessToken; - dataLen = 1 + 4 + fedAuthFeatureExtensionData.accessToken.length; // length of feature data = 1 byte for library and echo, security - // token length and sizeof(int) for token lengh itself + // length of feature data = 1 byte for library and echo, + // security token length and sizeof(int) for token length itself + dataLen = 1 + 4 + fedAuthFeatureExtensionData.accessToken.length; break; default: - assert (false); // Unrecognized library type for fedauth feature extension request" + assert (false); // Unrecognized library type for fedauth feature extension request" break; } - int totalLen = dataLen + 5; // length of feature id (1 byte), data length field (4 bytes), and feature data (dataLen) + int totalLen = dataLen + 5; // length of feature id (1 byte), data length field (4 bytes), and feature data + // (dataLen) // write feature id if (write) { @@ -3380,7 +3465,7 @@ int writeFedAuthFeatureRequest(boolean write, options |= TDS.TDS_FEDAUTH_LIBRARY_SECURITYTOKEN << 1; break; default: - assert (false); // Unrecognized library type for fedauth feature extension request + assert (false); // Unrecognized library type for fedauth feature extension request break; } @@ -3406,7 +3491,7 @@ int writeFedAuthFeatureRequest(boolean write, workflow = TDS.ADALWORKFLOW_ACTIVEDIRECTORYINTEGRATED; break; default: - assert (false); // Unrecognized Authentication type for fedauth ADAL request + assert (false); // Unrecognized Authentication type for fedauth ADAL request break; } @@ -3414,16 +3499,17 @@ int writeFedAuthFeatureRequest(boolean write, break; case TDS.TDS_FEDAUTH_LIBRARY_SECURITYTOKEN: tdsWriter.writeInt(fedAuthFeatureExtensionData.accessToken.length); - tdsWriter.writeBytes(fedAuthFeatureExtensionData.accessToken, 0, fedAuthFeatureExtensionData.accessToken.length); + tdsWriter.writeBytes(fedAuthFeatureExtensionData.accessToken, 0, + fedAuthFeatureExtensionData.accessToken.length); break; default: - assert (false); // Unrecognized FedAuthLibrary type for feature extension request + assert (false); // Unrecognized FedAuthLibrary type for feature extension request break; } } return totalLen; } - + int writeDataClassificationFeatureRequest(boolean write /* if false just calculates the length */, TDSWriter tdsWriter) throws SQLServerException { int len = 6; // 1byte = featureID, 4bytes = featureData length, 1 bytes = Version @@ -3435,7 +3521,7 @@ int writeDataClassificationFeatureRequest(boolean write /* if false just calcula } return len; // size of data written } - + int writeUTF8SupportFeatureRequest(boolean write, TDSWriter tdsWriter /* if false just calculates the length */) throws SQLServerException { int len = 5; // 1byte = featureID, 4bytes = featureData length @@ -3460,31 +3546,35 @@ final boolean doExecute() throws SQLServerException { private void logon(LogonCommand command) throws SQLServerException { SSPIAuthentication authentication = null; if (integratedSecurity && AuthenticationScheme.nativeAuthentication == intAuthScheme) - authentication = new AuthenticationJNI(this, currentConnectPlaceHolder.getServerName(), currentConnectPlaceHolder.getPortNumber()); + authentication = new AuthenticationJNI(this, currentConnectPlaceHolder.getServerName(), + currentConnectPlaceHolder.getPortNumber()); if (integratedSecurity && AuthenticationScheme.javaKerberos == intAuthScheme) { if (null != ImpersonatedUserCred) { - authentication = new KerbAuthentication(this, currentConnectPlaceHolder.getServerName(), currentConnectPlaceHolder.getPortNumber(), - ImpersonatedUserCred, isUserCreatedCredential); - } - else - authentication = new KerbAuthentication(this, currentConnectPlaceHolder.getServerName(), currentConnectPlaceHolder.getPortNumber()); + authentication = new KerbAuthentication(this, currentConnectPlaceHolder.getServerName(), + currentConnectPlaceHolder.getPortNumber(), ImpersonatedUserCred, isUserCreatedCredential); + } else + authentication = new KerbAuthentication(this, currentConnectPlaceHolder.getServerName(), + currentConnectPlaceHolder.getPortNumber()); } - // If the workflow being used is Active Directory Password or Active Directory Integrated and server's prelogin response - // for FEDAUTHREQUIRED option indicates Federated Authentication is required, we have to insert FedAuth Feature Extension + // If the workflow being used is Active Directory Password or Active Directory Integrated and server's prelogin + // response + // for FEDAUTHREQUIRED option indicates Federated Authentication is required, we have to insert FedAuth Feature + // Extension // in Login7, indicating the intent to use Active Directory Authentication Library for SQL Server. if (authenticationString.trim().equalsIgnoreCase(SqlAuthentication.ActiveDirectoryPassword.toString()) || (authenticationString.trim().equalsIgnoreCase(SqlAuthentication.ActiveDirectoryIntegrated.toString()) && fedAuthRequiredPreLoginResponse)) { federatedAuthenticationInfoRequested = true; - fedAuthFeatureExtensionData = new FederatedAuthenticationFeatureExtensionData(TDS.TDS_FEDAUTH_LIBRARY_ADAL, authenticationString, - fedAuthRequiredPreLoginResponse); + fedAuthFeatureExtensionData = new FederatedAuthenticationFeatureExtensionData(TDS.TDS_FEDAUTH_LIBRARY_ADAL, + authenticationString, fedAuthRequiredPreLoginResponse); } if (null != accessTokenInByte) { - fedAuthFeatureExtensionData = new FederatedAuthenticationFeatureExtensionData(TDS.TDS_FEDAUTH_LIBRARY_SECURITYTOKEN, - fedAuthRequiredPreLoginResponse, accessTokenInByte); - // No need any further info from the server for token based authentication. So set _federatedAuthenticationRequested to true + fedAuthFeatureExtensionData = new FederatedAuthenticationFeatureExtensionData( + TDS.TDS_FEDAUTH_LIBRARY_SECURITYTOKEN, fedAuthRequiredPreLoginResponse, accessTokenInByte); + // No need any further info from the server for token based authentication. So set + // _federatedAuthenticationRequested to true federatedAuthenticationRequested = true; } try { @@ -3500,8 +3590,7 @@ private void logon(LogonCommand command) throws SQLServerException { connectionCommand(sqlStmt, "Change Settings"); } } - } - finally { + } finally { if (integratedSecurity) { if (null != authentication) { authentication.ReleaseClientContext(); @@ -3547,8 +3636,7 @@ final void processEnvChange(TDSReader tdsReader) throws SQLServerException { // Set NEW value as new TDS packet size try { tdsPacketSize = Integer.parseInt(tdsReader.readUnicodeString(tdsReader.readUnsignedByte())); - } - catch (NumberFormatException e) { + } catch (NumberFormatException e) { tdsReader.throwInvalidTDS(); } if (connectionlogger.isLoggable(Level.FINER)) @@ -3561,8 +3649,7 @@ final void processEnvChange(TDSReader tdsReader) throws SQLServerException { try { databaseCollation = new SQLCollation(tdsReader); - } - catch (java.io.UnsupportedEncodingException e) { + } catch (java.io.UnsupportedEncodingException e) { terminate(SQLServerException.DRIVER_ERROR_INVALID_TDS, e.getMessage(), e); } @@ -3597,11 +3684,11 @@ final void processEnvChange(TDSReader tdsReader) throws SQLServerException { connectionlogger.finer(toString() + " rolled back. (DTC)"); // Do not clear the transaction descriptor if the connection is in DT. - // For a DTC transaction, a ENV_ROLLBACKTRAN token won't cleanup the xactID previously cached on the connection + // For a DTC transaction, a ENV_ROLLBACKTRAN token won't cleanup the xactID previously cached on the + // connection // because user is required to explicitly un-enlist/defect a connection from a DTC. // A ENV_DEFECTTRAN token though will clean the DTC xactID on the connection. - } - else { + } else { if (connectionlogger.isLoggable(Level.FINER)) connectionlogger.finer(toString() + " rolled back"); @@ -3656,7 +3743,8 @@ final void processEnvChange(TDSReader tdsReader) throws SQLServerException { try { routingDataValueLength = tdsReader.readUnsignedShort(); - if (routingDataValueLength <= 5)// (5 is the no of bytes in protocol + port number+ length field of server name) + if (routingDataValueLength <= 5)// (5 is the no of bytes in protocol + port number+ length field of + // server name) { throwInvalidTDS(); } @@ -3679,21 +3767,26 @@ final void processEnvChange(TDSReader tdsReader) throws SQLServerException { routingServerName = tdsReader.readUnicodeString(routingServerNameLength); assert routingServerName != null; - } - finally { + } finally { if (connectionlogger.isLoggable(Level.FINER)) { - connectionlogger.finer(toString() + " Received routing ENVCHANGE with the following values." + " routingDataValueLength:" - + routingDataValueLength + " protocol:" + routingProtocol + " portNumber:" + routingPortNumber + " serverNameLength:" - + routingServerNameLength + " serverName:" + ((routingServerName != null) ? routingServerName : "null")); + connectionlogger.finer(toString() + " Received routing ENVCHANGE with the following values." + + " routingDataValueLength:" + routingDataValueLength + " protocol:" + routingProtocol + + " portNumber:" + routingPortNumber + " serverNameLength:" + routingServerNameLength + + " serverName:" + ((routingServerName != null) ? routingServerName : "null")); } } // Check if the hostNameInCertificate needs to be updated to handle the rerouted subdomain in Azure String currentHostName = activeConnectionProperties.getProperty("hostNameInCertificate"); if (null != currentHostName && currentHostName.startsWith("*") && (null != routingServerName) /* - * skip the check for - * hostNameInCertificate if - * routingServerName is null + * skip + * the + * check + * for + * hostNameInCertificate + * if + * routingServerName + * is null */ && routingServerName.indexOf('.') != -1) { char[] currentHostNameCharArray = currentHostName.toCharArray(); @@ -3701,10 +3794,12 @@ final void processEnvChange(TDSReader tdsReader) throws SQLServerException { boolean hostNameNeedsUpdate = true; /* - * Check if routingServerName and hostNameInCertificate are from same domain by verifying each character in currentHostName from - * last until it reaches the character before the wildcard symbol (i.e. currentHostNameCharArray[1]) + * Check if routingServerName and hostNameInCertificate are from same domain by verifying each + * character in currentHostName from last until it reaches the character before the wildcard symbol + * (i.e. currentHostNameCharArray[1]) */ - for (int i = currentHostName.length() - 1, j = routingServerName.length() - 1; i > 0 && j > 0; i--, j--) { + for (int i = currentHostName.length() - 1, j = routingServerName.length() - 1; i > 0 && j > 0; + i--, j--) { if (routingServerNameCharArray[j] != currentHostNameCharArray[i]) { hostNameNeedsUpdate = false; break; @@ -3741,8 +3836,7 @@ final void processEnvChange(TDSReader tdsReader) throws SQLServerException { tdsReader.readBytes(new byte[envValueLength], 0, envValueLength); } - final void processFedAuthInfo(TDSReader tdsReader, - TDSTokenHandler tdsTokenHandler) throws SQLServerException { + final void processFedAuthInfo(TDSReader tdsReader, TDSTokenHandler tdsTokenHandler) throws SQLServerException { SqlFedAuthInfo sqlFedAuthInfo = new SqlFedAuthInfo(); tdsReader.readUnsignedByte(); // token type, 0xEE @@ -3759,7 +3853,8 @@ final void processFedAuthInfo(TDSReader tdsReader, if (connectionlogger.isLoggable(Level.SEVERE)) { connectionlogger.severe(toString() + "FEDAUTHINFO token stream length too short for CountOfInfoIDs."); } - throw new SQLServerException(SQLServerException.getErrString("R_FedAuthInfoLengthTooShortForCountOfInfoIds"), null); + throw new SQLServerException( + SQLServerException.getErrString("R_FedAuthInfoLengthTooShortForCountOfInfoIds"), null); } // read how many FedAuthInfo options there are @@ -3778,7 +3873,8 @@ final void processFedAuthInfo(TDSReader tdsReader, tdsReader.readBytes(tokenData, 0, tokenLen); if (connectionlogger.isLoggable(Level.FINER)) { - connectionlogger.fine(toString() + " Read rest of FEDAUTHINFO token stream: " + Arrays.toString(tokenData)); + connectionlogger + .fine(toString() + " Read rest of FEDAUTHINFO token stream: " + Arrays.toString(tokenData)); } // each FedAuthInfoOpt is 9 bytes: @@ -3812,7 +3908,8 @@ final void processFedAuthInfo(TDSReader tdsReader, int dataOffset = wrapped.getInt(); if (connectionlogger.isLoggable(Level.FINER)) { - connectionlogger.fine(toString() + " FedAuthInfoOpt: ID=" + id + ", DataLen=" + dataLen + ", Offset=" + dataOffset); + connectionlogger.fine(toString() + " FedAuthInfoOpt: ID=" + id + ", DataLen=" + dataLen + + ", Offset=" + dataOffset); } // offset is measured from optCount, so subtract to make offset measured @@ -3824,7 +3921,8 @@ final void processFedAuthInfo(TDSReader tdsReader, if (connectionlogger.isLoggable(Level.SEVERE)) { connectionlogger.severe(toString() + "FedAuthInfoDataOffset points to an invalid location."); } - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_FedAuthInfoInvalidOffset")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_FedAuthInfoInvalidOffset")); throw new SQLServerException(form.format(new Object[] {dataOffset}), null); } @@ -3834,8 +3932,7 @@ final void processFedAuthInfo(TDSReader tdsReader, byte[] dataArray = new byte[dataLen]; System.arraycopy(tokenData, dataOffset, dataArray, 0, dataLen); data = new String(dataArray, UTF_16LE); - } - catch (Exception e) { + } catch (Exception e) { connectionlogger.severe(toString() + "Failed to read FedAuthInfoData."); throw new SQLServerException(SQLServerException.getErrString("R_FedAuthInfoFailedToReadData"), e); } @@ -3854,17 +3951,19 @@ final void processFedAuthInfo(TDSReader tdsReader, break; default: if (connectionlogger.isLoggable(Level.FINER)) { - connectionlogger.fine(toString() + " Ignoring unknown federated authentication info option: " + id); + connectionlogger + .fine(toString() + " Ignoring unknown federated authentication info option: " + id); } break; } } - } - else { + } else { if (connectionlogger.isLoggable(Level.SEVERE)) { - connectionlogger.severe(toString() + "FEDAUTHINFO token stream is not long enough to contain the data it claims to."); + connectionlogger.severe( + toString() + "FEDAUTHINFO token stream is not long enough to contain the data it claims to."); } - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_FedAuthInfoLengthTooShortForData")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_FedAuthInfoLengthTooShortForData")); throw new SQLServerException(form.format(new Object[] {tokenLen}), null); } @@ -3874,7 +3973,8 @@ final void processFedAuthInfo(TDSReader tdsReader, if (connectionlogger.isLoggable(Level.SEVERE)) { connectionlogger.severe(toString() + "FEDAUTHINFO token stream does not contain both STSURL and SPN."); } - throw new SQLServerException(SQLServerException.getErrString("R_FedAuthInfoDoesNotContainStsurlAndSpn"), null); + throw new SQLServerException(SQLServerException.getErrString("R_FedAuthInfoDoesNotContainStsurlAndSpn"), + null); } onFedAuthInfo(sqlFedAuthInfo, tdsTokenHandler); @@ -3884,8 +3984,7 @@ final class FedAuthTokenCommand extends UninterruptableTDSCommand { TDSTokenHandler tdsTokenHandler = null; SqlFedAuthToken fedAuthToken = null; - FedAuthTokenCommand(SqlFedAuthToken fedAuthToken, - TDSTokenHandler tdsTokenHandler) { + FedAuthTokenCommand(SqlFedAuthToken fedAuthToken, TDSTokenHandler tdsTokenHandler) { super("FedAuth"); this.tdsTokenHandler = tdsTokenHandler; this.fedAuthToken = fedAuthToken; @@ -3898,14 +3997,14 @@ final boolean doExecute() throws SQLServerException { } /** - * Generates (if appropriate) and sends a Federated Authentication Access token to the server, using the Federated Authentication Info. + * Generates (if appropriate) and sends a Federated Authentication Access token to the server, using the Federated + * Authentication Info. */ - void onFedAuthInfo(SqlFedAuthInfo fedAuthInfo, - TDSTokenHandler tdsTokenHandler) throws SQLServerException { + void onFedAuthInfo(SqlFedAuthInfo fedAuthInfo, TDSTokenHandler tdsTokenHandler) throws SQLServerException { assert (null != activeConnectionProperties.getProperty(SQLServerDriverStringProperty.USER.toString()) && null != activeConnectionProperties.getProperty(SQLServerDriverStringProperty.PASSWORD.toString())) - || ((authenticationString.trim().equalsIgnoreCase(SqlAuthentication.ActiveDirectoryIntegrated.toString()) - && fedAuthRequiredPreLoginResponse)); + || ((authenticationString.trim().equalsIgnoreCase( + SqlAuthentication.ActiveDirectoryIntegrated.toString()) && fedAuthRequiredPreLoginResponse)); assert null != fedAuthInfo; attemptRefreshTokenLocked = true; @@ -3933,19 +4032,22 @@ private SqlFedAuthToken getFedAuthToken(SqlFedAuthInfo fedAuthInfo) throws SQLSe while (true) { if (authenticationString.trim().equalsIgnoreCase(SqlAuthentication.ActiveDirectoryPassword.toString())) { - fedAuthToken = SQLServerADAL4JUtils.getSqlFedAuthToken(fedAuthInfo, user, password, authenticationString); + fedAuthToken = SQLServerADAL4JUtils.getSqlFedAuthToken(fedAuthInfo, user, password, + authenticationString); // Break out of the retry loop in successful case. break; - } - else if (authenticationString.trim().equalsIgnoreCase(SqlAuthentication.ActiveDirectoryIntegrated.toString())) { + } else if (authenticationString.trim() + .equalsIgnoreCase(SqlAuthentication.ActiveDirectoryIntegrated.toString())) { // If operating system is windows and sqljdbc_auth is loaded then choose the DLL authentication. - if (System.getProperty("os.name").toLowerCase(Locale.ENGLISH).startsWith("windows") && AuthenticationJNI.isDllLoaded()) { + if (System.getProperty("os.name").toLowerCase(Locale.ENGLISH).startsWith("windows") + && AuthenticationJNI.isDllLoaded()) { try { long expirationFileTime = 0; - FedAuthDllInfo dllInfo = AuthenticationJNI.getAccessTokenForWindowsIntegrated(fedAuthInfo.stsurl, fedAuthInfo.spn, - clientConnectionId.toString(), ActiveDirectoryAuthentication.JDBC_FEDAUTH_CLIENT_ID, expirationFileTime); + FedAuthDllInfo dllInfo = AuthenticationJNI.getAccessTokenForWindowsIntegrated( + fedAuthInfo.stsurl, fedAuthInfo.spn, clientConnectionId.toString(), + ActiveDirectoryAuthentication.JDBC_FEDAUTH_CLIENT_ID, expirationFileTime); // AccessToken should not be null. assert null != dllInfo.accessTokenBytes; @@ -3958,32 +4060,35 @@ else if (authenticationString.trim().equalsIgnoreCase(SqlAuthentication.ActiveDi // Break out of the retry loop in successful case. break; - } - catch (DLLException adalException) { + } catch (DLLException adalException) { // the sqljdbc_auth.dll return -1 for errorCategory, if unable to load the adalsql.dll int errorCategory = adalException.GetCategory(); if (-1 == errorCategory) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_UnableLoadADALSqlDll")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_UnableLoadADALSqlDll")); Object[] msgArgs = {Integer.toHexString(adalException.GetState())}; throw new SQLServerException(form.format(msgArgs), null); } int millisecondsRemaining = TimerRemaining(timerExpire); - if (ActiveDirectoryAuthentication.GET_ACCESS_TOKEN_TANSISENT_ERROR != errorCategory || timerHasExpired(timerExpire) - || (sleepInterval >= millisecondsRemaining)) { + if (ActiveDirectoryAuthentication.GET_ACCESS_TOKEN_TANSISENT_ERROR != errorCategory + || timerHasExpired(timerExpire) || (sleepInterval >= millisecondsRemaining)) { String errorStatus = Integer.toHexString(adalException.GetStatus()); if (connectionlogger.isLoggable(Level.FINER)) { - connectionlogger.fine(toString() + " SQLServerConnection.getFedAuthToken.AdalException category:" + errorCategory - + " error: " + errorStatus); + connectionlogger.fine( + toString() + " SQLServerConnection.getFedAuthToken.AdalException category:" + + errorCategory + " error: " + errorStatus); } - MessageFormat form1 = new MessageFormat(SQLServerException.getErrString("R_ADALAuthenticationMiddleErrorMessage")); + MessageFormat form1 = new MessageFormat( + SQLServerException.getErrString("R_ADALAuthenticationMiddleErrorMessage")); String errorCode = Integer.toHexString(adalException.GetStatus()).toUpperCase(); Object[] msgArgs1 = {errorCode, adalException.GetState()}; - SQLServerException middleException = new SQLServerException(form1.format(msgArgs1), adalException); + SQLServerException middleException = new SQLServerException(form1.format(msgArgs1), + adalException); MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_ADALExecution")); Object[] msgArgs = {user, authenticationString}; @@ -3991,22 +4096,23 @@ else if (authenticationString.trim().equalsIgnoreCase(SqlAuthentication.ActiveDi } if (connectionlogger.isLoggable(Level.FINER)) { - connectionlogger.fine(toString() + " SQLServerConnection.getFedAuthToken sleeping: " + sleepInterval + " milliseconds."); - connectionlogger - .fine(toString() + " SQLServerConnection.getFedAuthToken remaining: " + millisecondsRemaining + " milliseconds."); + connectionlogger.fine(toString() + " SQLServerConnection.getFedAuthToken sleeping: " + + sleepInterval + " milliseconds."); + connectionlogger.fine(toString() + " SQLServerConnection.getFedAuthToken remaining: " + + millisecondsRemaining + " milliseconds."); } try { Thread.sleep(sleepInterval); - } - catch (InterruptedException e1) { + } catch (InterruptedException e1) { // re-interrupt the current thread, in order to restore the thread's interrupt status. Thread.currentThread().interrupt(); } sleepInterval = sleepInterval * 2; } } - // else choose ADAL4J for integrated authentication. This option is supported for both windows and unix, so we don't need to check the + // else choose ADAL4J for integrated authentication. This option is supported for both windows and unix, + // so we don't need to check the // OS version here. else { fedAuthToken = SQLServerADAL4JUtils.getSqlFedAuthTokenIntegrated(fedAuthInfo, authenticationString); @@ -4022,8 +4128,7 @@ else if (authenticationString.trim().equalsIgnoreCase(SqlAuthentication.ActiveDi /** * Send the access token to the server. */ - private void sendFedAuthToken(FedAuthTokenCommand fedAuthCommand, - SqlFedAuthToken fedAuthToken, + private void sendFedAuthToken(FedAuthTokenCommand fedAuthCommand, SqlFedAuthToken fedAuthToken, TDSTokenHandler tdsTokenHandler) throws SQLServerException { assert null != fedAuthToken; assert null != fedAuthToken.accessToken; @@ -4055,7 +4160,7 @@ private void sendFedAuthToken(FedAuthTokenCommand fedAuthCommand, } final void processFeatureExtAck(TDSReader tdsReader) throws SQLServerException { - tdsReader.readUnsignedByte(); // Reading FEATUREEXTACK_TOKEN 0xAE + tdsReader.readUnsignedByte(); // Reading FEATUREEXTACK_TOKEN 0xAE // read feature ID byte featureId; @@ -4072,12 +4177,10 @@ final void processFeatureExtAck(TDSReader tdsReader) throws SQLServerException { } onFeatureExtAck(featureId, data); } - } - while (featureId != TDS.FEATURE_EXT_TERMINATOR); + } while (featureId != TDS.FEATURE_EXT_TERMINATOR); } - private void onFeatureExtAck(byte featureId, - byte[] data) throws SQLServerException { + private void onFeatureExtAck(byte featureId, byte[] data) throws SQLServerException { if (null != routingInfo) { return; } @@ -4085,14 +4188,16 @@ private void onFeatureExtAck(byte featureId, switch (featureId) { case TDS.TDS_FEATURE_EXT_FEDAUTH: { if (connectionlogger.isLoggable(Level.FINER)) { - connectionlogger.fine(toString() + " Received feature extension acknowledgement for federated authentication."); + connectionlogger.fine( + toString() + " Received feature extension acknowledgement for federated authentication."); } if (!federatedAuthenticationRequested) { if (connectionlogger.isLoggable(Level.SEVERE)) { connectionlogger.severe(toString() + " Did not request federated authentication."); } - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_UnrequestedFeatureAckReceived")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_UnrequestedFeatureAckReceived")); Object[] msgArgs = {featureId}; throw new SQLServerException(form.format(msgArgs), null); } @@ -4109,16 +4214,19 @@ private void onFeatureExtAck(byte featureId, connectionlogger.severe(toString() + " Federated authentication feature extension ack for ADAL and Security Token includes extra data."); } - throw new SQLServerException(SQLServerException.getErrString("R_FedAuthFeatureAckContainsExtraData"), null); + throw new SQLServerException( + SQLServerException.getErrString("R_FedAuthFeatureAckContainsExtraData"), null); } break; default: - assert false; // Unknown _fedAuthLibrary type + assert false; // Unknown _fedAuthLibrary type if (connectionlogger.isLoggable(Level.SEVERE)) { - connectionlogger.severe(toString() + " Attempting to use unknown federated authentication library."); + connectionlogger.severe( + toString() + " Attempting to use unknown federated authentication library."); } - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_FedAuthFeatureAckUnknownLibraryType")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_FedAuthFeatureAckUnknownLibraryType")); Object[] msgArgs = {fedAuthFeatureExtensionData.libraryType}; throw new SQLServerException(form.format(msgArgs), null); } @@ -4149,7 +4257,8 @@ private void onFeatureExtAck(byte featureId, } case TDS.TDS_FEATURE_EXT_DATACLASSIFICATION: { if (connectionlogger.isLoggable(Level.FINER)) { - connectionlogger.fine(toString() + " Received feature extension acknowledgement for Data Classification."); + connectionlogger + .fine(toString() + " Received feature extension acknowledgement for Data Classification."); } if (2 != data.length) { @@ -4165,7 +4274,8 @@ private void onFeatureExtAck(byte featureId, if (connectionlogger.isLoggable(Level.SEVERE)) { connectionlogger.severe(toString() + " Invalid version number for Data Classification"); } - throw new SQLServerException(SQLServerException.getErrString("R_InvalidDataClsVersionNumber"), null); + throw new SQLServerException(SQLServerException.getErrString("R_InvalidDataClsVersionNumber"), + null); } byte enabled = data[1]; @@ -4197,16 +4307,12 @@ private void onFeatureExtAck(byte featureId, /* * Executes a DTC command */ - private void executeDTCCommand(int requestType, - byte[] payload, - String logContext) throws SQLServerException { + private void executeDTCCommand(int requestType, byte[] payload, String logContext) throws SQLServerException { final class DTCCommand extends UninterruptableTDSCommand { private final int requestType; private final byte[] payload; - DTCCommand(int requestType, - byte[] payload, - String logContext) { + DTCCommand(int requestType, byte[] payload, String logContext) { super(logContext); this.requestType = requestType; this.payload = payload; @@ -4218,8 +4324,7 @@ final boolean doExecute() throws SQLServerException { tdsWriter.writeShort((short) requestType); if (null == payload) { tdsWriter.writeShort((short) 0); - } - else { + } else { assert payload.length <= Short.MAX_VALUE; tdsWriter.writeShort((short) payload.length); tdsWriter.writeBytes(payload); @@ -4248,7 +4353,7 @@ final void JTAUnenlistConnection() throws SQLServerException { * Enlist this connection's local transaction with MS DTC * * @param cookie - * the cookie identifying the transaction + * the cookie identifying the transaction * @throws SQLServerException */ final void JTAEnlistConnection(byte cookie[]) throws SQLServerException { @@ -4265,7 +4370,7 @@ final void JTAEnlistConnection(byte cookie[]) throws SQLServerException { * Convert to a String UCS16 encoding. * * @param s - * the string + * the string * @throws SQLServerException * @return the encoded data */ @@ -4288,7 +4393,7 @@ private byte[] toUCS16(String s) throws SQLServerException { * Encrypt a password for the SQL Server logon. * * @param pwd - * the password + * the password * @return the encryption */ private byte[] encryptPassword(String pwd) { @@ -4312,11 +4417,10 @@ private byte[] encryptPassword(String pwd) { * Send a TDS 7.x logon packet. * * @param secsTimeout - * (optional) if non-zero, seconds to wait for logon to be sent. + * (optional) if non-zero, seconds to wait for logon to be sent. * @throws SQLServerException */ - private void sendLogon(LogonCommand logonCommand, - SSPIAuthentication authentication, + private void sendLogon(LogonCommand logonCommand, SSPIAuthentication authentication, FederatedAuthenticationFeatureExtensionData fedAuthFeatureExtensionData) throws SQLServerException { // TDS token handler class for processing logon responses. // @@ -4358,8 +4462,7 @@ boolean onLoginAck(TDSReader tdsReader) throws SQLServerException { return true; } - final boolean complete(LogonCommand logonCommand, - TDSReader tdsReader) throws SQLServerException { + final boolean complete(LogonCommand logonCommand, TDSReader tdsReader) throws SQLServerException { // If we have the login ack already then we're done processing. if (null != loginAckToken) return true; @@ -4392,21 +4495,24 @@ final boolean complete(LogonCommand logonCommand, // Cannot use both SSPI and FedAuth assert (!integratedSecurity) || !(federatedAuthenticationInfoRequested || federatedAuthenticationRequested); // fedAuthFeatureExtensionData provided without fed auth feature request - assert (null == fedAuthFeatureExtensionData) || (federatedAuthenticationInfoRequested || federatedAuthenticationRequested); + assert (null == fedAuthFeatureExtensionData) + || (federatedAuthenticationInfoRequested || federatedAuthenticationRequested); // Fed Auth feature requested without specifying fedAuthFeatureExtensionData. - assert (null != fedAuthFeatureExtensionData || !(federatedAuthenticationInfoRequested || federatedAuthenticationRequested)); + assert (null != fedAuthFeatureExtensionData + || !(federatedAuthenticationInfoRequested || federatedAuthenticationRequested)); String sUser = activeConnectionProperties.getProperty(SQLServerDriverStringProperty.USER.toString()); String sPwd = activeConnectionProperties.getProperty(SQLServerDriverStringProperty.PASSWORD.toString()); - String appName = activeConnectionProperties.getProperty(SQLServerDriverStringProperty.APPLICATION_NAME.toString()); + String appName = activeConnectionProperties + .getProperty(SQLServerDriverStringProperty.APPLICATION_NAME.toString()); String interfaceLibName = "Microsoft JDBC Driver " + SQLJdbcVersion.major + "." + SQLJdbcVersion.minor; - String databaseName = activeConnectionProperties.getProperty(SQLServerDriverStringProperty.DATABASE_NAME.toString()); + String databaseName = activeConnectionProperties + .getProperty(SQLServerDriverStringProperty.DATABASE_NAME.toString()); String serverName; // currentConnectPlaceHolder should not be null here. Still doing the check for extra security. if (null != currentConnectPlaceHolder) { serverName = currentConnectPlaceHolder.getServerName(); - } - else { + } else { serverName = activeConnectionProperties.getProperty(SQLServerDriverStringProperty.SERVER_NAME.toString()); } @@ -4428,8 +4534,8 @@ final boolean complete(LogonCommand logonCommand, byte appNameBytes[] = toUCS16(appName); byte serverNameBytes[] = toUCS16(serverName); byte interfaceLibNameBytes[] = toUCS16(interfaceLibName); - byte interfaceLibVersionBytes[] = {(byte) SQLJdbcVersion.build, (byte) SQLJdbcVersion.patch, (byte) SQLJdbcVersion.minor, - (byte) SQLJdbcVersion.major}; + byte interfaceLibVersionBytes[] = {(byte) SQLJdbcVersion.build, (byte) SQLJdbcVersion.patch, + (byte) SQLJdbcVersion.minor, (byte) SQLJdbcVersion.major}; byte databaseNameBytes[] = toUCS16(databaseName); byte netAddress[] = new byte[6]; int dataLen = 0; @@ -4439,24 +4545,21 @@ final boolean complete(LogonCommand logonCommand, if (serverMajorVersion >= 11) // Denali --> TDS 7.4 { tdsVersion = TDS.VER_DENALI; - } - else if (serverMajorVersion >= 10) // Katmai (10.0) & later 7.3B + } else if (serverMajorVersion >= 10) // Katmai (10.0) & later 7.3B { tdsVersion = TDS.VER_KATMAI; - } - else if (serverMajorVersion >= 9) // Yukon (9.0) --> TDS 7.2 // Prelogin disconnects anything older + } else if (serverMajorVersion >= 9) // Yukon (9.0) --> TDS 7.2 // Prelogin disconnects anything older { tdsVersion = TDS.VER_YUKON; - } - else // Shiloh (8.x) --> TDS 7.1 + } else // Shiloh (8.x) --> TDS 7.1 { assert false : "prelogin did not disconnect for the old version: " + serverMajorVersion; } TDSWriter tdsWriter = logonCommand.startRequest(TDS.PKT_LOGON70); - int len2 = TDS_LOGIN_REQUEST_BASE_LEN + hostnameBytes.length + appNameBytes.length + serverNameBytes.length + interfaceLibNameBytes.length - + databaseNameBytes.length + secBlob.length + 4;// AE is always on; + int len2 = TDS_LOGIN_REQUEST_BASE_LEN + hostnameBytes.length + appNameBytes.length + serverNameBytes.length + + interfaceLibNameBytes.length + databaseNameBytes.length + secBlob.length + 4;// AE is always on; // only add lengths of password and username if not using SSPI or requesting federated authentication info if (!integratedSecurity && !(federatedAuthenticationInfoRequested || federatedAuthenticationRequested)) { @@ -4472,9 +4575,9 @@ else if (serverMajorVersion >= 9) // Yukon (9.0) --> TDS 7.2 // Prelogin disconn // Data Classification is always enabled (by default) len2 += writeDataClassificationFeatureRequest(false, tdsWriter); - + len2 = len2 + writeUTF8SupportFeatureRequest(false, tdsWriter); - + len2 = len2 + 1; // add 1 to length because of FeatureEx terminator // Length of entire Login 7 packet @@ -4485,26 +4588,28 @@ else if (serverMajorVersion >= 9) // Yukon (9.0) --> TDS 7.2 // Prelogin disconn tdsWriter.writeInt(0); // Client process ID (0 = ??) tdsWriter.writeInt(0); // Primary server connection ID - tdsWriter.writeByte((byte) ( // OptionFlags1: + tdsWriter.writeByte((byte) ( // OptionFlags1: TDS.LOGIN_OPTION1_ORDER_X86 | // X86 byte order for numeric & datetime types TDS.LOGIN_OPTION1_CHARSET_ASCII | // ASCII character set TDS.LOGIN_OPTION1_FLOAT_IEEE_754 | // IEEE 754 floating point representation TDS.LOGIN_OPTION1_DUMPLOAD_ON | // Require dump/load BCP capabilities TDS.LOGIN_OPTION1_USE_DB_OFF | // No ENVCHANGE after USE DATABASE TDS.LOGIN_OPTION1_INIT_DB_FATAL | // Fail connection if initial database change fails - TDS.LOGIN_OPTION1_SET_LANG_ON // Warn on SET LANGUAGE stmt + TDS.LOGIN_OPTION1_SET_LANG_ON // Warn on SET LANGUAGE stmt )); - tdsWriter.writeByte((byte) ( // OptionFlags2: + tdsWriter.writeByte((byte) ( // OptionFlags2: TDS.LOGIN_OPTION2_INIT_LANG_FATAL | // Fail connection if initial language change fails - TDS.LOGIN_OPTION2_ODBC_ON | // Use ODBC defaults (ANSI_DEFAULTS ON, IMPLICIT_TRANSACTIONS OFF, TEXTSIZE inf, ROWCOUNT inf) - (integratedSecurity ? // Use integrated security if requested - TDS.LOGIN_OPTION2_INTEGRATED_SECURITY_ON : TDS.LOGIN_OPTION2_INTEGRATED_SECURITY_OFF))); + TDS.LOGIN_OPTION2_ODBC_ON | // Use ODBC defaults (ANSI_DEFAULTS ON, IMPLICIT_TRANSACTIONS OFF, TEXTSIZE + // inf, ROWCOUNT inf) + (integratedSecurity ? // Use integrated security if requested + TDS.LOGIN_OPTION2_INTEGRATED_SECURITY_ON + : TDS.LOGIN_OPTION2_INTEGRATED_SECURITY_OFF))); // TypeFlags - tdsWriter.writeByte((byte) (TDS.LOGIN_SQLTYPE_DEFAULT - | (applicationIntent != null && applicationIntent.equals(ApplicationIntent.READ_ONLY) ? TDS.LOGIN_READ_ONLY_INTENT - : TDS.LOGIN_READ_WRITE_INTENT))); + tdsWriter.writeByte((byte) (TDS.LOGIN_SQLTYPE_DEFAULT | (applicationIntent != null + && applicationIntent.equals(ApplicationIntent.READ_ONLY) ? TDS.LOGIN_READ_ONLY_INTENT + : TDS.LOGIN_READ_WRITE_INTENT))); // OptionFlags3 byte colEncSetting; @@ -4512,16 +4617,16 @@ else if (serverMajorVersion >= 9) // Yukon (9.0) --> TDS 7.2 // Prelogin disconn { colEncSetting = TDS.LOGIN_OPTION3_FEATURE_EXTENSION; } - tdsWriter.writeByte( - (byte) (TDS.LOGIN_OPTION3_DEFAULT | colEncSetting | ((serverMajorVersion >= 10) ? TDS.LOGIN_OPTION3_UNKNOWN_COLLATION_HANDLING : 0) // Accept - // unknown - // collations - // from - // Katmai - // & - // later - // servers - )); + tdsWriter.writeByte((byte) (TDS.LOGIN_OPTION3_DEFAULT | colEncSetting + | ((serverMajorVersion >= 10) ? TDS.LOGIN_OPTION3_UNKNOWN_COLLATION_HANDLING : 0) // Accept + // unknown + // collations + // from + // Katmai + // & + // later + // servers + )); tdsWriter.writeInt((byte) 0); // Client time zone tdsWriter.writeInt((byte) 0); // Client LCID @@ -4544,8 +4649,7 @@ else if (serverMajorVersion >= 9) // Yukon (9.0) --> TDS 7.2 // Prelogin disconn tdsWriter.writeShort((short) (sPwd == null ? 0 : sPwd.length())); dataLen += passwordLen; - } - else { + } else { // User and Password are null tdsWriter.writeShort((short) (0)); tdsWriter.writeShort((short) (0)); @@ -4594,13 +4698,11 @@ else if (serverMajorVersion >= 9) // Yukon (9.0) --> TDS 7.2 // Prelogin disconn if (!integratedSecurity) { tdsWriter.writeShort((short) 0); tdsWriter.writeShort((short) 0); - } - else { + } else { tdsWriter.writeShort((short) (TDS_LOGIN_REQUEST_BASE_LEN + dataLen)); if (USHRT_MAX <= secBlob.length) { tdsWriter.writeShort((short) (USHRT_MAX)); - } - else + } else tdsWriter.writeShort((short) (secBlob.length)); } @@ -4632,16 +4734,16 @@ else if (serverMajorVersion >= 9) // Yukon (9.0) --> TDS 7.2 // Prelogin disconn } tdsWriter.setDataLoggable(true); - tdsWriter.writeBytes(appNameBytes); // application name - tdsWriter.writeBytes(serverNameBytes); // server name + tdsWriter.writeBytes(appNameBytes); // application name + tdsWriter.writeBytes(serverNameBytes); // server name // AE is always ON { tdsWriter.writeInt(aeOffset); } - tdsWriter.writeBytes(interfaceLibNameBytes); // interfaceLibName - tdsWriter.writeBytes(databaseNameBytes); // databaseName + tdsWriter.writeBytes(interfaceLibNameBytes); // interfaceLibName + tdsWriter.writeBytes(databaseNameBytes); // databaseName // Don't allow user credentials to be logged tdsWriter.setDataLoggable(false); @@ -4668,8 +4770,7 @@ else if (serverMajorVersion >= 9) // Yukon (9.0) --> TDS 7.2 // Prelogin disconn do { tdsReader = logonCommand.startResponse(); TDSParser.parse(tdsReader, logonProcessor); - } - while (!logonProcessor.complete(logonCommand, tdsReader)); + } while (!logonProcessor.complete(logonCommand, tdsReader)); } /* --------------- JDBC 3.0 ------------- */ @@ -4687,33 +4788,34 @@ private void checkValidHoldability(int holdability) throws SQLServerException { /** * Checks that the proposed statement holdability matches this connection's current holdability. * - * SQL Server doesn't support per-statement holdability, so the statement's proposed holdability must match its parent connection's. Note that - * this doesn't stop anyone from changing the holdability of the connection after creating the statement. Apps should always call - * Statement.getResultSetHoldability to check the holdability of ResultSets that would be created, and/or ResultSet.getHoldability to check the - * holdability of an existing ResultSet. + * SQL Server doesn't support per-statement holdability, so the statement's proposed holdability must match its + * parent connection's. Note that this doesn't stop anyone from changing the holdability of the connection after + * creating the statement. Apps should always call Statement.getResultSetHoldability to check the holdability of + * ResultSets that would be created, and/or ResultSet.getHoldability to check the holdability of an existing + * ResultSet. */ private void checkMatchesCurrentHoldability(int resultSetHoldability) throws SQLServerException { if (resultSetHoldability != this.holdability) { - SQLServerException.makeFromDriverError(this, this, SQLServerException.getErrString("R_sqlServerHoldability"), null, false); + SQLServerException.makeFromDriverError(this, this, + SQLServerException.getErrString("R_sqlServerHoldability"), null, false); } } @Override - public Statement createStatement(int nType, - int nConcur, - int resultSetHoldability) throws SQLServerException { - loggerExternal.entering(getClassNameLogging(), "createStatement", new Object[] {nType, nConcur, resultSetHoldability}); - Statement st = createStatement(nType, nConcur, resultSetHoldability, SQLServerStatementColumnEncryptionSetting.UseConnectionSetting); + public Statement createStatement(int nType, int nConcur, int resultSetHoldability) throws SQLServerException { + loggerExternal.entering(getClassNameLogging(), "createStatement", + new Object[] {nType, nConcur, resultSetHoldability}); + Statement st = createStatement(nType, nConcur, resultSetHoldability, + SQLServerStatementColumnEncryptionSetting.UseConnectionSetting); loggerExternal.exiting(getClassNameLogging(), "createStatement", st); return st; } @Override - public Statement createStatement(int nType, - int nConcur, - int resultSetHoldability, + public Statement createStatement(int nType, int nConcur, int resultSetHoldability, SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException { - loggerExternal.entering(getClassNameLogging(), "createStatement", new Object[] {nType, nConcur, resultSetHoldability, stmtColEncSetting}); + loggerExternal.entering(getClassNameLogging(), "createStatement", + new Object[] {nType, nConcur, resultSetHoldability, stmtColEncSetting}); checkClosed(); checkValidHoldability(resultSetHoldability); checkMatchesCurrentHoldability(resultSetHoldability); @@ -4726,11 +4828,10 @@ public Statement createStatement(int nType, } @Override - public PreparedStatement prepareStatement(java.lang.String sql, - int nType, - int nConcur, + public PreparedStatement prepareStatement(java.lang.String sql, int nType, int nConcur, int resultSetHoldability) throws SQLServerException { - loggerExternal.entering(getClassNameLogging(), "prepareStatement", new Object[] {nType, nConcur, resultSetHoldability}); + loggerExternal.entering(getClassNameLogging(), "prepareStatement", + new Object[] {nType, nConcur, resultSetHoldability}); PreparedStatement st = prepareStatement(sql, nType, nConcur, resultSetHoldability, SQLServerStatementColumnEncryptionSetting.UseConnectionSetting); loggerExternal.exiting(getClassNameLogging(), "prepareStatement", st); @@ -4738,12 +4839,10 @@ public PreparedStatement prepareStatement(java.lang.String sql, } @Override - public PreparedStatement prepareStatement(java.lang.String sql, - int nType, - int nConcur, - int resultSetHoldability, + public PreparedStatement prepareStatement(java.lang.String sql, int nType, int nConcur, int resultSetHoldability, SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException { - loggerExternal.entering(getClassNameLogging(), "prepareStatement", new Object[] {nType, nConcur, resultSetHoldability, stmtColEncSetting}); + loggerExternal.entering(getClassNameLogging(), "prepareStatement", + new Object[] {nType, nConcur, resultSetHoldability, stmtColEncSetting}); checkClosed(); checkValidHoldability(resultSetHoldability); checkMatchesCurrentHoldability(resultSetHoldability); @@ -4759,23 +4858,21 @@ public PreparedStatement prepareStatement(java.lang.String sql, } @Override - public CallableStatement prepareCall(String sql, - int nType, - int nConcur, + public CallableStatement prepareCall(String sql, int nType, int nConcur, int resultSetHoldability) throws SQLServerException { - loggerExternal.entering(getClassNameLogging(), "prepareStatement", new Object[] {nType, nConcur, resultSetHoldability}); - CallableStatement st = prepareCall(sql, nType, nConcur, resultSetHoldability, SQLServerStatementColumnEncryptionSetting.UseConnectionSetting); + loggerExternal.entering(getClassNameLogging(), "prepareStatement", + new Object[] {nType, nConcur, resultSetHoldability}); + CallableStatement st = prepareCall(sql, nType, nConcur, resultSetHoldability, + SQLServerStatementColumnEncryptionSetting.UseConnectionSetting); loggerExternal.exiting(getClassNameLogging(), "prepareCall", st); return st; } @Override - public CallableStatement prepareCall(String sql, - int nType, - int nConcur, - int resultSetHoldability, + public CallableStatement prepareCall(String sql, int nType, int nConcur, int resultSetHoldability, SQLServerStatementColumnEncryptionSetting stmtColEncSetiing) throws SQLServerException { - loggerExternal.entering(getClassNameLogging(), "prepareStatement", new Object[] {nType, nConcur, resultSetHoldability, stmtColEncSetiing}); + loggerExternal.entering(getClassNameLogging(), "prepareStatement", + new Object[] {nType, nConcur, resultSetHoldability, stmtColEncSetiing}); checkClosed(); checkValidHoldability(resultSetHoldability); checkMatchesCurrentHoldability(resultSetHoldability); @@ -4793,8 +4890,7 @@ public CallableStatement prepareCall(String sql, /* JDBC 3.0 Auto generated keys */ @Override - public PreparedStatement prepareStatement(String sql, - int flag) throws SQLServerException { + public PreparedStatement prepareStatement(String sql, int flag) throws SQLServerException { loggerExternal.entering(getClassNameLogging(), "prepareStatement", new Object[] {sql, flag}); SQLServerPreparedStatement ps = (SQLServerPreparedStatement) prepareStatement(sql, flag, @@ -4805,21 +4901,19 @@ public PreparedStatement prepareStatement(String sql, } @Override - public PreparedStatement prepareStatement(String sql, - int flag, + public PreparedStatement prepareStatement(String sql, int flag, SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException { loggerExternal.entering(getClassNameLogging(), "prepareStatement", new Object[] {sql, flag, stmtColEncSetting}); checkClosed(); - SQLServerPreparedStatement ps = (SQLServerPreparedStatement) prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, - stmtColEncSetting); + SQLServerPreparedStatement ps = (SQLServerPreparedStatement) prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, + ResultSet.CONCUR_READ_ONLY, stmtColEncSetting); ps.bRequestedGeneratedKeys = (flag == Statement.RETURN_GENERATED_KEYS); loggerExternal.exiting(getClassNameLogging(), "prepareStatement", ps); return ps; } @Override - public PreparedStatement prepareStatement(String sql, - int[] columnIndexes) throws SQLServerException { + public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLServerException { loggerExternal.entering(getClassNameLogging(), "prepareStatement", new Object[] {sql, columnIndexes}); SQLServerPreparedStatement ps = (SQLServerPreparedStatement) prepareStatement(sql, columnIndexes, SQLServerStatementColumnEncryptionSetting.UseConnectionSetting); @@ -4829,25 +4923,25 @@ public PreparedStatement prepareStatement(String sql, } @Override - public PreparedStatement prepareStatement(String sql, - int[] columnIndexes, + public PreparedStatement prepareStatement(String sql, int[] columnIndexes, SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException { - loggerExternal.entering(getClassNameLogging(), "prepareStatement", new Object[] {sql, columnIndexes, stmtColEncSetting}); + loggerExternal.entering(getClassNameLogging(), "prepareStatement", + new Object[] {sql, columnIndexes, stmtColEncSetting}); checkClosed(); if (columnIndexes == null || columnIndexes.length != 1) { - SQLServerException.makeFromDriverError(this, this, SQLServerException.getErrString("R_invalidColumnArrayLength"), null, false); + SQLServerException.makeFromDriverError(this, this, + SQLServerException.getErrString("R_invalidColumnArrayLength"), null, false); } - SQLServerPreparedStatement ps = (SQLServerPreparedStatement) prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, - stmtColEncSetting); + SQLServerPreparedStatement ps = (SQLServerPreparedStatement) prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, + ResultSet.CONCUR_READ_ONLY, stmtColEncSetting); ps.bRequestedGeneratedKeys = true; loggerExternal.exiting(getClassNameLogging(), "prepareStatement", ps); return ps; } @Override - public PreparedStatement prepareStatement(String sql, - String[] columnNames) throws SQLServerException { + public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLServerException { loggerExternal.entering(getClassNameLogging(), "prepareStatement", new Object[] {sql, columnNames}); SQLServerPreparedStatement ps = (SQLServerPreparedStatement) prepareStatement(sql, columnNames, @@ -4858,16 +4952,17 @@ public PreparedStatement prepareStatement(String sql, } @Override - public PreparedStatement prepareStatement(String sql, - String[] columnNames, + public PreparedStatement prepareStatement(String sql, String[] columnNames, SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException { - loggerExternal.entering(getClassNameLogging(), "prepareStatement", new Object[] {sql, columnNames, stmtColEncSetting}); + loggerExternal.entering(getClassNameLogging(), "prepareStatement", + new Object[] {sql, columnNames, stmtColEncSetting}); checkClosed(); if (columnNames == null || columnNames.length != 1) { - SQLServerException.makeFromDriverError(this, this, SQLServerException.getErrString("R_invalidColumnArrayLength"), null, false); + SQLServerException.makeFromDriverError(this, this, + SQLServerException.getErrString("R_invalidColumnArrayLength"), null, false); } - SQLServerPreparedStatement ps = (SQLServerPreparedStatement) prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, - stmtColEncSetting); + SQLServerPreparedStatement ps = (SQLServerPreparedStatement) prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, + ResultSet.CONCUR_READ_ONLY, stmtColEncSetting); ps.bRequestedGeneratedKeys = true; loggerExternal.exiting(getClassNameLogging(), "prepareStatement", ps); return ps; @@ -4883,7 +4978,8 @@ public void releaseSavepoint(Savepoint savepoint) throws SQLException { final private Savepoint setNamedSavepoint(String sName) throws SQLServerException { if (true == databaseAutoCommitMode) { - SQLServerException.makeFromDriverError(this, this, SQLServerException.getErrString("R_cantSetSavepoint"), null, false); + SQLServerException.makeFromDriverError(this, this, SQLServerException.getErrString("R_cantSetSavepoint"), + null, false); } SQLServerSavepoint s = new SQLServerSavepoint(this, sName); @@ -4895,8 +4991,8 @@ final private Savepoint setNamedSavepoint(String sName) throws SQLServerExceptio // This is because the server creates a nested transaction (@@TRANCOUNT = 2) rather // than just the outer transaction (@@TRANCOUNT = 1). Should this limitation ever // change, the T-SQL below should still work. - connectionCommand("IF @@TRANCOUNT = 0 BEGIN BEGIN TRAN IF @@TRANCOUNT = 2 COMMIT TRAN END SAVE TRAN " + Util.escapeSQLId(s.getLabel()), - "setSavepoint"); + connectionCommand("IF @@TRANCOUNT = 0 BEGIN BEGIN TRAN IF @@TRANCOUNT = 2 COMMIT TRAN END SAVE TRAN " + + Util.escapeSQLId(s.getLabel()), "setSavepoint"); return s; } @@ -4933,9 +5029,11 @@ public void rollback(Savepoint s) throws SQLServerException { } checkClosed(); if (true == databaseAutoCommitMode) { - SQLServerException.makeFromDriverError(this, this, SQLServerException.getErrString("R_cantInvokeRollback"), null, false); + SQLServerException.makeFromDriverError(this, this, SQLServerException.getErrString("R_cantInvokeRollback"), + null, false); } - connectionCommand("IF @@TRANCOUNT > 0 ROLLBACK TRAN " + Util.escapeSQLId(((SQLServerSavepoint) s).getLabel()), "rollbackSavepoint"); + connectionCommand("IF @@TRANCOUNT > 0 ROLLBACK TRAN " + Util.escapeSQLId(((SQLServerSavepoint) s).getLabel()), + "rollbackSavepoint"); loggerExternal.exiting(getClassNameLogging(), "rollback"); } @@ -4958,10 +5056,12 @@ public void setHoldability(int holdability) throws SQLServerException { checkClosed(); if (this.holdability != holdability) { - assert ResultSet.HOLD_CURSORS_OVER_COMMIT == holdability || ResultSet.CLOSE_CURSORS_AT_COMMIT == holdability : "invalid holdability " - + holdability; + assert ResultSet.HOLD_CURSORS_OVER_COMMIT == holdability + || ResultSet.CLOSE_CURSORS_AT_COMMIT == holdability : "invalid holdability " + holdability; - connectionCommand((holdability == ResultSet.CLOSE_CURSORS_AT_COMMIT) ? "SET CURSOR_CLOSE_ON_COMMIT ON" : "SET CURSOR_CLOSE_ON_COMMIT OFF", + connectionCommand( + (holdability == ResultSet.CLOSE_CURSORS_AT_COMMIT) ? "SET CURSOR_CLOSE_ON_COMMIT ON" + : "SET CURSOR_CLOSE_ON_COMMIT OFF", "setHoldability"); this.holdability = holdability; @@ -4979,8 +5079,7 @@ public int getNetworkTimeout() throws SQLException { int timeout = 0; try { timeout = tdsChannel.getNetworkTimeout(); - } - catch (IOException ioe) { + } catch (IOException ioe) { terminate(SQLServerException.DRIVER_ERROR_IO_FAILED, ioe.getMessage(), ioe); } @@ -4989,8 +5088,7 @@ public int getNetworkTimeout() throws SQLException { } @Override - public void setNetworkTimeout(Executor executor, - int timeout) throws SQLException { + public void setNetworkTimeout(Executor executor, int timeout) throws SQLException { loggerExternal.entering(getClassNameLogging(), "setNetworkTimeout", timeout); if (timeout < 0) { @@ -5007,8 +5105,7 @@ public void setNetworkTimeout(Executor executor, try { SQLPermission perm = new SQLPermission(SET_NETWORK_TIMEOUT_PERM); secMgr.checkPermission(perm); - } - catch (SecurityException ex) { + } catch (SecurityException ex) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_permissionDenied")); Object[] msgArgs = {SET_NETWORK_TIMEOUT_PERM}; SQLServerException.makeFromDriverError(this, this, form.format(msgArgs), null, true); @@ -5017,8 +5114,7 @@ public void setNetworkTimeout(Executor executor, try { tdsChannel.setNetworkTimeout(timeout); - } - catch (IOException ioe) { + } catch (IOException ioe) { terminate(SQLServerException.DRIVER_ERROR_IO_FAILED, ioe.getMessage(), ioe); } @@ -5040,19 +5136,18 @@ public String getSchema() throws SQLException { if (resultSet != null) { resultSet.next(); return resultSet.getString(1); + } else { + SQLServerException.makeFromDriverError(this, this, SQLServerException.getErrString("R_getSchemaError"), + null, true); } - else { - SQLServerException.makeFromDriverError(this, this, SQLServerException.getErrString("R_getSchemaError"), null, true); - } - } - catch (SQLException e) { + } catch (SQLException e) { if (isSessionUnAvailable()) { throw e; } - SQLServerException.makeFromDriverError(this, this, SQLServerException.getErrString("R_getSchemaError"), null, true); - } - finally { + SQLServerException.makeFromDriverError(this, this, SQLServerException.getErrString("R_getSchemaError"), + null, true); + } finally { if (resultSet != null) { resultSet.close(); } @@ -5080,8 +5175,7 @@ public void setSendTimeAsDatetime(boolean sendTimeAsDateTimeValue) { } @Override - public java.sql.Array createArrayOf(String typeName, - Object[] elements) throws SQLException { + public java.sql.Array createArrayOf(String typeName, Object[] elements) throws SQLException { SQLServerException.throwNotSupportedException(this, null); return null; } @@ -5115,8 +5209,7 @@ public SQLXML createSQLXML() throws SQLException { } @Override - public java.sql.Struct createStruct(String typeName, - Object[] attributes) throws SQLException { + public java.sql.Struct createStruct(String typeName, Object[] attributes) throws SQLException { SQLServerException.throwNotSupportedException(this, null); return null; } @@ -5148,8 +5241,7 @@ public void setClientInfo(Properties properties) throws SQLClientInfoException { // This function is only marked as throwing only SQLClientInfoException so the conversion is necessary try { checkClosed(); - } - catch (SQLServerException ex) { + } catch (SQLServerException ex) { SQLClientInfoException info = new SQLClientInfoException(); info.initCause(ex); throw info; @@ -5167,14 +5259,12 @@ public void setClientInfo(Properties properties) throws SQLClientInfoException { } @Override - public void setClientInfo(String name, - String value) throws SQLClientInfoException { + public void setClientInfo(String name, String value) throws SQLClientInfoException { loggerExternal.entering(getClassNameLogging(), "setClientInfo", new Object[] {name, value}); // This function is only marked as throwing only SQLClientInfoException so the conversion is necessary try { checkClosed(); - } - catch (SQLServerException ex) { + } catch (SQLServerException ex) { SQLClientInfoException info = new SQLClientInfoException(); info.initCause(ex); throw info; @@ -5188,22 +5278,24 @@ public void setClientInfo(String name, /** * Determine whether the connection is still valid. * - * The driver shall submit a query on the connection or use some other mechanism that positively verifies the connection is still valid when this - * method is called. + * The driver shall submit a query on the connection or use some other mechanism that positively verifies the + * connection is still valid when this method is called. * - * The query submitted by the driver to validate the connection shall be executed in the context of the current transaction. + * The query submitted by the driver to validate the connection shall be executed in the context of the current + * transaction. * * @param timeout - * The time in seconds to wait for the database operation used to validate the connection to complete. If the timeout period expires - * before the operation completes, this method returns false. A value of 0 indicates a timeout is not applied to the database - * operation. Note that if the value is 0, the call to isValid may block indefinitely if the connection is not valid... + * The time in seconds to wait for the database operation used to validate the connection to complete. If the + * timeout period expires before the operation completes, this method returns false. A value of 0 indicates a + * timeout is not applied to the database operation. Note that if the value is 0, the call to isValid may + * block indefinitely if the connection is not valid... * * @return true if the connection has not been closed and is still valid. * * @throws SQLException - * if the value supplied for the timeout is less than 0. + * if the value supplied for the timeout is less than 0. */ - @Override + @Override public boolean isValid(int timeout) throws SQLException { boolean isValid = false; @@ -5221,8 +5313,8 @@ public boolean isValid(int timeout) throws SQLException { return false; try { - SQLServerStatement stmt = new SQLServerStatement(this, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, - SQLServerStatementColumnEncryptionSetting.UseConnectionSetting); + SQLServerStatement stmt = new SQLServerStatement(this, ResultSet.TYPE_FORWARD_ONLY, + ResultSet.CONCUR_READ_ONLY, SQLServerStatementColumnEncryptionSetting.UseConnectionSetting); // If asked, limit the time to wait for the query to complete. if (0 != timeout) @@ -5235,8 +5327,7 @@ public boolean isValid(int timeout) throws SQLException { stmt.executeQueryInternal("SELECT 1"); stmt.close(); isValid = true; - } - catch (SQLException e) { + } catch (SQLException e) { // Do not propagate SQLExceptions from query execution or statement closure. // The connection is considered to be invalid if the statement fails to close, // even though query execution succeeded. @@ -5261,8 +5352,7 @@ public T unwrap(Class iface) throws SQLException { T t; try { t = iface.cast(this); - } - catch (ClassCastException e) { + } catch (ClassCastException e) { SQLServerException newe = new SQLServerException(e.getMessage(), e); throw newe; @@ -5282,6 +5372,7 @@ public T unwrap(Class iface) throws SQLException { private int originalServerPreparedStatementDiscardThreshold; private Boolean originalEnablePrepareOnFirstPreparedStatementCall; private String originalSCatalog; + private boolean originalUseBulkCopyForBatchInsert; private volatile SQLWarning originalSqlWarnings; private List openStatements; @@ -5299,6 +5390,7 @@ protected void beginRequestInternal() throws SQLException { originalServerPreparedStatementDiscardThreshold = getServerPreparedStatementDiscardThreshold(); originalEnablePrepareOnFirstPreparedStatementCall = getEnablePrepareOnFirstPreparedStatementCall(); originalSCatalog = sCatalog; + originalUseBulkCopyForBatchInsert = getUseBulkCopyForBatchInsert(); originalSqlWarnings = sqlWarnings; openStatements = new LinkedList(); requestStarted = true; @@ -5344,11 +5436,13 @@ protected void endRequestInternal() throws SQLException { if (!sCatalog.equals(originalSCatalog)) { setCatalog(originalSCatalog); } + if (getUseBulkCopyForBatchInsert() != originalUseBulkCopyForBatchInsert) { + setUseBulkCopyForBatchInsert(originalUseBulkCopyForBatchInsert); + } sqlWarnings = originalSqlWarnings; if (null != openStatements) { while (!openStatements.isEmpty()) { - try (Statement st = openStatements.get(0)) { - } + try (Statement st = openStatements.get(0)) {} } openStatements.clear(); } @@ -5359,17 +5453,16 @@ protected void endRequestInternal() throws SQLException { } /** - * Replace JDBC syntax parameter markets '?' with SQL Server paramter markers @p1, @p2 etc... + * Replaces JDBC syntax parameter markets '?' with SQL Server paramter markers @p1, @p2 etc... * * @param sql - * the user's SQL + * the user's SQL * @throws SQLServerException * @return the returned syntax */ static final char[] OUT = {' ', 'O', 'U', 'T'}; - String replaceParameterMarkers(String sqlSrc, - Parameter[] params, + String replaceParameterMarkers(String sqlSrc, int[] paramPositions, Parameter[] params, boolean isReturnValueSyntax) throws SQLServerException { final int MAX_PARAM_NAME_LEN = 6; char[] sqlDst = new char[sqlSrc.length() + params.length * (MAX_PARAM_NAME_LEN + OUT.length)]; @@ -5379,7 +5472,7 @@ String replaceParameterMarkers(String sqlSrc, int paramIndex = 0; while (true) { - int srcEnd = ParameterUtils.scanSQLForChar('?', sqlSrc, srcBegin); + int srcEnd = (paramIndex >= paramPositions.length) ? sqlSrc.length() : paramPositions[paramIndex]; sqlSrc.getChars(srcBegin, srcEnd, sqlDst, dstBegin); dstBegin += srcEnd - srcBegin; @@ -5404,25 +5497,22 @@ String replaceParameterMarkers(String sqlSrc, } /** - * Make a SQL Server style parameter name. + * Makes a SQL Server style parameter name. * * @param nParam - * the parameter number + * the parameter number * @param name - * the paramter name + * the paramter name * @param offset * @return int */ - static int makeParamName(int nParam, - char[] name, - int offset) { + static int makeParamName(int nParam, char[] name, int offset) { name[offset + 0] = '@'; name[offset + 1] = 'P'; if (nParam < 10) { name[offset + 2] = (char) ('0' + nParam); return 3; - } - else { + } else { if (nParam < 100) { int nBase = 2; while (true) { // make a char[] representation of the param number 2.26 @@ -5433,8 +5523,7 @@ static int makeParamName(int nParam, } nBase++; } - } - else { + } else { String sParam = "" + nParam; sParam.getChars(0, sParam.length(), name, offset + 2); return 2 + sParam.length(); @@ -5442,11 +5531,12 @@ static int makeParamName(int nParam, } } - // Notify any interested parties (e.g. pooling managers) of a ConnectionEvent activity - // on the connection. Calling notifyPooledConnection with null event will place this - // connection back in the pool. Calling notifyPooledConnection with a non-null event is - // used to notify the pooling manager that the connection is bad and should be removed - // from the pool. + /** + * Notify any interested parties (e.g. pooling managers) of a ConnectionEvent activity on the connection. Calling + * notifyPooledConnection with null event will place this connection back in the pool. Calling + * notifyPooledConnection with a non-null event is used to notify the pooling manager that the connection is bad and + * should be removed from the pool. + */ void notifyPooledConnection(SQLServerException e) { synchronized (this) { if (null != pooledConnectionParent) { @@ -5464,19 +5554,18 @@ void DetachFromPool() { } /** - * Determine the listening port of a named SQL Server instance. + * Determines the listening port of a named SQL Server instance. * * @param server - * the server name + * the server name * @param instanceName - * the instance + * the instance * @throws SQLServerException * @return the instance's port */ private static final int BROWSER_PORT = 1434; - String getInstancePort(String server, - String instanceName) throws SQLServerException { + String getInstancePort(String server, String instanceName) throws SQLServerException { String browserResult = null; DatagramSocket datagramSocket = null; String lastErrorMessage = null; @@ -5488,8 +5577,7 @@ String getInstancePort(String server, try { datagramSocket = new DatagramSocket(); datagramSocket.setSoTimeout(1000); - } - catch (SocketException socketException) { + } catch (SocketException socketException) { // Errors creating a local socket // Log the error and bail. lastErrorMessage = "Unable to create local datagram socket"; @@ -5497,13 +5585,15 @@ String getInstancePort(String server, } // Second, we need to get the IP address of the server to which we'll send the UDP request. - // This may require a DNS lookup, which may fail due to transient conditions, so retry after logging the first time. + // This may require a DNS lookup, which may fail due to transient conditions, so retry after logging the + // first time. // send UDP packet assert null != datagramSocket; try { if (multiSubnetFailover) { - // If instance name is specified along with multiSubnetFailover, we get all IPs resolved by server name + // If instance name is specified along with multiSubnetFailover, we get all IPs resolved by server + // name InetAddress[] inetAddrs = InetAddress.getAllByName(server); assert null != inetAddrs; for (InetAddress inetAddr : inetAddrs) { @@ -5511,18 +5601,18 @@ String getInstancePort(String server, try { byte sendBuffer[] = (" " + instanceName).getBytes(); sendBuffer[0] = 4; - DatagramPacket udpRequest = new DatagramPacket(sendBuffer, sendBuffer.length, inetAddr, BROWSER_PORT); + DatagramPacket udpRequest = new DatagramPacket(sendBuffer, sendBuffer.length, inetAddr, + BROWSER_PORT); datagramSocket.send(udpRequest); - } - catch (IOException ioException) { - lastErrorMessage = "Error sending SQL Server Browser Service UDP request to address: " + inetAddr + ", port: " - + BROWSER_PORT; + } catch (IOException ioException) { + lastErrorMessage = "Error sending SQL Server Browser Service UDP request to address: " + + inetAddr + ", port: " + BROWSER_PORT; throw ioException; } } - } - else { - // If instance name is not specified along with multiSubnetFailover, we resolve only the first IP for server name + } else { + // If instance name is not specified along with multiSubnetFailover, we resolve only the first IP + // for server name InetAddress inetAddr = InetAddress.getByName(server); assert null != inetAddr; @@ -5530,16 +5620,16 @@ String getInstancePort(String server, try { byte sendBuffer[] = (" " + instanceName).getBytes(); sendBuffer[0] = 4; - DatagramPacket udpRequest = new DatagramPacket(sendBuffer, sendBuffer.length, inetAddr, BROWSER_PORT); + DatagramPacket udpRequest = new DatagramPacket(sendBuffer, sendBuffer.length, inetAddr, + BROWSER_PORT); datagramSocket.send(udpRequest); - } - catch (IOException ioException) { - lastErrorMessage = "Error sending SQL Server Browser Service UDP request to address: " + inetAddr + ", port: " + BROWSER_PORT; + } catch (IOException ioException) { + lastErrorMessage = "Error sending SQL Server Browser Service UDP request to address: " + + inetAddr + ", port: " + BROWSER_PORT; throw ioException; } } - } - catch (UnknownHostException unknownHostException) { + } catch (UnknownHostException unknownHostException) { lastErrorMessage = "Unable to determine IP address of host: " + server; throw unknownHostException; } @@ -5551,22 +5641,20 @@ String getInstancePort(String server, datagramSocket.receive(udpResponse); browserResult = new String(receiveBuffer, 3, receiveBuffer.length - 3); if (connectionlogger.isLoggable(Level.FINER)) - connectionlogger.fine(toString() + " Received SSRP UDP response from IP address: " + udpResponse.getAddress().getHostAddress()); - } - catch (IOException ioException) { + connectionlogger.fine(toString() + " Received SSRP UDP response from IP address: " + + udpResponse.getAddress().getHostAddress()); + } catch (IOException ioException) { // Warn and retry lastErrorMessage = "Error receiving SQL Server Browser Service UDP response from server: " + server; throw ioException; } - } - catch (IOException ioException) { + } catch (IOException ioException) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_sqlBrowserFailed")); Object[] msgArgs = {server, instanceName, ioException.toString()}; connectionlogger.log(Level.FINE, toString() + " " + lastErrorMessage, ioException); - SQLServerException.makeFromDriverError(this, this, form.format(msgArgs), SQLServerException.EXCEPTION_XOPEN_CONNECTION_CANT_ESTABLISH, - false); - } - finally { + SQLServerException.makeFromDriverError(this, this, form.format(msgArgs), + SQLServerException.EXCEPTION_XOPEN_CONNECTION_CANT_ESTABLISH, false); + } finally { if (null != datagramSocket) datagramSocket.close(); } @@ -5576,8 +5664,8 @@ String getInstancePort(String server, if (-1 == p) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_notConfiguredToListentcpip")); Object[] msgArgs = {instanceName}; - SQLServerException.makeFromDriverError(this, this, form.format(msgArgs), SQLServerException.EXCEPTION_XOPEN_CONNECTION_CANT_ESTABLISH, - false); + SQLServerException.makeFromDriverError(this, this, form.format(msgArgs), + SQLServerException.EXCEPTION_XOPEN_CONNECTION_CANT_ESTABLISH, false); } // All went well, so return the TCP port of the SQL Server instance int p1 = p + 4; @@ -5590,28 +5678,31 @@ int getNextSavepointId() { return nNextSavePointId; } - // Returns this connection's SQLServerConnectionSecurityManager class to caller. - // Used by SQLServerPooledConnection to verify security when passing out Connection objects. + /** + * Returns this connection's SQLServerConnectionSecurityManager class to caller. Used by SQLServerPooledConnection + * to verify security when passing out Connection objects. + */ void doSecurityCheck() { assert null != currentConnectPlaceHolder; currentConnectPlaceHolder.doSecurityCheck(); } - // ColumnEncryptionKeyCache sets time-to-live for column encryption key entries in - // the column encryption key cache for the Always Encrypted feature. The default value is 2 hours. - // This variable holds the value in seconds. + /** + * Sets time-to-live for column encryption key entries in the column encryption key cache for the Always Encrypted + * feature. The default value is 2 hours. This variable holds the value in seconds. + */ private static long columnEncryptionKeyCacheTtl = TimeUnit.SECONDS.convert(2, TimeUnit.HOURS); /** - * Sets time-to-live for column encryption key entries in the column encryption key cache for the Always Encrypted feature. The default value is 2 - * hours. This variable holds the value in seconds. + * Sets time-to-live for column encryption key entries in the column encryption key cache for the Always Encrypted + * feature. The default value is 2 hours. This variable holds the value in seconds. * * @param columnEncryptionKeyCacheTTL - * The timeunit in seconds + * The timeunit in seconds * @param unit - * The Timeunit. + * The Timeunit. * @throws SQLServerException - * when an error occurs + * when an error occurs */ public static synchronized void setColumnEncryptionKeyCacheTtl(int columnEncryptionKeyCacheTTL, TimeUnit unit) throws SQLServerException { @@ -5628,17 +5719,18 @@ static synchronized long getColumnEncryptionKeyCacheTtl() { } /** - * Enqueue a discarded prepared statement handle to be clean-up on the server. + * Enqueues a discarded prepared statement handle to be clean-up on the server. * * @param statementHandle - * The prepared statement handle that should be scheduled for unprepare. + * The prepared statement handle that should be scheduled for unprepare. */ final void enqueueUnprepareStatementHandle(PreparedStatementHandle statementHandle) { if (null == statementHandle) return; if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.finer(this + ": Adding PreparedHandle to queue for un-prepare:" + statementHandle.getHandle()); + loggerExternal + .finer(this + ": Adding PreparedHandle to queue for un-prepare:" + statementHandle.getHandle()); // Add the new handle to the discarding queue and find out current # enqueued. this.discardedPreparedStatementHandles.add(statementHandle); @@ -5656,7 +5748,7 @@ public void closeUnreferencedPreparedStatementHandles() { } /** - * Remove references to outstanding un-prepare requests. Should be run when connection is closed. + * Removes references to outstanding un-prepare requests. Should be run when connection is closed. */ private final void cleanupPreparedStatementDiscardActions() { discardedPreparedStatementHandles.clear(); @@ -5694,10 +5786,12 @@ final boolean isPreparedStatementUnprepareBatchingEnabled() { } /** - * Cleans-up discarded prepared statement handles on the server using batched un-prepare actions if the batching threshold has been reached. + * Cleans up discarded prepared statement handles on the server using batched un-prepare actions if the batching + * threshold has been reached. * * @param force - * When force is set to true we ignore the current threshold for if the discard actions should run and run them anyway. + * When force is set to true we ignore the current threshold for if the discard actions should run and run + * them anyway. */ final void unprepareUnreferencedPreparedStatementHandles(boolean force) { // Skip out if session is unavailable to adhere to previous non-batched behavior. @@ -5722,8 +5816,8 @@ final void unprepareUnreferencedPreparedStatementHandles(boolean force) { while (null != (statementHandle = discardedPreparedStatementHandles.poll())) { ++handlesRemoved; - sql.append(statementHandle.isDirectSql() ? "EXEC sp_unprepare " : "EXEC sp_cursorunprepare ").append(statementHandle.getHandle()) - .append(';'); + sql.append(statementHandle.isDirectSql() ? "EXEC sp_unprepare " : "EXEC sp_cursorunprepare ") + .append(statementHandle.getHandle()).append(';'); } try { @@ -5734,8 +5828,7 @@ final void unprepareUnreferencedPreparedStatementHandles(boolean force) { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.finer(this + ": Finished un-preparing handle count:" + handlesRemoved); - } - catch (SQLException e) { + } catch (SQLException e) { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.log(Level.FINER, this + ": Error batch-closing at least one prepared handle", e); } @@ -5773,7 +5866,8 @@ public int getStatementHandleCacheEntryCount() { @Override public boolean isStatementPoolingEnabled() { - return null != preparedStatementHandleCache && 0 < this.getStatementPoolingCacheSize() && !this.getDisableStatementPooling(); + return null != preparedStatementHandleCache && 0 < this.getStatementPoolingCacheSize() + && !this.getDisableStatementPooling(); } @Override @@ -5792,46 +5886,45 @@ public void setStatementPoolingCacheSize(int value) { } /** - * Internal method to prepare the cache handle + * Prepares the cache handle. * * @param value */ private void prepareCache() { - preparedStatementHandleCache = new Builder().maximumWeightedCapacity(getStatementPoolingCacheSize()) + preparedStatementHandleCache = new Builder() + .maximumWeightedCapacity(getStatementPoolingCacheSize()) .listener(new PreparedStatementCacheEvictionListener()).build(); - parameterMetadataCache = new Builder().maximumWeightedCapacity(getStatementPoolingCacheSize()) - .build(); + parameterMetadataCache = new Builder() + .maximumWeightedCapacity(getStatementPoolingCacheSize()).build(); } - /** Get a parameter metadata cache entry if statement pooling is enabled */ - final SQLServerParameterMetaData getCachedParameterMetadata(Sha1HashKey key) { + /** Returns a parameter metadata cache entry if statement pooling is enabled */ + final SQLServerParameterMetaData getCachedParameterMetadata(CityHash128Key key) { if (!isStatementPoolingEnabled()) return null; return parameterMetadataCache.get(key); } - /** Register a parameter metadata cache entry if statement pooling is enabled */ - final void registerCachedParameterMetadata(Sha1HashKey key, - SQLServerParameterMetaData pmd) { + /** Registers a parameter metadata cache entry if statement pooling is enabled */ + final void registerCachedParameterMetadata(CityHash128Key key, SQLServerParameterMetaData pmd) { if (!isStatementPoolingEnabled() || null == pmd) return; parameterMetadataCache.put(key, pmd); } - /** Get or create prepared statement handle cache entry if statement pooling is enabled */ - final PreparedStatementHandle getCachedPreparedStatementHandle(Sha1HashKey key) { + /** Gets or creates prepared statement handle cache entry if statement pooling is enabled */ + final PreparedStatementHandle getCachedPreparedStatementHandle(CityHash128Key key) { if (!isStatementPoolingEnabled()) return null; return preparedStatementHandleCache.get(key); } - /** Get or create prepared statement handle cache entry if statement pooling is enabled */ - final PreparedStatementHandle registerCachedPreparedStatementHandle(Sha1HashKey key, - int handle, + /** Gets or creates prepared statement handle cache entry if statement pooling is enabled */ + final PreparedStatementHandle registerCachedPreparedStatementHandle(CityHash128Key key, int handle, boolean isDirectSql) { if (!isStatementPoolingEnabled() || null == key) return null; @@ -5841,7 +5934,7 @@ final PreparedStatementHandle registerCachedPreparedStatementHandle(Sha1HashKey return cacheItem; } - /** Return prepared statement handle cache entry so it can be un-prepared. */ + /** Returns prepared statement handle cache entry so it can be un-prepared. */ final void returnCachedPreparedStatementHandle(PreparedStatementHandle handle) { handle.removeReference(); @@ -5849,7 +5942,7 @@ final void returnCachedPreparedStatementHandle(PreparedStatementHandle handle) { enqueueUnprepareStatementHandle(handle); } - /** Force eviction of prepared statement handle cache entry. */ + /** Forces eviction of prepared statement handle cache entry. */ final void evictCachedPreparedStatementHandle(PreparedStatementHandle handle) { if (null == handle || null == handle.getKey()) return; @@ -5857,10 +5950,12 @@ final void evictCachedPreparedStatementHandle(PreparedStatementHandle handle) { preparedStatementHandleCache.remove(handle.getKey()); } - // Handle closing handles when removed from cache. - final class PreparedStatementCacheEvictionListener implements EvictionListener { - public void onEviction(Sha1HashKey key, - PreparedStatementHandle handle) { + /* + * Handles closing handles when removed from cache. + */ + final class PreparedStatementCacheEvictionListener + implements EvictionListener { + public void onEviction(CityHash128Key key, PreparedStatementHandle handle) { if (null != handle) { handle.setIsEvictedFromCache(true); // Mark as evicted from cache. @@ -5875,16 +5970,17 @@ public void onEviction(Sha1HashKey key, boolean isAzureDW() throws SQLServerException, SQLException { if (null == isAzureDW) { - try (Statement stmt = this.createStatement(); ResultSet rs = stmt.executeQuery("SELECT CAST(SERVERPROPERTY('EngineEdition') as INT)");) - { - // SERVERPROPERTY('EngineEdition') can be used to determine whether the db server is SQL Azure. - // It should return 6 for SQL Azure DW. This is more reliable than @@version or serverproperty('edition'). - // Reference: http://msdn.microsoft.com/en-us/library/ee336261.aspx - // - // SERVERPROPERTY('EngineEdition') means + try (Statement stmt = this.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT CAST(SERVERPROPERTY('EngineEdition') as INT)");) { + // SERVERPROPERTY('EngineEdition') can be used to determine whether the db server is SQL Azure. + // It should return 6 for SQL Azure DW. This is more reliable than @@version or + // serverproperty('edition'). + // Reference: http://msdn.microsoft.com/en-us/library/ee336261.aspx + // + // SERVERPROPERTY('EngineEdition') means // Database Engine edition of the instance of SQL Server installed on the server. // 1 = Personal or Desktop Engine (Not available for SQL Server.) - // 2 = Standard (This is returned for Standard and Workgroup.) + // 2 = Standard (This is returned for Standard and Workgroup.) // 3 = Enterprise (This is returned for Enterprise, Enterprise Evaluation, and Developer.) // 4 = Express (This is returned for Express, Express with Advanced Services, and Windows Embedded SQL.) // 5 = SQL Azure @@ -5901,8 +5997,10 @@ boolean isAzureDW() throws SQLServerException, SQLException { } /** + * Adds statement to openStatements + * * @param st - * Statement to add to openStatements + * Statement to add to openStatements */ final synchronized void addOpenStatement(Statement st) { if (null != openStatements) { @@ -5911,8 +6009,10 @@ final synchronized void addOpenStatement(Statement st) { } /** + * Removes state from openStatements + * * @param st - * Statement to remove from openStatements + * Statement to remove from openStatements */ final synchronized void removeOpenStatement(Statement st) { if (null != openStatements) { @@ -5921,24 +6021,27 @@ final synchronized void removeOpenStatement(Statement st) { } } -// Helper class for security manager functions used by SQLServerConnection class. + +/** + * Provides Helper class for security manager functions used by SQLServerConnection class. + * + */ final class SQLServerConnectionSecurityManager { static final String dllName = "sqljdbc_auth.dll"; String serverName; int portNumber; - SQLServerConnectionSecurityManager(String serverName, - int portNumber) { + SQLServerConnectionSecurityManager(String serverName, int portNumber) { this.serverName = serverName; this.portNumber = portNumber; } /** - * checkConnect will throws a SecurityException if the calling thread is not allowed to open a socket connection to the specified serverName and - * portNumber. + * Throws a SecurityException if the calling thread is not allowed to open a socket connection to the specified + * serverName and portNumber. * * @throws SecurityException - * when an error occurs + * when an error occurs */ public void checkConnect() throws SecurityException { SecurityManager security = System.getSecurityManager(); @@ -5951,7 +6054,7 @@ public void checkConnect() throws SecurityException { * Throws a SecurityException if the calling thread is not allowed to dynamic link the library code. * * @throws SecurityException - * when an error occurs + * when an error occurs */ public void checkLink() throws SecurityException { SecurityManager security = System.getSecurityManager(); diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection43.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection43.java index 27c782c0c..93505f5f1 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection43.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection43.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -11,14 +8,16 @@ import java.sql.SQLException; import java.sql.ShardingKey; + /** - * SQLServerConnection43 extends {@link SQLServerConnection43} class and implements {@link ISQLServerConnection43} with methods introduced in JDBC 4.3 - * Specifications. This class is used by the drdiver when initializing a class with 43 driver version + * Extends {@link SQLServerConnection43} and implements {@link ISQLServerConnection43} with methods introduced in JDBC + * 4.3 Specifications. This class is used by the driver when initializing a class with with JDBC 4.3 Specs supported + * JVM. */ public class SQLServerConnection43 extends SQLServerConnection implements ISQLServerConnection43 { /** - * Always refresh SerialVersionUID when prompted + * Always refresh SerialVersionUID when prompted. */ private static final long serialVersionUID = -6904163521498951547L; @@ -42,21 +41,18 @@ public void setShardingKey(ShardingKey shardingKey) throws SQLException { } @Override - public void setShardingKey(ShardingKey shardingKey, - ShardingKey superShardingKey) throws SQLException { + public void setShardingKey(ShardingKey shardingKey, ShardingKey superShardingKey) throws SQLException { SQLServerException.throwFeatureNotSupportedException(); } @Override - public boolean setShardingKeyIfValid(ShardingKey shardingKey, - int timeout) throws SQLException { + public boolean setShardingKeyIfValid(ShardingKey shardingKey, int timeout) throws SQLException { SQLServerException.throwFeatureNotSupportedException(); return false; } @Override - public boolean setShardingKeyIfValid(ShardingKey shardingKey, - ShardingKey superShardingKey, + public boolean setShardingKeyIfValid(ShardingKey shardingKey, ShardingKey superShardingKey, int timeout) throws SQLException { SQLServerException.throwFeatureNotSupportedException(); return false; diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionPoolDataSource.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionPoolDataSource.java index 50115cd05..4ac11100f 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionPoolDataSource.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionPoolDataSource.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -15,11 +12,12 @@ import javax.sql.ConnectionPoolDataSource; import javax.sql.PooledConnection; + /** - * SQLServerConnectionPoolDataSource provides physical database connections for connection pool managers. SQLServerConnectionPoolDataSource is - * typically used in Java Application Server environments that support built-in connection pooling and require a ConnectionPoolDataSource to provide - * physical connections. For example, J2EE application servers that provide JDBC 3.0 API spec connection pooling. - * + * Provides physical database connections for connection pool managers. SQLServerConnectionPoolDataSource is typically + * used in Java Application Server environments that support built-in connection pooling and require a + * ConnectionPoolDataSource to provide physical connections. For example, J2EE application servers that provide JDBC 3.0 + * API spec connection pooling. */ public class SQLServerConnectionPoolDataSource extends SQLServerDataSource implements ConnectionPoolDataSource { // Get a new physical connection that the pool manager will issue logical connections from @@ -34,10 +32,10 @@ public PooledConnection getPooledConnection() throws SQLException { } @Override - public PooledConnection getPooledConnection(String user, - String password) throws SQLException { + public PooledConnection getPooledConnection(String user, String password) throws SQLException { if (loggerExternal.isLoggable(Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "getPooledConnection", new Object[] {user, "Password not traced"}); + loggerExternal.entering(getClassNameLogging(), "getPooledConnection", + new Object[] {user, "Password not traced"}); SQLServerPooledConnection pc = new SQLServerPooledConnection(this, user, password); if (loggerExternal.isLoggable(Level.FINER)) loggerExternal.exiting(getClassNameLogging(), "getPooledConnection", pc); @@ -66,8 +64,9 @@ private void readObject(java.io.ObjectInputStream stream) throws java.io.Invalid throw new java.io.InvalidObjectException(""); } - // This is 90% duplicate from the SQLServerDataSource, the serialization proxy pattern does not lend itself to inheritance - // so the duplication is necessary + /** + * Implements java.io.Serializable the same way as {@link SQLServerDataSource} + */ private static class SerializationProxy implements java.io.Serializable { private final Reference ref; private static final long serialVersionUID = 654661379842314126L; diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionPoolProxy.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionPoolProxy.java index cca04ad76..1ee3d0128 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionPoolProxy.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionPoolProxy.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -18,16 +15,16 @@ import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; + /** - * SQLServerConnectionPoolProxy is a wrapper around SQLServerConnection object. When returning a connection object from PooledConnection.getConnection - * we return this proxy per SPEC. + * Provides a wrapper around SQLServerConnection object. When returning a connection object from + * PooledConnection.getConnection we return this proxy per SPEC. *

* This class's public functions need to be kept identical to the SQLServerConnection's. *

- * The API javadoc for JDBC API methods that this class implements are not repeated here. Please see Sun's JDBC API interfaces javadoc for those - * details. + * The API javadoc for JDBC API methods that this class implements are not repeated here. Please see Sun's JDBC API + * interfaces javadoc for those details. */ - class SQLServerConnectionPoolProxy implements ISQLServerConnection, java.io.Serializable { /** * Always refresh SerialVersionUID when prompted @@ -41,12 +38,13 @@ class SQLServerConnectionPoolProxy implements ISQLServerConnection, java.io.Seri // dispenser final private String traceID; - // Permission targets - // currently only callAbort is implemented + /** + * Permission targets currently only callAbort is implemented + */ private static final String callAbortPerm = "callAbort"; /** - * Generate the next unique connection id. + * Generates the next unique connection id. * * @return the next conn id */ @@ -69,7 +67,8 @@ public String toString() { void checkClosed() throws SQLServerException { if (!bIsOpen) { - SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_connectionIsClosed"), null, false); + SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_connectionIsClosed"), + null, false); } } @@ -138,8 +137,7 @@ public void abort(Executor executor) throws SQLException { try { java.sql.SQLPermission perm = new java.sql.SQLPermission(callAbortPerm); secMgr.checkPermission(perm); - } - catch (SecurityException ex) { + } catch (SecurityException ex) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_permissionDenied")); Object[] msgArgs = {callAbortPerm}; throw new SQLServerException(form.format(msgArgs), null, 0, ex); @@ -155,8 +153,7 @@ public void run() { try { wrappedConnection.poolCloseEventNotify(); wrappedConnection = null; - } - catch (SQLException e) { + } catch (SQLException e) { throw new RuntimeException(e); } } @@ -242,24 +239,20 @@ public void clearWarnings() throws SQLServerException { // --------------------------JDBC 2.0----------------------------- @Override - public Statement createStatement(int resultSetType, - int resultSetConcurrency) throws SQLException { + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { checkClosed(); return wrappedConnection.createStatement(resultSetType, resultSetConcurrency); } @Override - public PreparedStatement prepareStatement(String sSql, - int resultSetType, + public PreparedStatement prepareStatement(String sSql, int resultSetType, int resultSetConcurrency) throws SQLException { checkClosed(); return wrappedConnection.prepareStatement(sSql, resultSetType, resultSetConcurrency); } @Override - public CallableStatement prepareCall(String sql, - int resultSetType, - int resultSetConcurrency) throws SQLException { + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { checkClosed(); return wrappedConnection.prepareCall(sql, resultSetType, resultSetConcurrency); } @@ -277,55 +270,40 @@ public java.util.Map> getTypeMap() throws SQLServerException { } @Override - public Statement createStatement(int nType, - int nConcur, - int nHold) throws SQLServerException { + public Statement createStatement(int nType, int nConcur, int nHold) throws SQLServerException { checkClosed(); return wrappedConnection.createStatement(nType, nConcur, nHold); } @Override - public Statement createStatement(int nType, - int nConcur, - int nHold, + public Statement createStatement(int nType, int nConcur, int nHold, SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException { checkClosed(); return wrappedConnection.createStatement(nType, nConcur, nHold, stmtColEncSetting); } @Override - public PreparedStatement prepareStatement(java.lang.String sql, - int nType, - int nConcur, + public PreparedStatement prepareStatement(java.lang.String sql, int nType, int nConcur, int nHold) throws SQLServerException { checkClosed(); return wrappedConnection.prepareStatement(sql, nType, nConcur, nHold); } @Override - public PreparedStatement prepareStatement(String sql, - int nType, - int nConcur, - int nHold, + public PreparedStatement prepareStatement(String sql, int nType, int nConcur, int nHold, SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException { checkClosed(); return wrappedConnection.prepareStatement(sql, nType, nConcur, nHold, stmtColEncSetting); } @Override - public CallableStatement prepareCall(String sql, - int nType, - int nConcur, - int nHold) throws SQLServerException { + public CallableStatement prepareCall(String sql, int nType, int nConcur, int nHold) throws SQLServerException { checkClosed(); return wrappedConnection.prepareCall(sql, nType, nConcur, nHold); } @Override - public CallableStatement prepareCall(String sql, - int nType, - int nConcur, - int nHold, + public CallableStatement prepareCall(String sql, int nType, int nConcur, int nHold, SQLServerStatementColumnEncryptionSetting stmtColEncSetiing) throws SQLServerException { checkClosed(); return wrappedConnection.prepareCall(sql, nType, nConcur, nHold, stmtColEncSetiing); @@ -334,45 +312,39 @@ public CallableStatement prepareCall(String sql, /* JDBC 3.0 Auto generated keys */ @Override - public PreparedStatement prepareStatement(String sql, - int flag) throws SQLServerException { + public PreparedStatement prepareStatement(String sql, int flag) throws SQLServerException { checkClosed(); return wrappedConnection.prepareStatement(sql, flag); } @Override - public PreparedStatement prepareStatement(String sql, - int flag, + public PreparedStatement prepareStatement(String sql, int flag, SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException { checkClosed(); return wrappedConnection.prepareStatement(sql, flag, stmtColEncSetting); } @Override - public PreparedStatement prepareStatement(String sql, - int[] columnIndexes) throws SQLServerException { + public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLServerException { checkClosed(); return wrappedConnection.prepareStatement(sql, columnIndexes); } @Override - public PreparedStatement prepareStatement(String sql, - int[] columnIndexes, + public PreparedStatement prepareStatement(String sql, int[] columnIndexes, SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException { checkClosed(); return wrappedConnection.prepareStatement(sql, columnIndexes, stmtColEncSetting); } @Override - public PreparedStatement prepareStatement(String sql, - String[] columnNames) throws SQLServerException { + public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLServerException { checkClosed(); return wrappedConnection.prepareStatement(sql, columnNames); } @Override - public PreparedStatement prepareStatement(String sql, - String[] columnNames, + public PreparedStatement prepareStatement(String sql, String[] columnNames, SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException { checkClosed(); return wrappedConnection.prepareStatement(sql, columnNames, stmtColEncSetting); @@ -423,8 +395,7 @@ public int getNetworkTimeout() throws SQLException { } @Override - public void setNetworkTimeout(Executor executor, - int timeout) throws SQLException { + public void setNetworkTimeout(Executor executor, int timeout) throws SQLException { checkClosed(); wrappedConnection.setNetworkTimeout(executor, timeout); } @@ -442,8 +413,7 @@ public void setSchema(String schema) throws SQLException { } @Override - public java.sql.Array createArrayOf(String typeName, - Object[] elements) throws SQLException { + public java.sql.Array createArrayOf(String typeName, Object[] elements) throws SQLException { checkClosed(); return wrappedConnection.createArrayOf(typeName, elements); } @@ -473,8 +443,7 @@ public java.sql.SQLXML createSQLXML() throws SQLException { } @Override - public java.sql.Struct createStruct(String typeName, - Object[] attributes) throws SQLException { + public java.sql.Struct createStruct(String typeName, Object[] attributes) throws SQLException { checkClosed(); return wrappedConnection.createStruct(typeName, attributes); } @@ -499,8 +468,7 @@ public void setClientInfo(java.util.Properties properties) throws SQLClientInfoE } @Override - public void setClientInfo(String name, - String value) throws SQLClientInfoException { + public void setClientInfo(String name, String value) throws SQLClientInfoException { // No checkClosed() call since we can only throw SQLClientInfoException // from here wrappedConnection.setClientInfo(name, value); @@ -526,8 +494,7 @@ public T unwrap(Class iface) throws SQLException { T t; try { t = iface.cast(this); - } - catch (ClassCastException e) { + } catch (ClassCastException e) { SQLServerException newe = new SQLServerException(e.getMessage(), e); throw newe; } @@ -542,7 +509,7 @@ public java.util.UUID getClientConnectionId() throws SQLServerException { } @Override - public synchronized void setSendTimeAsDatetime(boolean sendTimeAsDateTimeValue) throws SQLServerException { + public void setSendTimeAsDatetime(boolean sendTimeAsDateTimeValue) throws SQLServerException { checkClosed(); wrappedConnection.setSendTimeAsDatetime(sendTimeAsDateTimeValue); } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataColumn.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataColumn.java index 7877cf3ab..218f58dbb 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataColumn.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataColumn.java @@ -1,52 +1,48 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -/** - * This class represents a column of the in-memory data table represented by SQLServerDataTable. - */ -public final class SQLServerDataColumn { - String columnName; - int javaSqlType; - int precision = 0; - int scale = 0; - int numberOfDigitsIntegerPart = 0; - - /** - * Initializes a new instance of SQLServerDataColumn with the column name and type. - * - * @param columnName - * the name of the column - * @param sqlType - * the type of the column - */ - public SQLServerDataColumn(String columnName, - int sqlType) { - this.columnName = columnName; - this.javaSqlType = sqlType; - } - - /** - * Retrieves the column name. - * - * @return the name of the column. - */ - public String getColumnName() { - return columnName; - } - - /** - * Retrieves the column type. - * - * @return the column type. - */ - public int getColumnType() { - return javaSqlType; - } -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +/** + * Represents a column of the in-memory data table represented by {@link SQLServerDataTable}. + */ +public final class SQLServerDataColumn { + String columnName; + int javaSqlType; + int precision = 0; + int scale = 0; + int numberOfDigitsIntegerPart = 0; + + /** + * Constructs a SQLServerDataColumn with the column name and type. + * + * @param columnName + * the name of the column + * @param sqlType + * the type of the column + */ + public SQLServerDataColumn(String columnName, int sqlType) { + this.columnName = columnName; + this.javaSqlType = sqlType; + } + + /** + * Returns the column name. + * + * @return the name of the column. + */ + public String getColumnName() { + return columnName; + } + + /** + * Returns the column type. + * + * @return the column type. + */ + public int getColumnType() { + return javaSqlType; + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java index 607c2d89f..a0b32b32e 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -22,14 +19,19 @@ import org.ietf.jgss.GSSCredential; + /** - * This datasource lists properties specific for the SQLServerConnection class. + * Contains a list of properties specific for the {@link SQLServerConnection} class. */ -public class SQLServerDataSource implements ISQLServerDataSource, javax.sql.DataSource, java.io.Serializable, javax.naming.Referenceable { +public class SQLServerDataSource + implements ISQLServerDataSource, javax.sql.DataSource, java.io.Serializable, javax.naming.Referenceable { // dsLogger is logger used for all SQLServerDataSource instances. - static final java.util.logging.Logger dsLogger = java.util.logging.Logger.getLogger("com.microsoft.sqlserver.jdbc.internals.SQLServerDataSource"); - static final java.util.logging.Logger loggerExternal = java.util.logging.Logger.getLogger("com.microsoft.sqlserver.jdbc.DataSource"); - static final private java.util.logging.Logger parentLogger = java.util.logging.Logger.getLogger("com.microsoft.sqlserver.jdbc"); + static final java.util.logging.Logger dsLogger = java.util.logging.Logger + .getLogger("com.microsoft.sqlserver.jdbc.internals.SQLServerDataSource"); + static final java.util.logging.Logger loggerExternal = java.util.logging.Logger + .getLogger("com.microsoft.sqlserver.jdbc.DataSource"); + static final private java.util.logging.Logger parentLogger = java.util.logging.Logger + .getLogger("com.microsoft.sqlserver.jdbc"); final private String loggingClassName; private boolean trustStorePasswordStripped = false; @@ -55,14 +57,15 @@ public class SQLServerDataSource implements ISQLServerDataSource, javax.sql.Data final private String traceID; /** - * Initializes a new instance of the SQLServerDataSource class. + * Constructs a SQLServerDataSource. */ public SQLServerDataSource() { connectionProps = new Properties(); int dataSourceID = nextDataSourceID(); String nameL = getClass().getName(); traceID = nameL.substring(1 + nameL.lastIndexOf('.')) + ":" + dataSourceID; - loggingClassName = "com.microsoft.sqlserver.jdbc." + nameL.substring(1 + nameL.lastIndexOf('.')) + ":" + dataSourceID; + loggingClassName = "com.microsoft.sqlserver.jdbc." + nameL.substring(1 + nameL.lastIndexOf('.')) + ":" + + dataSourceID; } String getClassNameLogging() { @@ -85,17 +88,19 @@ public Connection getConnection() throws SQLServerException { } @Override - public Connection getConnection(String username, - String password) throws SQLServerException { + public Connection getConnection(String username, String password) throws SQLServerException { if (loggerExternal.isLoggable(Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "getConnection", new Object[] {username, "Password not traced"}); + loggerExternal.entering(getClassNameLogging(), "getConnection", + new Object[] {username, "Password not traced"}); Connection con = getConnectionInternal(username, password, null); loggerExternal.exiting(getClassNameLogging(), "getConnection", con); return con; } - // Sets the maximum time in seconds that this data source will wait while - // attempting to connect to a database. Note default value is 0. + /** + * Sets the maximum time in seconds that this data source will wait while attempting to connect to a database. Note + * default value is 0. + */ @Override public void setLoginTimeout(int loginTimeout) { setIntProperty(connectionProps, SQLServerDriverIntProperty.LOGIN_TIMEOUT.toString(), loginTimeout); @@ -104,14 +109,16 @@ public void setLoginTimeout(int loginTimeout) { @Override public int getLoginTimeout() { int defaultTimeOut = SQLServerDriverIntProperty.LOGIN_TIMEOUT.getDefaultValue(); - final int logintimeout = getIntProperty(connectionProps, SQLServerDriverIntProperty.LOGIN_TIMEOUT.toString(), defaultTimeOut); + final int logintimeout = getIntProperty(connectionProps, SQLServerDriverIntProperty.LOGIN_TIMEOUT.toString(), + defaultTimeOut); // even if the user explicitly sets the timeout to zero, convert to 15 return (logintimeout == 0) ? defaultTimeOut : logintimeout; } - // Sets the log writer for this DataSource. - // Currently we just hold onto this logWriter and pass it back to callers, - // nothing else. + /** + * Sets the log writer for this DataSource. Currently we just hold onto this logWriter and pass it back to callers, + * nothing else. + */ private transient PrintWriter logWriter; @Override @@ -121,7 +128,9 @@ public void setLogWriter(PrintWriter out) { loggerExternal.exiting(getClassNameLogging(), "setLogWriter"); } - // Retrieves the log writer for this DataSource. + /** + * Returns the log writer for this DataSource. + */ @Override public PrintWriter getLogWriter() { loggerExternal.entering(getClassNameLogging(), "getLogWriter"); @@ -136,9 +145,9 @@ public Logger getParentLogger() throws java.sql.SQLFeatureNotSupportedException // Core Connection property setters/getters. - // applicationName is used to identify the specific application in various - // SQL Server - // profiling and logging tools. + /** + * Sets the specific application in various SQL Server profiling and logging tools. + */ @Override public void setApplicationName(String applicationName) { setStringProperty(connectionProps, SQLServerDriverStringProperty.APPLICATION_NAME.toString(), applicationName); @@ -150,9 +159,12 @@ public String getApplicationName() { SQLServerDriverStringProperty.APPLICATION_NAME.getDefaultValue()); } - // databaseName is the name of the database to connect to. If databaseName - // is not set, - // getDatabaseName returns the default value of null. + /** + * Sets the the database to connect to. + * + * @param databaseName + * if not set, returns the default value of null. + */ @Override public void setDatabaseName(String databaseName) { setStringProperty(connectionProps, SQLServerDriverStringProperty.DATABASE_NAME.toString(), databaseName); @@ -163,9 +175,12 @@ public String getDatabaseName() { return getStringProperty(connectionProps, SQLServerDriverStringProperty.DATABASE_NAME.toString(), null); } - // instanceName is the SQL Server instance name to connect to. - // If instanceName is not set, getInstanceName returns the default value of - // null. + /** + * Sets the the SQL Server instance name to connect to. + * + * @param instanceName + * if not set, returns the default value of null. + */ @Override public void setInstanceName(String instanceName) { setStringProperty(connectionProps, SQLServerDriverStringProperty.INSTANCE_NAME.toString(), instanceName); @@ -183,7 +198,8 @@ public void setIntegratedSecurity(boolean enable) { @Override public void setAuthenticationScheme(String authenticationScheme) { - setStringProperty(connectionProps, SQLServerDriverStringProperty.AUTHENTICATION_SCHEME.toString(), authenticationScheme); + setStringProperty(connectionProps, SQLServerDriverStringProperty.AUTHENTICATION_SCHEME.toString(), + authenticationScheme); } @Override @@ -204,7 +220,8 @@ public void setGSSCredentials(GSSCredential userCredential) { @Override public GSSCredential getGSSCredentials() { - return (GSSCredential) getObjectProperty(connectionProps, SQLServerDriverObjectProperty.GSS_CREDENTIAL.toString(), + return (GSSCredential) getObjectProperty(connectionProps, + SQLServerDriverObjectProperty.GSS_CREDENTIAL.toString(), SQLServerDriverObjectProperty.GSS_CREDENTIAL.getDefaultValue()); } @@ -218,16 +235,15 @@ public String getAccessToken() { return getStringProperty(connectionProps, SQLServerDriverStringProperty.ACCESS_TOKEN.toString(), null); } - // If lastUpdateCount is set to true, the driver will return only the last - // update - // count from all the update counts returned by a batch. The default of - // false will - // return all update counts. If lastUpdateCount is not set, - // getLastUpdateCount - // returns the default value of false. + /** + * Sets the Column Encryption setting. If lastUpdateCount is set to true, the driver will return only the last + * update count from all the update counts returned by a batch. The default of false will return all update counts. + * If lastUpdateCount is not set, getLastUpdateCount returns the default value of false. + */ @Override public void setColumnEncryptionSetting(String columnEncryptionSetting) { - setStringProperty(connectionProps, SQLServerDriverStringProperty.COLUMN_ENCRYPTION.toString(), columnEncryptionSetting); + setStringProperty(connectionProps, SQLServerDriverStringProperty.COLUMN_ENCRYPTION.toString(), + columnEncryptionSetting); } @Override @@ -238,7 +254,8 @@ public String getColumnEncryptionSetting() { @Override public void setKeyStoreAuthentication(String keyStoreAuthentication) { - setStringProperty(connectionProps, SQLServerDriverStringProperty.KEY_STORE_AUTHENTICATION.toString(), keyStoreAuthentication); + setStringProperty(connectionProps, SQLServerDriverStringProperty.KEY_STORE_AUTHENTICATION.toString(), + keyStoreAuthentication); } @Override @@ -254,7 +271,8 @@ public void setKeyStoreSecret(String keyStoreSecret) { @Override public void setKeyStoreLocation(String keyStoreLocation) { - setStringProperty(connectionProps, SQLServerDriverStringProperty.KEY_STORE_LOCATION.toString(), keyStoreLocation); + setStringProperty(connectionProps, SQLServerDriverStringProperty.KEY_STORE_LOCATION.toString(), + keyStoreLocation); } @Override @@ -265,7 +283,8 @@ public String getKeyStoreLocation() { @Override public void setLastUpdateCount(boolean lastUpdateCount) { - setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.LAST_UPDATE_COUNT.toString(), lastUpdateCount); + setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.LAST_UPDATE_COUNT.toString(), + lastUpdateCount); } @Override @@ -287,12 +306,14 @@ public boolean getEncrypt() { @Override public void setTransparentNetworkIPResolution(boolean tnir) { - setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.TRANSPARENT_NETWORK_IP_RESOLUTION.toString(), tnir); + setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.TRANSPARENT_NETWORK_IP_RESOLUTION.toString(), + tnir); } @Override public boolean getTransparentNetworkIPResolution() { - return getBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.TRANSPARENT_NETWORK_IP_RESOLUTION.toString(), + return getBooleanProperty(connectionProps, + SQLServerDriverBooleanProperty.TRANSPARENT_NETWORK_IP_RESOLUTION.toString(), SQLServerDriverBooleanProperty.TRANSPARENT_NETWORK_IP_RESOLUTION.getDefaultValue()); } @@ -333,7 +354,8 @@ public void setTrustStorePassword(String trustStorePassword) { // if a non value property is set if (trustStorePassword != null) trustStorePasswordStripped = false; - setStringProperty(connectionProps, SQLServerDriverStringProperty.TRUST_STORE_PASSWORD.toString(), trustStorePassword); + setStringProperty(connectionProps, SQLServerDriverStringProperty.TRUST_STORE_PASSWORD.toString(), + trustStorePassword); } @Override @@ -343,17 +365,18 @@ public void setHostNameInCertificate(String hostName) { @Override public String getHostNameInCertificate() { - return getStringProperty(connectionProps, SQLServerDriverStringProperty.HOSTNAME_IN_CERTIFICATE.toString(), null); + return getStringProperty(connectionProps, SQLServerDriverStringProperty.HOSTNAME_IN_CERTIFICATE.toString(), + null); } - // lockTimeout is the number of milliseconds to wait before the database - // reports - // a lock timeout. The default value of -1 means wait forever. If specified, - // this value will be the default for all statements on the connection. Note - // a - // value of 0 means no wait. If lockTimeout is not set, getLockTimeout - // returns - // the default of -1. + /** + * Sets the lock timeout value. + * + * @param lockTimeout + * the number of milliseconds to wait before the database reports a lock timeout. The default value of -1 + * means wait forever. If specified, this value will be the default for all statements on the connection. + * Note a value of 0 means no wait. If lockTimeout is not set, getLockTimeout returns the default of -1. + */ @Override public void setLockTimeout(int lockTimeout) { setIntProperty(connectionProps, SQLServerDriverIntProperty.LOCK_TIMEOUT.toString(), lockTimeout); @@ -365,12 +388,13 @@ public int getLockTimeout() { SQLServerDriverIntProperty.LOCK_TIMEOUT.getDefaultValue()); } - // setPassword sets the password that will be used when connecting to SQL - // Server. - // Note getPassword is deliberately declared non-public for security - // reasons. - // If the password is not set, getPassword returns the default value of - // null. + /** + * Sets the password that will be used when connecting to SQL Server. + * + * @param password + * Note getPassword is deliberately declared non-public for security reasons. If the password is not set, + * getPassword returns the default value of null. + */ @Override public void setPassword(String password) { setStringProperty(connectionProps, SQLServerDriverStringProperty.PASSWORD.toString(), password); @@ -380,13 +404,14 @@ String getPassword() { return getStringProperty(connectionProps, SQLServerDriverStringProperty.PASSWORD.toString(), null); } - // portNumber is the TCP-IP port number used when opening a socket - // connection - // to SQL Server. If portNumber is not set, getPortNumber returns the - // default - // of 1433. Note as mentioned above, setPortNumber does not do any range - // checking on the port value passed in, invalid port numbers like 99999 can - // be passed in without triggering any error. + /** + * Sets the TCP-IP port number used when opening a socket connection to SQL Server. + * + * @param portNumber + * if not set, getPortNumber returns the default of 1433. Note as mentioned above, setPortNumber does not do + * any range checking on the port value passed in,\ invalid port numbers like 99999 can be passed in without + * triggering any error. + */ @Override public void setPortNumber(int portNumber) { setIntProperty(connectionProps, SQLServerDriverIntProperty.PORT_NUMBER.toString(), portNumber); @@ -398,14 +423,16 @@ public int getPortNumber() { SQLServerDriverIntProperty.PORT_NUMBER.getDefaultValue()); } - // selectMethod is the default cursor type used for the result set. This - // property is useful when you are dealing with large result sets and don't - // want to store the whole result set in memory on the client side. By - // setting - // the property to "cursor" you will be able to create a server side cursor - // that - // can fetch smaller chunks of data at a time. If selectMethod is not set, - // getSelectMethod returns the default value of "direct". + /** + * Sets the default cursor type used for the result set. + * + * @param selectMethod + * This(non-Javadoc) @see com.microsoft.sqlserver.jdbc.ISQLServerDataSource#setSelectMethod(java.lang.String) + * property is useful when you are dealing with large result sets and do not want to store the whole result + * set in memory on the client side. By setting the property to "cursor" you will be able to create a server + * side cursor that can fetch smaller chunks of data at a time. If selectMethod is not set, getSelectMethod + * returns the default value of "direct". + */ @Override public void setSelectMethod(String selectMethod) { setStringProperty(connectionProps, SQLServerDriverStringProperty.SELECT_METHOD.toString(), selectMethod); @@ -430,7 +457,8 @@ public String getResponseBuffering() { @Override public void setApplicationIntent(String applicationIntent) { - setStringProperty(connectionProps, SQLServerDriverStringProperty.APPLICATION_INTENT.toString(), applicationIntent); + setStringProperty(connectionProps, SQLServerDriverStringProperty.APPLICATION_INTENT.toString(), + applicationIntent); } @Override @@ -441,7 +469,8 @@ public String getApplicationIntent() { @Override public void setSendTimeAsDatetime(boolean sendTimeAsDatetime) { - setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.SEND_TIME_AS_DATETIME.toString(), sendTimeAsDatetime); + setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.SEND_TIME_AS_DATETIME.toString(), + sendTimeAsDatetime); } @Override @@ -450,14 +479,14 @@ public boolean getSendTimeAsDatetime() { SQLServerDriverBooleanProperty.SEND_TIME_AS_DATETIME.getDefaultValue()); } - // If sendStringParametersAsUnicode is set to true (which is the default), - // string parameters are sent to the server in UNICODE format. If - // sendStringParametersAsUnicode - // is set to false, string parameters are sent to the server in the native - // TDS collation - // format of the database, not in UNICODE. If sendStringParametersAsUnicode - // is not set, - // getSendStringParametersAsUnicode returns the default of true. + /** + * Sets whether string parameters are sent to the server in UNICODE format. + * + * @param sendStringParametersAsUnicode + * if true (default), string parameters are sent to the server in UNICODE format. if false, string parameters + * are sent to the server in the native TDS collation format of the database, not in UNICODE. if set, returns + * the default of true. + */ @Override public void setSendStringParametersAsUnicode(boolean sendStringParametersAsUnicode) { setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.SEND_STRING_PARAMETERS_AS_UNICODE.toString(), @@ -466,13 +495,15 @@ public void setSendStringParametersAsUnicode(boolean sendStringParametersAsUnico @Override public boolean getSendStringParametersAsUnicode() { - return getBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.SEND_STRING_PARAMETERS_AS_UNICODE.toString(), + return getBooleanProperty(connectionProps, + SQLServerDriverBooleanProperty.SEND_STRING_PARAMETERS_AS_UNICODE.toString(), SQLServerDriverBooleanProperty.SEND_STRING_PARAMETERS_AS_UNICODE.getDefaultValue()); } @Override public void setServerNameAsACE(boolean serverNameAsACE) { - setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.SERVER_NAME_AS_ACE.toString(), serverNameAsACE); + setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.SERVER_NAME_AS_ACE.toString(), + serverNameAsACE); } @Override @@ -481,9 +512,12 @@ public boolean getServerNameAsACE() { SQLServerDriverBooleanProperty.SERVER_NAME_AS_ACE.getDefaultValue()); } - // serverName is the host name of the target SQL Server. If serverName is - // not set, - // getServerName returns the default value of null is returned. + /** + * Sets the host name of the target SQL Server. + * + * @param serverName + * if not set, returns the default value of null is returned. + */ @Override public void setServerName(String serverName) { setStringProperty(connectionProps, SQLServerDriverStringProperty.SERVER_NAME.toString(), serverName); @@ -494,8 +528,13 @@ public String getServerName() { return getStringProperty(connectionProps, SQLServerDriverStringProperty.SERVER_NAME.toString(), null); } - // Specify an Service Principal Name (SPN) of the target SQL Server. - // https://msdn.microsoft.com/en-us/library/cc280459.aspx + /** + * Sets the Service Principal Name (SPN) of the target SQL Server. + * https://msdn.microsoft.com/en-us/library/cc280459.aspx + * + * @param serverSpn + * service principal name + */ @Override public void setServerSpn(String serverSpn) { setStringProperty(connectionProps, SQLServerDriverStringProperty.SERVER_SPN.toString(), serverSpn); @@ -506,9 +545,12 @@ public String getServerSpn() { return getStringProperty(connectionProps, SQLServerDriverStringProperty.SERVER_SPN.toString(), null); } - // serverName is the host name of the target SQL Server. If serverName is - // not set, - // getServerName returns the default value of null is returned. + /** + * Sets the fail over partner of the target SQL Server. + * + * @param serverName + * if not set, returns the default value of null. + */ @Override public void setFailoverPartner(String serverName) { setStringProperty(connectionProps, SQLServerDriverStringProperty.FAILOVER_PARTNER.toString(), serverName); @@ -521,7 +563,8 @@ public String getFailoverPartner() { @Override public void setMultiSubnetFailover(boolean multiSubnetFailover) { - setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.MULTI_SUBNET_FAILOVER.toString(), multiSubnetFailover); + setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.MULTI_SUBNET_FAILOVER.toString(), + multiSubnetFailover); } @Override @@ -530,9 +573,12 @@ public boolean getMultiSubnetFailover() { SQLServerDriverBooleanProperty.MULTI_SUBNET_FAILOVER.getDefaultValue()); } - // setUser set's the user name that will be used when connecting to SQL - // Server. - // If user is not set, getUser returns the default value of null. + /** + * Sets the user name that will be used when connecting to SQL Server. + * + * @param user + * if not set, returns the default value of null. + */ @Override public void setUser(String user) { setStringProperty(connectionProps, SQLServerDriverStringProperty.USER.toString(), user); @@ -543,12 +589,14 @@ public String getUser() { return getStringProperty(connectionProps, SQLServerDriverStringProperty.USER.toString(), null); } - // workstationID is the name of the client machine (or client workstation). - // workstationID is the host name of the client in other words. If - // workstationID - // is not set, the default value is constructed by calling - // InetAddress.getLocalHost().getHostName() - // or if getHostName() returns blank then getHostAddress().toString(). + /** + * Sets the name of the client machine (or client workstation). + * + * @param workstationID + * host name of the client. if not set, the default value is constructed by calling + * InetAddress.getLocalHost().getHostName() or if getHostName() returns blank then + * getHostAddress().toString(). + */ @Override public void setWorkstationID(String workstationID) { setStringProperty(connectionProps, SQLServerDriverStringProperty.WORKSTATION_ID.toString(), workstationID); @@ -568,13 +616,13 @@ public String getWorkstationID() { return getWSID; } - // If xopenStates is set to true, the driver will convert SQL states to - // XOPEN - // compliant states. The default is false which causes the driver to - // generate SQL 99 - // state codes. If xopenStates is not set, getXopenStates returns the - // default value - // of false. + /** + * Sets whether the driver will convert SQL states to XOPEN compliant states. + * + * @param xopenStates + * if true, the driver will convert SQL states to XOPEN compliant states. The default is false which causes + * the driver to generate SQL 99 state codes. If not set, getXopenStates returns the default value of false. + */ @Override public void setXopenStates(boolean xopenStates) { setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.XOPEN_STATES.toString(), xopenStates); @@ -610,7 +658,8 @@ public String getSSLProtocol() { @Override public void setTrustManagerClass(String trustManagerClass) { - setStringProperty(connectionProps, SQLServerDriverStringProperty.TRUST_MANAGER_CLASS.toString(), trustManagerClass); + setStringProperty(connectionProps, SQLServerDriverStringProperty.TRUST_MANAGER_CLASS.toString(), + trustManagerClass); } @Override @@ -621,35 +670,30 @@ public String getTrustManagerClass() { @Override public void setTrustManagerConstructorArg(String trustManagerConstructorArg) { - setStringProperty(connectionProps, SQLServerDriverStringProperty.TRUST_MANAGER_CONSTRUCTOR_ARG.toString(), trustManagerConstructorArg); + setStringProperty(connectionProps, SQLServerDriverStringProperty.TRUST_MANAGER_CONSTRUCTOR_ARG.toString(), + trustManagerConstructorArg); } @Override public String getTrustManagerConstructorArg() { - return getStringProperty(connectionProps, SQLServerDriverStringProperty.TRUST_MANAGER_CONSTRUCTOR_ARG.toString(), + return getStringProperty(connectionProps, + SQLServerDriverStringProperty.TRUST_MANAGER_CONSTRUCTOR_ARG.toString(), SQLServerDriverStringProperty.TRUST_MANAGER_CONSTRUCTOR_ARG.getDefaultValue()); } - // The URL property is exposed for backwards compatibility reasons. Also, - // several - // Java Application servers expect a setURL function on the DataSource and - // set it - // by default (JBoss and WebLogic). - - // Note for security reasons we do not recommend that customers include the - // password - // in the url supplied to setURL. The reason for this is third-party Java - // Application - // Servers will very often display the value set to URL property in their - // DataSource - // configuration GUI. We recommend instead that clients use the setPassword - // method - // to set the password value. The Java Application Servers will not display - // a password - // that is set on the DataSource in the configuration GUI. - - // Note if setURL is not called, getURL returns the default value of - // "jdbc:sqlserver://". + /** + * Sets the datasource URL. + * + * @param url + * The URL property is exposed for backwards compatibility reasons. Also, several Java Application servers + * expect a setURL function on the DataSource and set it by default (JBoss and WebLogic) Note for security + * reasons we do not recommend that customers include the password in the url supplied to setURL. The reason + * for this is third-party Java Application Servers will very often display the value set to URL property in + * their DataSource configuration GUI. We recommend instead that clients use the setPassword method to set + * the password value. The Java Application Servers will not display a password that is set on the DataSource + * in the configuration GUI. Note if setURL is not called, getURL returns the default value of + * "jdbc:sqlserver://". + */ @Override public void setURL(String url) { loggerExternal.entering(getClassNameLogging(), "setURL", url); @@ -669,9 +713,10 @@ public String getURL() { return url; } - // DataSource specific property setters/getters. - // Per JDBC specification 16.1.1 "...the only property that all DataSource - // implementations are required to support is the description property". + /** + * Sets the DataSource description. Per JDBC specification 16.1.1 "...the only property that all DataSource + * implementations are required to support is the description property". + */ @Override public void setDescription(String description) { loggerExternal.entering(getClassNameLogging(), "setDescription", description); @@ -679,6 +724,9 @@ public void setDescription(String description) { loggerExternal.exiting(getClassNameLogging(), "setDescription"); } + /** + * Returns the DataSource description + */ @Override public String getDescription() { loggerExternal.entering(getClassNameLogging(), "getDescription"); @@ -686,10 +734,14 @@ public String getDescription() { return dataSourceDescription; } - // packetSize is the size (in bytes) to use for the TCP/IP send and receive - // buffer. It is also the value used for the TDS packet size (SQL Server - // Network Packet Size). Validity of the value is checked at connect time. - // If no value is set for this property, its default value is 4KB. + /** + * Sets the packet size. + * + * @param packetSize + * the size (in bytes) to use for the TCP/IP send and receive buffer. It is also the value used for the TDS + * packet size (SQL Server Network Packet Size). Validity of the value is checked at connect time. If no + * value is set for this property, its default value is 4KB. + */ @Override public void setPacketSize(int packetSize) { setIntProperty(connectionProps, SQLServerDriverIntProperty.PACKET_SIZE.toString(), packetSize); @@ -725,49 +777,57 @@ public int getCancelQueryTimeout() { @Override public void setEnablePrepareOnFirstPreparedStatementCall(boolean enablePrepareOnFirstPreparedStatementCall) { - setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.ENABLE_PREPARE_ON_FIRST_PREPARED_STATEMENT.toString(), + setBooleanProperty(connectionProps, + SQLServerDriverBooleanProperty.ENABLE_PREPARE_ON_FIRST_PREPARED_STATEMENT.toString(), enablePrepareOnFirstPreparedStatementCall); } @Override public boolean getEnablePrepareOnFirstPreparedStatementCall() { - boolean defaultValue = SQLServerDriverBooleanProperty.ENABLE_PREPARE_ON_FIRST_PREPARED_STATEMENT.getDefaultValue(); - return getBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.ENABLE_PREPARE_ON_FIRST_PREPARED_STATEMENT.toString(), - defaultValue); + boolean defaultValue = SQLServerDriverBooleanProperty.ENABLE_PREPARE_ON_FIRST_PREPARED_STATEMENT + .getDefaultValue(); + return getBooleanProperty(connectionProps, + SQLServerDriverBooleanProperty.ENABLE_PREPARE_ON_FIRST_PREPARED_STATEMENT.toString(), defaultValue); } @Override public void setServerPreparedStatementDiscardThreshold(int serverPreparedStatementDiscardThreshold) { - setIntProperty(connectionProps, SQLServerDriverIntProperty.SERVER_PREPARED_STATEMENT_DISCARD_THRESHOLD.toString(), + setIntProperty(connectionProps, + SQLServerDriverIntProperty.SERVER_PREPARED_STATEMENT_DISCARD_THRESHOLD.toString(), serverPreparedStatementDiscardThreshold); } @Override public int getServerPreparedStatementDiscardThreshold() { int defaultSize = SQLServerDriverIntProperty.SERVER_PREPARED_STATEMENT_DISCARD_THRESHOLD.getDefaultValue(); - return getIntProperty(connectionProps, SQLServerDriverIntProperty.SERVER_PREPARED_STATEMENT_DISCARD_THRESHOLD.toString(), defaultSize); + return getIntProperty(connectionProps, + SQLServerDriverIntProperty.SERVER_PREPARED_STATEMENT_DISCARD_THRESHOLD.toString(), defaultSize); } @Override public void setStatementPoolingCacheSize(int statementPoolingCacheSize) { - setIntProperty(connectionProps, SQLServerDriverIntProperty.STATEMENT_POOLING_CACHE_SIZE.toString(), statementPoolingCacheSize); + setIntProperty(connectionProps, SQLServerDriverIntProperty.STATEMENT_POOLING_CACHE_SIZE.toString(), + statementPoolingCacheSize); } @Override public int getStatementPoolingCacheSize() { int defaultSize = SQLServerDriverIntProperty.STATEMENT_POOLING_CACHE_SIZE.getDefaultValue(); - return getIntProperty(connectionProps, SQLServerDriverIntProperty.STATEMENT_POOLING_CACHE_SIZE.toString(), defaultSize); + return getIntProperty(connectionProps, SQLServerDriverIntProperty.STATEMENT_POOLING_CACHE_SIZE.toString(), + defaultSize); } @Override public void setDisableStatementPooling(boolean disableStatementPooling) { - setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.DISABLE_STATEMENT_POOLING.toString(), disableStatementPooling); + setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.DISABLE_STATEMENT_POOLING.toString(), + disableStatementPooling); } @Override public boolean getDisableStatementPooling() { boolean defaultValue = SQLServerDriverBooleanProperty.DISABLE_STATEMENT_POOLING.getDefaultValue(); - return getBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.DISABLE_STATEMENT_POOLING.toString(), defaultValue); + return getBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.DISABLE_STATEMENT_POOLING.toString(), + defaultValue); } @Override @@ -783,18 +843,21 @@ public int getSocketTimeout() { @Override public void setUseBulkCopyForBatchInsert(boolean useBulkCopyForBatchInsert) { - setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.USE_BULK_COPY_FOR_BATCH_INSERT.toString(), useBulkCopyForBatchInsert); + setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.USE_BULK_COPY_FOR_BATCH_INSERT.toString(), + useBulkCopyForBatchInsert); } @Override public boolean getUseBulkCopyForBatchInsert() { - return getBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.USE_BULK_COPY_FOR_BATCH_INSERT.toString(), + return getBooleanProperty(connectionProps, + SQLServerDriverBooleanProperty.USE_BULK_COPY_FOR_BATCH_INSERT.toString(), SQLServerDriverBooleanProperty.USE_BULK_COPY_FOR_BATCH_INSERT.getDefaultValue()); } @Override public void setJASSConfigurationName(String configurationName) { - setStringProperty(connectionProps, SQLServerDriverStringProperty.JAAS_CONFIG_NAME.toString(), configurationName); + setStringProperty(connectionProps, SQLServerDriverStringProperty.JAAS_CONFIG_NAME.toString(), + configurationName); } @Override @@ -803,77 +866,67 @@ public String getJASSConfigurationName() { SQLServerDriverStringProperty.JAAS_CONFIG_NAME.getDefaultValue()); } - // responseBuffering controls the driver's buffering of responses from SQL - // Server. - // Possible values are: - // - // "full" - Fully buffer the response at execution time. - // Advantages: - // 100% back compat with v1.1 driver - // Maximizes concurrency on the server - // Disadvantages: - // Consumes more client-side memory - // Client scalability limits with large responses - // More execute latency - // - // "adaptive" - Data Pipe adaptive buffering - // Advantages: - // Buffers only when necessary, only as much as necessary - // Enables handling very large responses, values - // Disadvantages - // Reduced concurrency on the server - // Internal functions for setting/getting property values. - - // Set a string property value. - // Caller will always supply a non-null props and propKey. - // Caller may supply a null propValue, in this case no property value is - // set. - private void setStringProperty(Properties props, - String propKey, - String propValue) { - if (loggerExternal.isLoggable(java.util.logging.Level.FINER) && !propKey.contains("password") && !propKey.contains("Password")) { + /** + * Sets a property string value. + * + * @param props + * @param propKey + * @param propValue + * Caller will always supply a non-null props and propKey. Caller may supply a null propValue, in this case + * no property value is set. + */ + private void setStringProperty(Properties props, String propKey, String propValue) { + if (loggerExternal.isLoggable(java.util.logging.Level.FINER) && !propKey.contains("password") + && !propKey.contains("Password")) { loggerExternal.entering(getClassNameLogging(), "set" + propKey, propValue); - } - else + } else loggerExternal.entering(getClassNameLogging(), "set" + propKey); if (null != propValue) props.setProperty(propKey, propValue); loggerExternal.exiting(getClassNameLogging(), "set" + propKey); } - // Reads property value in String format. - // Caller will always supply a non-null props and propKey. - // Returns null if the specific property value is not set. - private String getStringProperty(Properties props, - String propKey, - String defaultValue) { + /** + * Returns a property value in String format. + * + * @param props + * @param propKey + * @param defaultValue + * @return Caller will always supply a non-null props and propKey. Returns null if the specific property value is + * not set. + */ + private String getStringProperty(Properties props, String propKey, String defaultValue) { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "get" + propKey); String propValue = props.getProperty(propKey); if (null == propValue) propValue = defaultValue; - if (loggerExternal.isLoggable(java.util.logging.Level.FINER) && !propKey.contains("password") && !propKey.contains("Password")) + if (loggerExternal.isLoggable(java.util.logging.Level.FINER) && !propKey.contains("password") + && !propKey.contains("Password")) loggerExternal.exiting(getClassNameLogging(), "get" + propKey, propValue); return propValue; } - // Set an integer property value. - // Caller will always supply a non-null props and propKey. - private void setIntProperty(Properties props, - String propKey, - int propValue) { + /** + * Sets an integer property value. + * + * @param props + * @param propKey + * @param propValue + * Caller will always supply a non-null props and propKey. + */ + private void setIntProperty(Properties props, String propKey, int propValue) { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "set" + propKey, propValue); props.setProperty(propKey, Integer.valueOf(propValue).toString()); loggerExternal.exiting(getClassNameLogging(), "set" + propKey); } - // Reads a property value in int format. - // Caller will always supply a non-null props and propKey. - // Returns defaultValue if the specific property value is not set. - private int getIntProperty(Properties props, - String propKey, - int defaultValue) { + /** + * Returns a property value in int format. Caller will always supply a non-null props and propKey. Returns + * defaultValue if the specific property value is not set. + */ + private int getIntProperty(Properties props, String propKey, int defaultValue) { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "get" + propKey); String propValue = props.getProperty(propKey); @@ -881,8 +934,7 @@ private int getIntProperty(Properties props, if (null != propValue) { try { value = Integer.parseInt(propValue); - } - catch (NumberFormatException nfe) { + } catch (NumberFormatException nfe) { // This exception cannot occur as all of our properties // are set internally by int -> Integer.toString. assert false : "Bad portNumber:-" + propValue; @@ -893,31 +945,28 @@ private int getIntProperty(Properties props, return value; } - // Set a boolean property value. - // Caller will always supply a non-null props and propKey. - private void setBooleanProperty(Properties props, - String propKey, - boolean propValue) { + /** + * Set a boolean property value. Caller will always supply a non-null props and propKey. + */ + private void setBooleanProperty(Properties props, String propKey, boolean propValue) { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "set" + propKey, propValue); props.setProperty(propKey, (propValue) ? "true" : "false"); loggerExternal.exiting(getClassNameLogging(), "set" + propKey); } - // Reads a property value in boolean format. - // Caller will always supply a non-null props and propKey. - // Returns defaultValue if the specific property value is not set. - private boolean getBooleanProperty(Properties props, - String propKey, - boolean defaultValue) { + /** + * Returns a property value in boolean format. Caller will always supply a non-null props and propKey. Returns + * defaultValue if the specific property value is not set. + */ + private boolean getBooleanProperty(Properties props, String propKey, boolean defaultValue) { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "get" + propKey); String propValue = props.getProperty(propKey); Boolean value; if (null == propValue) { value = defaultValue; - } - else { + } else { // Since we set the value of the String property ourselves to // "true" or "false", we can do this. value = Boolean.valueOf(propValue); @@ -926,9 +975,7 @@ private boolean getBooleanProperty(Properties props, return value; } - private void setObjectProperty(Properties props, - String propKey, - Object propValue) { + private void setObjectProperty(Properties props, String propKey, Object propValue) { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) { loggerExternal.entering(getClassNameLogging(), "set" + propKey); } @@ -938,9 +985,7 @@ private void setObjectProperty(Properties props, loggerExternal.exiting(getClassNameLogging(), "set" + propKey); } - private Object getObjectProperty(Properties props, - String propKey, - Object defaultValue) { + private Object getObjectProperty(Properties props, String propKey, Object defaultValue) { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "get" + propKey); Object propValue = props.get(propKey); @@ -950,26 +995,21 @@ private Object getObjectProperty(Properties props, return propValue; } - // Returns a SQLServerConnection given username, password, and - // pooledConnection. - // Note that the DataSource properties set to connectionProps are used when - // creating - // the connection. - - // Both username and password can be null. - - // If pooledConnection is not null, then connection returned is attached to - // the pooledConnection - // and participates in connection pooling. - SQLServerConnection getConnectionInternal(String username, - String password, + /** + * Returns a SQLServerConnection given username, password, and pooledConnection. Note that the DataSource properties + * set to connectionProps are used when creating the connection. Both username and password can be null. If + * pooledConnection is not null, then connection returned is attached to the pooledConnection and participates in + * connection pooling. + */ + SQLServerConnection getConnectionInternal(String username, String password, SQLServerPooledConnection pooledConnection) throws SQLServerException { Properties userSuppliedProps; Properties mergedProps; // Trust store password stripped and this object got created via // Objectfactory referencing. if (trustStorePasswordStripped) - SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_referencingFailedTSP"), null, true); + SQLServerException.makeFromDriverError(null, null, + SQLServerException.getErrString("R_referencingFailedTSP"), null, true); // If username or password is passed in, clone the property set so we // don't alter original connectionProps. @@ -986,8 +1026,7 @@ SQLServerConnection getConnectionInternal(String username, userSuppliedProps.put(SQLServerDriverStringProperty.USER.toString(), username); if (null != password) userSuppliedProps.put(SQLServerDriverStringProperty.PASSWORD.toString(), password); - } - else { + } else { userSuppliedProps = connectionProps; } @@ -997,11 +1036,11 @@ SQLServerConnection getConnectionInternal(String username, // null returned properties means that the passed in URL is not // supported. if (null == urlProps) - SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_errorConnectionString"), null, true); + SQLServerException.makeFromDriverError(null, null, + SQLServerException.getErrString("R_errorConnectionString"), null, true); // Manually merge URL props and user supplied props. mergedProps = SQLServerDriver.mergeURLAndSuppliedProperties(urlProps, userSuppliedProps); - } - else { + } else { mergedProps = userSuppliedProps; } @@ -1011,8 +1050,7 @@ SQLServerConnection getConnectionInternal(String username, SQLServerConnection result = null; if (Util.use43Wrapper()) { result = new SQLServerConnection43(toString()); - } - else { + } else { result = new SQLServerConnection(toString()); } result.connect(mergedProps, pooledConnection); @@ -1035,7 +1073,8 @@ Reference getReferenceInternal(String dataSourceClassString) { if (dsLogger.isLoggable(Level.FINER)) dsLogger.finer(toString() + " creating reference for " + dataSourceClassString + "."); - Reference ref = new Reference(this.getClass().getName(), "com.microsoft.sqlserver.jdbc.SQLServerDataSourceObjectFactory", null); + Reference ref = new Reference(this.getClass().getName(), + "com.microsoft.sqlserver.jdbc.SQLServerDataSourceObjectFactory", null); if (null != dataSourceClassString) ref.add(new StringRefAddr("class", dataSourceClassString)); @@ -1053,8 +1092,7 @@ Reference getReferenceInternal(String dataSourceClassString) { // possible assert trustStorePasswordStripped == false; ref.add(new StringRefAddr("trustStorePasswordStripped", "true")); - } - else { + } else { // do not add passwords to the collection. we have normal // password if (!propertyName.contains(SQLServerDriverStringProperty.PASSWORD.toString())) @@ -1073,10 +1111,12 @@ Reference getReferenceInternal(String dataSourceClassString) { return ref; } - // Initialize this datasource from properties found inside the reference - // ref. - // Called by SQLServerDataSourceObjectFactory to initialize new DataSource - // instance. + /** + * Initializes the datasource from properties found inside the reference + * + * @param ref + * Called by SQLServerDataSourceObjectFactory to initialize new DataSource instance. + */ void initializeFromReference(javax.naming.Reference ref) { // Enumerate all the StringRefAddr objects in the Reference and assign // properties appropriately. @@ -1089,11 +1129,9 @@ void initializeFromReference(javax.naming.Reference ref) { // Special case dataSourceURL and dataSourceDescription. if ("dataSourceURL".equals(propertyName)) { dataSourceURL = propertyValue; - } - else if ("dataSourceDescription".equals(propertyName)) { + } else if ("dataSourceDescription".equals(propertyName)) { dataSourceDescription = propertyValue; - } - else if ("trustStorePasswordStripped".equals(propertyName)) { + } else if ("trustStorePasswordStripped".equals(propertyName)) { trustStorePasswordStripped = true; } // Just skip "class" StringRefAddr, it does not go into @@ -1119,8 +1157,7 @@ public T unwrap(Class iface) throws SQLException { T t; try { t = iface.cast(this); - } - catch (ClassCastException e) { + } catch (ClassCastException e) { throw new SQLServerException(e.getMessage(), e); } loggerExternal.exiting(getClassNameLogging(), "unwrap", t); diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSourceObjectFactory.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSourceObjectFactory.java index 256635954..59fc884b1 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSourceObjectFactory.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSourceObjectFactory.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -15,28 +12,26 @@ import javax.naming.Name; import javax.naming.spi.ObjectFactory; + /** - * SQLServerDataSourceObjectFactory is an object factory to materialize datasources from JNDI. + * Defines an object factory to materialize datasources from JNDI. */ - public final class SQLServerDataSourceObjectFactory implements ObjectFactory { // NOTE: Per ObjectFactory spec, the ObjectFactory class requires a public // class with public constructor. /** - * Initializes a new instance of the SQLServerDataSourceObjectFactory class. + * Constructs a SQLServerDataSourceObjectFactory. */ - public SQLServerDataSourceObjectFactory() { - } + public SQLServerDataSourceObjectFactory() {} - // getObjectInstance is a factory for rehydrating references to SQLServerDataSource and its child classes. - // Caller gets the reference by calling SQLServerDataSource.getReference. - // References are used by JNDI to persist and rehydrate objects. - public Object getObjectInstance(Object ref, - Name name, - Context c, - Hashtable h) throws SQLServerException { + /** + * Returns an reference to the SQLServerDataSource instance getObjectInstance is a factory for rehydrating + * references to SQLServerDataSource and its child classes. Caller gets the reference by calling + * SQLServerDataSource.getReference. References are used by JNDI to persist and rehydrate objects. + */ + public Object getObjectInstance(Object ref, Name name, Context c, Hashtable h) throws SQLServerException { // Create a new instance of a DataSource class from the given reference. try { javax.naming.Reference r = (javax.naming.Reference) ref; @@ -71,9 +66,8 @@ public Object getObjectInstance(Object ref, } // Class not found, throw invalid reference exception. throwInvalidDataSourceRefException(); - } - catch (ClassNotFoundException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException - | NoSuchMethodException | SecurityException e) { + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | IllegalArgumentException + | InvocationTargetException | NoSuchMethodException | SecurityException e) { throwInvalidDataSourceRefException(); } // no chance of getting here but to keep the compiler happy @@ -81,7 +75,8 @@ public Object getObjectInstance(Object ref, } private void throwInvalidDataSourceRefException() throws SQLServerException { - SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_invalidDataSourceReference"), null, true); + SQLServerException.makeFromDriverError(null, null, + SQLServerException.getErrString("R_invalidDataSourceReference"), null, true); } } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataTable.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataTable.java index 1e894bdf9..e64827187 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataTable.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataTable.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -21,6 +18,10 @@ import java.util.Set; import java.util.UUID; + +/** + * Represents the data table for SQL Server. + */ public final class SQLServerDataTable { int rowCount = 0; @@ -32,10 +33,11 @@ public final class SQLServerDataTable { private String tvpName = null; /** - * The constant in the Java programming language, sometimes referred to as a type code, that identifies the type TVP. + * The constant in the Java programming language, sometimes referred to as a type code, that identifies the type + * TVP. * * @throws SQLServerException - * when an error occurs + * when an error occurs */ // Name used in CREATE TYPE public SQLServerDataTable() throws SQLServerException { @@ -55,7 +57,7 @@ public synchronized void clear() { } /** - * Retrieves an iterator on the rows of the data table. + * Returns an iterator on the rows of the data table. * * @return an iterator on the rows of the data table. */ @@ -67,29 +69,28 @@ public synchronized Iterator> getIterator() { } /** - * Adds meta data for the specified column + * Adds meta data for the specified column. * * @param columnName - * the name of the column + * the name of the column * @param sqlType - * the sql type of the column + * the sql type of the column * @throws SQLServerException - * when an error occurs + * when an error occurs */ - public synchronized void addColumnMetadata(String columnName, - int sqlType) throws SQLServerException { + public synchronized void addColumnMetadata(String columnName, int sqlType) throws SQLServerException { // column names must be unique Util.checkDuplicateColumnName(columnName, columnNames); columnMetadata.put(columnCount++, new SQLServerDataColumn(columnName, sqlType)); } /** - * Adds meta data for the specified column + * Adds meta data for the specified column. * * @param column - * the name of the column + * the name of the column * @throws SQLServerException - * when an error occurs + * when an error occurs */ public synchronized void addColumnMetadata(SQLServerDataColumn column) throws SQLServerException { // column names must be unique @@ -101,16 +102,17 @@ public synchronized void addColumnMetadata(SQLServerDataColumn column) throws SQ * Adds one row of data to the data table. * * @param values - * values to be added in one row of data to the data table. + * values to be added in one row of data to the data table. * @throws SQLServerException - * when an error occurs + * when an error occurs */ public synchronized void addRow(Object... values) throws SQLServerException { try { int columnCount = columnMetadata.size(); if ((null != values) && values.length > columnCount) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_moreDataInRowThanColumnInTVP")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_moreDataInRowThanColumnInTVP")); Object[] msgArgs = {}; throw new SQLServerException(null, form.format(msgArgs), null, 0, false); } @@ -129,11 +131,9 @@ public synchronized void addRow(Object... values) throws SQLServerException { internalAddrow(jdbcType, val, rowValues, pair); } rows.put(rowCount++, rowValues); - } - catch (NumberFormatException e) { + } catch (NumberFormatException e) { throw new SQLServerException(SQLServerException.getErrString("R_TVPInvalidColumnValue"), e); - } - catch (ClassCastException e) { + } catch (ClassCastException e) { throw new SQLServerException(SQLServerException.getErrString("R_TVPInvalidColumnValue"), e); } @@ -143,19 +143,17 @@ public synchronized void addRow(Object... values) throws SQLServerException { * Adding rows one row of data to data table. * * @param jdbcType - * The jdbcType + * The jdbcType * @param val - * The data value + * The data value * @param rowValues - * Row of data + * Row of data * @param pair - * pair to be added to data table + * pair to be added to data table * @throws SQLServerException - * when an error occurs + * when an error occurs */ - private void internalAddrow(JDBCType jdbcType, - Object val, - Object[] rowValues, + private void internalAddrow(JDBCType jdbcType, Object val, Object[] rowValues, Map.Entry pair) throws SQLServerException { SQLServerDataColumn currentColumnMetadata = pair.getValue(); @@ -205,7 +203,8 @@ private void internalAddrow(JDBCType jdbcType, } if (isColumnMetadataUpdated) { - currentColumnMetadata.precision = currentColumnMetadata.scale + currentColumnMetadata.numberOfDigitsIntegerPart; + currentColumnMetadata.precision = currentColumnMetadata.scale + + currentColumnMetadata.numberOfDigitsIntegerPart; columnMetadata.put(pair.getKey(), currentColumnMetadata); } } @@ -230,7 +229,8 @@ private void internalAddrow(JDBCType jdbcType, case DATETIME: case SMALLDATETIME: // Sending temporal types as string. Error from database is thrown if parsing fails - // no need to send precision for temporal types, string literal will never exceed DataTypes.SHORT_VARTYPE_MAX_BYTES + // no need to send precision for temporal types, string literal will never exceed + // DataTypes.SHORT_VARTYPE_MAX_BYTES if (null == val) rowValues[pair.getKey()] = null; @@ -282,7 +282,8 @@ else if (val instanceof OffsetTime) case SQL_VARIANT: JDBCType internalJDBCType; if (null == val) { // TODO:Check this later - throw new SQLServerException(SQLServerException.getErrString("R_invalidValueForTVPWithSQLVariant"), null); + throw new SQLServerException(SQLServerException.getErrString("R_invalidValueForTVPWithSQLVariant"), + null); } JavaType javaType = JavaType.of(val); internalJDBCType = javaType.getJDBCType(SSType.UNKNOWN, jdbcType); @@ -296,8 +297,8 @@ else if (val instanceof OffsetTime) } /** - * Retrieves java.util.Map object type of columnMetaData for all columns where column indexes are mapped with their - * respective {@link SQLServerDataColumn} Java object + * Returns the java.util.Map object type of columnMetaData for all columns where column indexes are + * mapped with their respective {@link SQLServerDataColumn} Java object. * * @return Map */ @@ -306,7 +307,7 @@ public synchronized Map getColumnMetadata() { } /** - * Returns name of TVP type set by {@link #setTvpName(String)} + * Returns name of TVP type set by {@link #setTvpName(String)}. * * @return tvpName */ @@ -315,10 +316,10 @@ public String getTvpName() { } /** - * Sets the TVP Name + * Sets the TVP Name. * * @param tvpName - * the name of TVP + * the name of TVP */ public void setTvpName(String tvpName) { this.tvpName = tvpName; diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDatabaseMetaData.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDatabaseMetaData.java index 9c9fb5513..aca757bc9 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDatabaseMetaData.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDatabaseMetaData.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -21,11 +18,12 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; + /** - * SQLServerDatabaseMetaData provides JDBC database meta data. + * Provides the JDBC database meta data. * - * The API javadoc for JDBC API methods that this class implements are not repeated here. Please see Sun's JDBC API interfaces javadoc for those - * details. + * The API javadoc for JDBC API methods that this class implements are not repeated here. Please see Sun's JDBC API + * interfaces javadoc for those details. */ public final class SQLServerDatabaseMetaData implements java.sql.DatabaseMetaData { private SQLServerConnection connection; @@ -71,8 +69,7 @@ enum CallableHandles { // procs on or after katmai private final String katProc; - private CallableHandles(String name, - String katName) { + private CallableHandles(String name, String katName) { this.preKatProc = name; this.katProc = katName; } @@ -86,8 +83,7 @@ final class HandleAssociation { final String databaseName; final CallableStatement stmt; - HandleAssociation(String databaseName, - CallableStatement stmt) { + HandleAssociation(String databaseName, CallableStatement stmt) { this.databaseName = databaseName; this.stmt = stmt; } @@ -105,7 +101,7 @@ private static int nextInstanceID() { } /** - * This is a helper function to provide an ID string suitable for tracing. + * Provides a helper function to provide an ID string suitable for tracing. * * @return traceID string */ @@ -114,10 +110,10 @@ final public String toString() { } /** - * Create new database meta data + * Constructs a SQLServerDatabaseMetaData database meta data * * @param con - * the connection + * the connection */ public SQLServerDatabaseMetaData(SQLServerConnection con) { traceID = " SQLServerDatabaseMetaData:" + nextInstanceID(); @@ -138,8 +134,7 @@ public T unwrap(Class iface) throws SQLException { T t; try { t = iface.cast(this); - } - catch (ClassCastException e) { + } catch (ClassCastException e) { throw new SQLServerException(e.getMessage(), e); } return t; @@ -238,12 +233,12 @@ private void checkClosed() throws SQLServerException { private static final String IS_AUTOINCREMENT = "IS_AUTOINCREMENT"; /** - * Make a simple query execute and return the result from it. This is to be used only for internal queries without any user input. + * Returns the result from a simple query. This is to be used only for internal queries without any user input. * * @param catalog - * catalog the query to be made in + * catalog the query to be made in * @param query - * to execute + * to execute * @return Resultset from the execution * @throws SQLTimeoutException */ @@ -255,8 +250,7 @@ private SQLServerResultSet getResultSetFromInternalQueries(String catalog, SQLServerResultSet rs = null; try { rs = ((SQLServerStatement) connection.createStatement()).executeQueryInternal(query); - } - finally { + } finally { if (null != orgCat) { connection.setCatalog(orgCat); } @@ -264,8 +258,8 @@ private SQLServerResultSet getResultSetFromInternalQueries(String catalog, return rs; } - /* - * Note we pool the handles per object. + /** + * Returns the CallableStatement handle. Note we pool the handles per object. */ private CallableStatement getCallableStatementHandle(CallableHandles request, String catalog) throws SQLServerException { @@ -283,19 +277,18 @@ private CallableStatement getCallableStatementHandle(CallableHandles request, } /** - * Make the stored procedure call and return the result from it. + * Returns the result from the stored procedure call. * * @param catalog - * catalog the query to be made in + * catalog the query to be made in * @param procedure - * to execute + * to execute * @param arguments - * for the stored procedure + * for the stored procedure * @return Resultset from the execution * @throws SQLTimeoutException */ - private SQLServerResultSet getResultSetFromStoredProc(String catalog, - CallableHandles procedure, + private SQLServerResultSet getResultSetFromStoredProc(String catalog, CallableHandles procedure, String[] arguments) throws SQLServerException, SQLTimeoutException { checkClosed(); assert null != arguments; @@ -303,15 +296,15 @@ private SQLServerResultSet getResultSetFromStoredProc(String catalog, orgCat = switchCatalogs(catalog); SQLServerResultSet rs = null; try { - SQLServerCallableStatement call = (SQLServerCallableStatement) getCallableStatementHandle(procedure, catalog); + SQLServerCallableStatement call = (SQLServerCallableStatement) getCallableStatementHandle(procedure, + catalog); for (int i = 1; i <= arguments.length; i++) { // note individual arguments can be null. call.setString(i, arguments[i - 1]); } rs = (SQLServerResultSet) call.executeQueryInternal(); - } - finally { + } finally { if (null != orgCat) { connection.setCatalog(orgCat); } @@ -319,10 +312,8 @@ private SQLServerResultSet getResultSetFromStoredProc(String catalog, return rs; } - private SQLServerResultSet getResultSetWithProvidedColumnNames(String catalog, - CallableHandles procedure, - String[] arguments, - String[] columnNames) throws SQLServerException, SQLTimeoutException { + private SQLServerResultSet getResultSetWithProvidedColumnNames(String catalog, CallableHandles procedure, + String[] arguments, String[] columnNames) throws SQLServerException, SQLTimeoutException { // Execute the query SQLServerResultSet rs = getResultSetFromStoredProc(catalog, procedure, arguments); @@ -333,10 +324,10 @@ private SQLServerResultSet getResultSetWithProvidedColumnNames(String catalog, } /** - * Switch database catalogs. + * Switches the database catalogs. * * @param catalog - * the new catalog + * the new catalog * @throws SQLServerException * @return the old catalog */ @@ -446,13 +437,12 @@ public String getCatalogTerm() throws SQLServerException { return "database"; } - private static final String[] getColumnPrivilegesColumnNames = {/* 1 */ TABLE_CAT, /* 2 */ TABLE_SCHEM, /* 3 */ TABLE_NAME, /* 4 */ COLUMN_NAME, - /* 5 */ GRANTOR, /* 6 */ GRANTEE, /* 7 */ PRIVILEGE, /* 8 */ IS_GRANTABLE}; + private static final String[] getColumnPrivilegesColumnNames = {/* 1 */ TABLE_CAT, /* 2 */ TABLE_SCHEM, + /* 3 */ TABLE_NAME, /* 4 */ COLUMN_NAME, /* 5 */ GRANTOR, /* 6 */ GRANTEE, /* 7 */ PRIVILEGE, + /* 8 */ IS_GRANTABLE}; @Override - public java.sql.ResultSet getColumnPrivileges(String catalog, - String schema, - String table, + public java.sql.ResultSet getColumnPrivileges(String catalog, String schema, String table, String col) throws SQLServerException, SQLTimeoutException { if (loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn()) { loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString()); @@ -461,8 +451,8 @@ public java.sql.ResultSet getColumnPrivileges(String catalog, // column_privileges supports columns being escaped. col = EscapeIDName(col); /* - * sp_column_privileges [ @table_name = ] 'table_name' [ , [ @table_owner = ] 'table_owner' ] [ , [ @table_qualifier = ] 'table_qualifier' ] [ - * , [ @column_name = ] 'column' ] + * sp_column_privileges [ @table_name = ] 'table_name' [ , [ @table_owner = ] 'table_owner' ] [ , + * [ @table_qualifier = ] 'table_qualifier' ] [ , [ @column_name = ] 'column' ] */ String[] arguments = new String[4]; @@ -470,16 +460,15 @@ public java.sql.ResultSet getColumnPrivileges(String catalog, arguments[1] = schema; arguments[2] = catalog; arguments[3] = col; - return getResultSetWithProvidedColumnNames(catalog, CallableHandles.SP_COLUMN_PRIVILEGES, arguments, getColumnPrivilegesColumnNames); + return getResultSetWithProvidedColumnNames(catalog, CallableHandles.SP_COLUMN_PRIVILEGES, arguments, + getColumnPrivilegesColumnNames); } - private static final String[] getTablesColumnNames = {/* 1 */ TABLE_CAT, /* 2 */ TABLE_SCHEM, /* 3 */ TABLE_NAME, /* 4 */ TABLE_TYPE, - /* 5 */ REMARKS}; + private static final String[] getTablesColumnNames = {/* 1 */ TABLE_CAT, /* 2 */ TABLE_SCHEM, /* 3 */ TABLE_NAME, + /* 4 */ TABLE_TYPE, /* 5 */ REMARKS}; @Override - public java.sql.ResultSet getTables(String catalog, - String schema, - String table, + public java.sql.ResultSet getTables(String catalog, String schema, String table, String types[]) throws SQLServerException, SQLTimeoutException { if (loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn()) { loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString()); @@ -490,8 +479,8 @@ public java.sql.ResultSet getTables(String catalog, table = EscapeIDName(table); schema = EscapeIDName(schema); /* - * sp_tables [ [ @table_name = ] 'name' ] [ , [ @table_owner = ] 'owner' ] [ , [ @table_qualifier = ] 'qualifier' ] [ , [ @table_type = ] - * "type" ] + * sp_tables [ [ @table_name = ] 'name' ] [ , [ @table_owner = ] 'owner' ] [ , [ @table_qualifier = ] + * 'qualifier' ] [ , [ @table_type = ] "type" ] */ String[] arguments = new String[4]; @@ -521,8 +510,9 @@ public java.sql.ResultSet getTables(String catalog, static final char DOUBLE_RIGHT_BRACKET[] = {']', ']'}; /** - * Accepts a SQL identifier (such as a column name or table name) and escapes the identifier so sql 92 wild card characters can be escaped - * properly to be passed to functions like sp_columns or sp_tables. Assumes that the incoming identifier is unescaped. + * Accepts a SQL identifier (such as a column name or table name) and escapes the identifier so sql 92 wild card + * characters can be escaped properly to be passed to functions like sp_columns or sp_tables. Assumes that the + * incoming identifier is un-escaped. * * @inID input identifier to escape. * @return the escaped value. @@ -565,8 +555,7 @@ private static String EscapeIDName(String inID) throws SQLServerException { outID.append(ch); } - } - else { + } else { // no escape just copy outID.append(ch); } @@ -574,25 +563,25 @@ private static String EscapeIDName(String inID) throws SQLServerException { return outID.toString(); } - private static final String[] getColumnsColumnNames = {/* 1 */ TABLE_CAT, /* 2 */ TABLE_SCHEM, /* 3 */ TABLE_NAME, /* 4 */ COLUMN_NAME, - /* 5 */ DATA_TYPE, /* 6 */ TYPE_NAME, /* 7 */ COLUMN_SIZE, /* 8 */ BUFFER_LENGTH, /* 9 */ DECIMAL_DIGITS, /* 10 */ NUM_PREC_RADIX, - /* 11 */ NULLABLE, /* 12 */ REMARKS, /* 13 */ COLUMN_DEF, /* 14 */ SQL_DATA_TYPE, /* 15 */ SQL_DATETIME_SUB, /* 16 */ CHAR_OCTET_LENGTH, - /* 17 */ ORDINAL_POSITION, /* 18 */ IS_NULLABLE}; + private static final String[] getColumnsColumnNames = {/* 1 */ TABLE_CAT, /* 2 */ TABLE_SCHEM, /* 3 */ TABLE_NAME, + /* 4 */ COLUMN_NAME, /* 5 */ DATA_TYPE, /* 6 */ TYPE_NAME, /* 7 */ COLUMN_SIZE, /* 8 */ BUFFER_LENGTH, + /* 9 */ DECIMAL_DIGITS, /* 10 */ NUM_PREC_RADIX, /* 11 */ NULLABLE, /* 12 */ REMARKS, /* 13 */ COLUMN_DEF, + /* 14 */ SQL_DATA_TYPE, /* 15 */ SQL_DATETIME_SUB, /* 16 */ CHAR_OCTET_LENGTH, /* 17 */ ORDINAL_POSITION, + /* 18 */ IS_NULLABLE}; // SQL10 columns not exahustive we only need to set until the one we want to // change // in this case we want to change SS_IS_IDENTITY 22nd column to // IS_AUTOINCREMENT // to be inline with JDBC spec - private static final String[] getColumnsColumnNamesKatmai = {/* 1 */ TABLE_CAT, /* 2 */ TABLE_SCHEM, /* 3 */ TABLE_NAME, /* 4 */ COLUMN_NAME, - /* 5 */ DATA_TYPE, /* 6 */ TYPE_NAME, /* 7 */ COLUMN_SIZE, /* 8 */ BUFFER_LENGTH, /* 9 */ DECIMAL_DIGITS, /* 10 */ NUM_PREC_RADIX, - /* 11 */ NULLABLE, /* 12 */ REMARKS, /* 13 */ COLUMN_DEF, /* 14 */ SQL_DATA_TYPE, /* 15 */ SQL_DATETIME_SUB, /* 16 */ CHAR_OCTET_LENGTH, - /* 17 */ ORDINAL_POSITION, /* 18 */ IS_NULLABLE, /* 20 */ SS_IS_SPARSE, /* 20 */ SS_IS_COLUMN_SET, /* 21 */ IS_GENERATEDCOLUMN, - /* 22 */ IS_AUTOINCREMENT}; + private static final String[] getColumnsColumnNamesKatmai = {/* 1 */ TABLE_CAT, /* 2 */ TABLE_SCHEM, + /* 3 */ TABLE_NAME, /* 4 */ COLUMN_NAME, /* 5 */ DATA_TYPE, /* 6 */ TYPE_NAME, /* 7 */ COLUMN_SIZE, + /* 8 */ BUFFER_LENGTH, /* 9 */ DECIMAL_DIGITS, /* 10 */ NUM_PREC_RADIX, /* 11 */ NULLABLE, /* 12 */ REMARKS, + /* 13 */ COLUMN_DEF, /* 14 */ SQL_DATA_TYPE, /* 15 */ SQL_DATETIME_SUB, /* 16 */ CHAR_OCTET_LENGTH, + /* 17 */ ORDINAL_POSITION, /* 18 */ IS_NULLABLE, /* 20 */ SS_IS_SPARSE, /* 20 */ SS_IS_COLUMN_SET, + /* 21 */ IS_GENERATEDCOLUMN, /* 22 */ IS_AUTOINCREMENT}; @Override - public java.sql.ResultSet getColumns(String catalog, - String schema, - String table, + public java.sql.ResultSet getColumns(String catalog, String schema, String table, String col) throws SQLServerException, SQLTimeoutException { if (loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn()) { loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString()); @@ -605,8 +594,8 @@ public java.sql.ResultSet getColumns(String catalog, schema = EscapeIDName(schema); /* - * sp_columns [ @table_name = ] object [ , [ @table_owner = ] owner ] [ , [ @table_qualifier = ] qualifier ] [ , [ @column_name = ] column ] [ - * , [ @ODBCVer = ] ODBCVer ] + * sp_columns [ @table_name = ] object [ , [ @table_owner = ] owner ] [ , [ @table_qualifier = ] qualifier ] [ , + * [ @column_name = ] column ] [ , [ @ODBCVer = ] ODBCVer ] */ String[] arguments; if (connection.isKatmaiOrLater()) @@ -621,14 +610,15 @@ public java.sql.ResultSet getColumns(String catalog, arguments[4] = "2"; // give information about everything including // sparse columns arguments[5] = "3"; // odbc version - } - else + } else arguments[4] = "3"; // odbc version SQLServerResultSet rs; if (connection.isKatmaiOrLater()) - rs = getResultSetWithProvidedColumnNames(catalog, CallableHandles.SP_COLUMNS, arguments, getColumnsColumnNamesKatmai); + rs = getResultSetWithProvidedColumnNames(catalog, CallableHandles.SP_COLUMNS, arguments, + getColumnsColumnNamesKatmai); else - rs = getResultSetWithProvidedColumnNames(catalog, CallableHandles.SP_COLUMNS, arguments, getColumnsColumnNames); + rs = getResultSetWithProvidedColumnNames(catalog, CallableHandles.SP_COLUMNS, arguments, + getColumnsColumnNames); // Hook in a filter on the DATA_TYPE column of the result set we're // going to return that converts the ODBC values from sp_columns // into JDBC values. @@ -643,18 +633,18 @@ public java.sql.ResultSet getColumns(String catalog, return rs; } - private static final String[] getFunctionsColumnNames = {/* 1 */ FUNCTION_CAT, /* 2 */ FUNCTION_SCHEM, /* 3 */ FUNCTION_NAME, - /* 4 */ NUM_INPUT_PARAMS, /* 5 */ NUM_OUTPUT_PARAMS, /* 6 */ NUM_RESULT_SETS, /* 7 */ REMARKS, /* 8 */ FUNCTION_TYPE}; + private static final String[] getFunctionsColumnNames = {/* 1 */ FUNCTION_CAT, /* 2 */ FUNCTION_SCHEM, + /* 3 */ FUNCTION_NAME, /* 4 */ NUM_INPUT_PARAMS, /* 5 */ NUM_OUTPUT_PARAMS, /* 6 */ NUM_RESULT_SETS, + /* 7 */ REMARKS, /* 8 */ FUNCTION_TYPE}; @Override - public java.sql.ResultSet getFunctions(String catalog, - String schemaPattern, + public java.sql.ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern) throws SQLException { checkClosed(); /* - * sp_stored_procedures [ [ @sp_name = ] 'name' ] [ , [ @sp_owner = ] 'schema'] [ , [ @sp_qualifier = ] 'qualifier' ] [ , [@fUsePattern = ] - * 'fUsePattern' ] + * sp_stored_procedures [ [ @sp_name = ] 'name' ] [ , [ @sp_owner = ] 'schema'] [ , [ @sp_qualifier = ] + * 'qualifier' ] [ , [@fUsePattern = ] 'fUsePattern' ] */ // use default ie use pattern matching. // catalog cannot be empty in sql server if (catalog != null && catalog.length() == 0) { @@ -667,23 +657,23 @@ public java.sql.ResultSet getFunctions(String catalog, arguments[0] = EscapeIDName(functionNamePattern); arguments[1] = EscapeIDName(schemaPattern); arguments[2] = catalog; - return getResultSetWithProvidedColumnNames(catalog, CallableHandles.SP_STORED_PROCEDURES, arguments, getFunctionsColumnNames); + return getResultSetWithProvidedColumnNames(catalog, CallableHandles.SP_STORED_PROCEDURES, arguments, + getFunctionsColumnNames); } - private static final String[] getFunctionsColumnsColumnNames = {/* 1 */ FUNCTION_CAT, /* 2 */ FUNCTION_SCHEM, /* 3 */ FUNCTION_NAME, - /* 4 */ COLUMN_NAME, /* 5 */ COLUMN_TYPE, /* 6 */ DATA_TYPE, /* 7 */ TYPE_NAME, /* 8 */ PRECISION, /* 9 */ LENGTH, /* 10 */ SCALE, - /* 11 */ RADIX, /* 12 */ NULLABLE, /* 13 */ REMARKS, /* 14 */ COLUMN_DEF, /* 15 */ SQL_DATA_TYPE, /* 16 */ SQL_DATETIME_SUB, - /* 17 */ CHAR_OCTET_LENGTH, /* 18 */ ORDINAL_POSITION, /* 19 */ IS_NULLABLE}; + private static final String[] getFunctionsColumnsColumnNames = {/* 1 */ FUNCTION_CAT, /* 2 */ FUNCTION_SCHEM, + /* 3 */ FUNCTION_NAME, /* 4 */ COLUMN_NAME, /* 5 */ COLUMN_TYPE, /* 6 */ DATA_TYPE, /* 7 */ TYPE_NAME, + /* 8 */ PRECISION, /* 9 */ LENGTH, /* 10 */ SCALE, /* 11 */ RADIX, /* 12 */ NULLABLE, /* 13 */ REMARKS, + /* 14 */ COLUMN_DEF, /* 15 */ SQL_DATA_TYPE, /* 16 */ SQL_DATETIME_SUB, /* 17 */ CHAR_OCTET_LENGTH, + /* 18 */ ORDINAL_POSITION, /* 19 */ IS_NULLABLE}; @Override - public java.sql.ResultSet getFunctionColumns(String catalog, - String schemaPattern, - String functionNamePattern, + public java.sql.ResultSet getFunctionColumns(String catalog, String schemaPattern, String functionNamePattern, String columnNamePattern) throws SQLException { checkClosed(); /* - * sp_sproc_columns [[@procedure_name =] 'name'] [,[@procedure_owner =] 'owner'] [,[@procedure_qualifier =] 'qualifier'] [,[@column_name =] - * 'column_name'] [,[@ODBCVer =] 'ODBCVer'] + * sp_sproc_columns [[@procedure_name =] 'name'] [,[@procedure_owner =] 'owner'] [,[@procedure_qualifier =] + * 'qualifier'] [,[@column_name =] 'column_name'] [,[@ODBCVer =] 'ODBCVer'] */ // catalog cannot be empty in sql server @@ -703,8 +693,8 @@ public java.sql.ResultSet getFunctionColumns(String catalog, // col name supports escaping arguments[3] = EscapeIDName(columnNamePattern); arguments[4] = "3"; - SQLServerResultSet rs = getResultSetWithProvidedColumnNames(catalog, CallableHandles.SP_SPROC_COLUMNS, arguments, - getFunctionsColumnsColumnNames); + SQLServerResultSet rs = getResultSetWithProvidedColumnNames(catalog, CallableHandles.SP_SPROC_COLUMNS, + arguments, getFunctionsColumnsColumnNames); // Hook in a filter on the DATA_TYPE column of the result set we're // going to return that converts the ODBC values from sp_columns @@ -729,22 +719,21 @@ public java.sql.ResultSet getClientInfoProperties() throws SQLException { /* 4 */ " cast(NULL as char(1)) as DESCRIPTION " + " where 0 = 1"); } - private static final String[] getBestRowIdentifierColumnNames = {/* 1 */ SCOPE, /* 2 */ COLUMN_NAME, /* 3 */ DATA_TYPE, /* 4 */ TYPE_NAME, - /* 5 */ COLUMN_SIZE, /* 6 */ BUFFER_LENGTH, /* 7 */ DECIMAL_DIGITS, /* 8 */ PSEUDO_COLUMN}; + private static final String[] getBestRowIdentifierColumnNames = {/* 1 */ SCOPE, /* 2 */ COLUMN_NAME, + /* 3 */ DATA_TYPE, /* 4 */ TYPE_NAME, /* 5 */ COLUMN_SIZE, /* 6 */ BUFFER_LENGTH, /* 7 */ DECIMAL_DIGITS, + /* 8 */ PSEUDO_COLUMN}; @Override - public java.sql.ResultSet getBestRowIdentifier(String catalog, - String schema, - String table, - int scope, + public java.sql.ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, boolean nullable) throws SQLServerException, SQLTimeoutException { if (loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn()) { loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString()); } checkClosed(); /* - * sp_special_columns [@table_name =] 'table_name' [,[@table_owner =] 'table_owner'] [,[@qualifier =] 'qualifier'] [,[@col_type =] 'col_type'] - * [,[@scope =] 'scope'] [,[@nullable =] 'nullable'] [,[@ODBCVer =] 'ODBCVer'] ; + * sp_special_columns [@table_name =] 'table_name' [,[@table_owner =] 'table_owner'] [,[@qualifier =] + * 'qualifier'] [,[@col_type =] 'col_type'] [,[@scope =] 'scope'] [,[@nullable =] 'nullable'] [,[@ODBCVer =] + * 'ODBCVer'] ; */ String[] arguments = new String[7]; arguments[0] = table; @@ -760,8 +749,8 @@ public java.sql.ResultSet getBestRowIdentifier(String catalog, else arguments[5] = "O"; // nullable arguments[6] = "3"; // Use 3 unless required otherwise - SQLServerResultSet rs = getResultSetWithProvidedColumnNames(catalog, CallableHandles.SP_SPECIAL_COLUMNS, arguments, - getBestRowIdentifierColumnNames); + SQLServerResultSet rs = getResultSetWithProvidedColumnNames(catalog, CallableHandles.SP_SPECIAL_COLUMNS, + arguments, getBestRowIdentifierColumnNames); // Hook in a filter on the DATA_TYPE column of the result set we're // going to return that converts the ODBC values from sp_columns @@ -771,11 +760,7 @@ public java.sql.ResultSet getBestRowIdentifier(String catalog, } @Override - public java.sql.ResultSet getCrossReference(String cat1, - String schem1, - String tab1, - String cat2, - String schem2, + public java.sql.ResultSet getCrossReference(String cat1, String schem1, String tab1, String cat2, String schem2, String tab2) throws SQLServerException, SQLTimeoutException { if (loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn()) { loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString()); @@ -783,8 +768,9 @@ public java.sql.ResultSet getCrossReference(String cat1, checkClosed(); /* - * sp_fkeys [ @pktable_name = ] 'pktable_name' [ , [ @pktable_owner = ] 'pktable_owner' ] [ , [ @pktable_qualifier = ] 'pktable_qualifier' ] { - * , [ @fktable_name = ] 'fktable_name' } [ , [ @fktable_owner = ] 'fktable_owner' ] [ , [ @fktable_qualifier = ] 'fktable_qualifier' ] + * sp_fkeys [ @pktable_name = ] 'pktable_name' [ , [ @pktable_owner = ] 'pktable_owner' ] [ , + * [ @pktable_qualifier = ] 'pktable_qualifier' ] { , [ @fktable_name = ] 'fktable_name' } [ , [ @fktable_owner + * = ] 'fktable_owner' ] [ , [ @fktable_qualifier = ] 'fktable_qualifier' ] */ String[] arguments = {tab1, schem1, cat1, tab2, schem2, cat2}; return executeSPFkeys(arguments); @@ -839,8 +825,7 @@ public String getDriverVersion() throws SQLServerException { } @Override - public java.sql.ResultSet getExportedKeys(String cat, - String schema, + public java.sql.ResultSet getExportedKeys(String cat, String schema, String table) throws SQLServerException, SQLTimeoutException { return getCrossReference(cat, schema, table, null, null, null); } @@ -858,40 +843,42 @@ public String getIdentifierQuoteString() throws SQLServerException { } @Override - public java.sql.ResultSet getImportedKeys(String cat, - String schema, + public java.sql.ResultSet getImportedKeys(String cat, String schema, String table) throws SQLServerException, SQLTimeoutException { return getCrossReference(null, null, null, cat, schema, table); } private ResultSet executeSPFkeys(String[] procParams) throws SQLServerException, SQLTimeoutException { String tempTableName = "@jdbc_temp_fkeys_result"; - String sql = "DECLARE " + tempTableName + " table (PKTABLE_QUALIFIER sysname, " + "PKTABLE_OWNER sysname, " + "PKTABLE_NAME sysname, " - + "PKCOLUMN_NAME sysname, " + "FKTABLE_QUALIFIER sysname, " + "FKTABLE_OWNER sysname, " + "FKTABLE_NAME sysname, " - + "FKCOLUMN_NAME sysname, " + "KEY_SEQ smallint, " + "UPDATE_RULE smallint, " + "DELETE_RULE smallint, " + "FK_NAME sysname, " - + "PK_NAME sysname, " + "DEFERRABILITY smallint);" + "INSERT INTO " + tempTableName + " EXEC sp_fkeys ?,?,?,?,?,?;" - + "SELECT t.PKTABLE_QUALIFIER AS PKTABLE_CAT, " + "t.PKTABLE_OWNER AS PKTABLE_SCHEM, " + "t.PKTABLE_NAME, " + "t.PKCOLUMN_NAME, " - + "t.FKTABLE_QUALIFIER AS FKTABLE_CAT, " + "t.FKTABLE_OWNER AS FKTABLE_SCHEM, " + "t.FKTABLE_NAME, " + "t.FKCOLUMN_NAME, " - + "t.KEY_SEQ, " + "CASE s.update_referential_action " + "WHEN 1 THEN 0 " + // cascade - // - - // note - // that - // sp_fkey - // and - // sys.foreign_keys - // have - // flipped - // values - // for - // cascade - // and - // no - // action + String sql = "DECLARE " + tempTableName + " table (PKTABLE_QUALIFIER sysname, " + "PKTABLE_OWNER sysname, " + + "PKTABLE_NAME sysname, " + "PKCOLUMN_NAME sysname, " + "FKTABLE_QUALIFIER sysname, " + + "FKTABLE_OWNER sysname, " + "FKTABLE_NAME sysname, " + "FKCOLUMN_NAME sysname, " + + "KEY_SEQ smallint, " + "UPDATE_RULE smallint, " + "DELETE_RULE smallint, " + "FK_NAME sysname, " + + "PK_NAME sysname, " + "DEFERRABILITY smallint);" + "INSERT INTO " + tempTableName + + " EXEC sp_fkeys ?,?,?,?,?,?;" + "SELECT t.PKTABLE_QUALIFIER AS PKTABLE_CAT, " + + "t.PKTABLE_OWNER AS PKTABLE_SCHEM, " + "t.PKTABLE_NAME, " + "t.PKCOLUMN_NAME, " + + "t.FKTABLE_QUALIFIER AS FKTABLE_CAT, " + "t.FKTABLE_OWNER AS FKTABLE_SCHEM, " + "t.FKTABLE_NAME, " + + "t.FKCOLUMN_NAME, " + "t.KEY_SEQ, " + "CASE s.update_referential_action " + "WHEN 1 THEN 0 " + // cascade + // - + // note + // that + // sp_fkey + // and + // sys.foreign_keys + // have + // flipped + // values + // for + // cascade + // and + // no + // action "WHEN 0 THEN 3 " + // no action "WHEN 2 THEN 2 " + // set null "WHEN 3 THEN 4 " + // set default - "END as UPDATE_RULE, " + "CASE s.delete_referential_action " + "WHEN 1 THEN 0 " + "WHEN 0 THEN 3 " + "WHEN 2 THEN 2 " - + "WHEN 3 THEN 4 " + "END as DELETE_RULE, " + "t.FK_NAME, " + "t.PK_NAME, " + "t.DEFERRABILITY " + "FROM " + tempTableName + " t " + "END as UPDATE_RULE, " + "CASE s.delete_referential_action " + "WHEN 1 THEN 0 " + "WHEN 0 THEN 3 " + + "WHEN 2 THEN 2 " + "WHEN 3 THEN 4 " + "END as DELETE_RULE, " + "t.FK_NAME, " + "t.PK_NAME, " + + "t.DEFERRABILITY " + "FROM " + tempTableName + " t " + "LEFT JOIN sys.foreign_keys s ON t.FK_NAME = s.name collate database_default;"; SQLServerCallableStatement cstmt = (SQLServerCallableStatement) connection.prepareCall(sql); for (int i = 0; i < 6; i++) { @@ -900,8 +887,7 @@ private ResultSet executeSPFkeys(String[] procParams) throws SQLServerException, String currentDB = null; if (procParams[2] != null && procParams[2] != "") {// pktable_qualifier currentDB = switchCatalogs(procParams[2]); - } - else if (procParams[5] != null && procParams[5] != "") {// fktable_qualifier + } else if (procParams[5] != null && procParams[5] != "") {// fktable_qualifier currentDB = switchCatalogs(procParams[5]); } ResultSet rs = cstmt.executeQuery(); @@ -911,23 +897,21 @@ else if (procParams[5] != null && procParams[5] != "") {// fktable_qualifier return rs; } - private static final String[] getIndexInfoColumnNames = {/* 1 */ TABLE_CAT, /* 2 */ TABLE_SCHEM, /* 3 */ TABLE_NAME, /* 4 */ NON_UNIQUE, - /* 5 */ INDEX_QUALIFIER, /* 6 */ INDEX_NAME, /* 7 */ TYPE, /* 8 */ ORDINAL_POSITION, /* 9 */ COLUMN_NAME, /* 10 */ ASC_OR_DESC, - /* 11 */ CARDINALITY, /* 12 */ PAGES, /* 13 */ FILTER_CONDITION}; + private static final String[] getIndexInfoColumnNames = {/* 1 */ TABLE_CAT, /* 2 */ TABLE_SCHEM, /* 3 */ TABLE_NAME, + /* 4 */ NON_UNIQUE, /* 5 */ INDEX_QUALIFIER, /* 6 */ INDEX_NAME, /* 7 */ TYPE, /* 8 */ ORDINAL_POSITION, + /* 9 */ COLUMN_NAME, /* 10 */ ASC_OR_DESC, /* 11 */ CARDINALITY, /* 12 */ PAGES, /* 13 */ FILTER_CONDITION}; @Override - public java.sql.ResultSet getIndexInfo(String cat, - String schema, - String table, - boolean unique, + public java.sql.ResultSet getIndexInfo(String cat, String schema, String table, boolean unique, boolean approximate) throws SQLServerException, SQLTimeoutException { if (loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn()) { loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString()); } checkClosed(); /* - * sp_statistics [ @table_name = ] 'table_name' [ , [ @table_owner = ] 'owner' ] [ , [ @table_qualifier = ] 'qualifier' ] [ , [ @index_name = - * ] 'index_name' ] [ , [ @is_unique = ] 'is_unique' ] [ , [ @accuracy = ] 'accuracy' ] + * sp_statistics [ @table_name = ] 'table_name' [ , [ @table_owner = ] 'owner' ] [ , [ @table_qualifier = ] + * 'qualifier' ] [ , [ @index_name = ] 'index_name' ] [ , [ @is_unique = ] 'is_unique' ] [ , [ @accuracy = ] + * 'accuracy' ] */ String[] arguments = new String[6]; arguments[0] = table; @@ -943,7 +927,8 @@ public java.sql.ResultSet getIndexInfo(String cat, arguments[5] = "Q"; else arguments[5] = "E"; - return getResultSetWithProvidedColumnNames(cat, CallableHandles.SP_STATISTICS, arguments, getIndexInfoColumnNames); + return getResultSetWithProvidedColumnNames(cat, CallableHandles.SP_STATISTICS, arguments, + getIndexInfoColumnNames); } @Override @@ -1009,8 +994,7 @@ public int getMaxConnections() throws SQLServerException, SQLTimeoutException { if (!rs.next()) return 0; return rs.getInt("maximum"); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { return 0; } @@ -1090,12 +1074,11 @@ public String getNumericFunctions() throws SQLServerException { return "ABS,ACOS,ASIN,ATAN,ATAN2,CEILING,COS,COT,DEGREES,EXP, FLOOR,LOG,LOG10,MOD,PI,POWER,RADIANS,RAND,ROUND,SIGN,SIN,SQRT,TAN,TRUNCATE"; } - private static final String[] getPrimaryKeysColumnNames = {/* 1 */ TABLE_CAT, /* 2 */ TABLE_SCHEM, /* 3 */ TABLE_NAME, /* 4 */ COLUMN_NAME, - /* 5 */ KEY_SEQ, /* 6 */ PK_NAME}; + private static final String[] getPrimaryKeysColumnNames = {/* 1 */ TABLE_CAT, /* 2 */ TABLE_SCHEM, + /* 3 */ TABLE_NAME, /* 4 */ COLUMN_NAME, /* 5 */ KEY_SEQ, /* 6 */ PK_NAME}; @Override - public java.sql.ResultSet getPrimaryKeys(String cat, - String schema, + public java.sql.ResultSet getPrimaryKeys(String cat, String schema, String table) throws SQLServerException, SQLTimeoutException { if (loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn()) { loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString()); @@ -1111,23 +1094,22 @@ public java.sql.ResultSet getPrimaryKeys(String cat, return getResultSetWithProvidedColumnNames(cat, CallableHandles.SP_PKEYS, arguments, getPrimaryKeysColumnNames); } - private static final String[] getProcedureColumnsColumnNames = {/* 1 */ PROCEDURE_CAT, /* 2 */ PROCEDURE_SCHEM, /* 3 */ PROCEDURE_NAME, - /* 4 */ COLUMN_NAME, /* 5 */ COLUMN_TYPE, /* 6 */ DATA_TYPE, /* 7 */ TYPE_NAME, /* 8 */ PRECISION, /* 9 */ LENGTH, /* 10 */ SCALE, - /* 11 */ RADIX, /* 12 */ NULLABLE, /* 13 */ REMARKS, /* 14 */ COLUMN_DEF, /* 15 */ SQL_DATA_TYPE, /* 16 */ SQL_DATETIME_SUB, - /* 17 */ CHAR_OCTET_LENGTH, /* 18 */ ORDINAL_POSITION, /* 19 */ IS_NULLABLE}; + private static final String[] getProcedureColumnsColumnNames = {/* 1 */ PROCEDURE_CAT, /* 2 */ PROCEDURE_SCHEM, + /* 3 */ PROCEDURE_NAME, /* 4 */ COLUMN_NAME, /* 5 */ COLUMN_TYPE, /* 6 */ DATA_TYPE, /* 7 */ TYPE_NAME, + /* 8 */ PRECISION, /* 9 */ LENGTH, /* 10 */ SCALE, /* 11 */ RADIX, /* 12 */ NULLABLE, /* 13 */ REMARKS, + /* 14 */ COLUMN_DEF, /* 15 */ SQL_DATA_TYPE, /* 16 */ SQL_DATETIME_SUB, /* 17 */ CHAR_OCTET_LENGTH, + /* 18 */ ORDINAL_POSITION, /* 19 */ IS_NULLABLE}; @Override - public java.sql.ResultSet getProcedureColumns(String catalog, - String schema, - String proc, + public java.sql.ResultSet getProcedureColumns(String catalog, String schema, String proc, String col) throws SQLServerException, SQLTimeoutException { if (loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn()) { loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString()); } checkClosed(); /* - * sp_sproc_columns [[@procedure_name =] 'name'] [,[@procedure_owner =] 'owner'] [,[@procedure_qualifier =] 'qualifier'] [,[@column_name =] - * 'column_name'] [,[@ODBCVer =] 'ODBCVer'] + * sp_sproc_columns [[@procedure_name =] 'name'] [,[@procedure_owner =] 'owner'] [,[@procedure_qualifier =] + * 'qualifier'] [,[@column_name =] 'column_name'] [,[@ODBCVer =] 'ODBCVer'] */ String[] arguments = new String[5]; @@ -1141,8 +1123,8 @@ public java.sql.ResultSet getProcedureColumns(String catalog, col = EscapeIDName(col); arguments[3] = col; arguments[4] = "3"; - SQLServerResultSet rs = getResultSetWithProvidedColumnNames(catalog, CallableHandles.SP_SPROC_COLUMNS, arguments, - getProcedureColumnsColumnNames); + SQLServerResultSet rs = getResultSetWithProvidedColumnNames(catalog, CallableHandles.SP_SPROC_COLUMNS, + arguments, getProcedureColumnsColumnNames); // Hook in a filter on the DATA_TYPE column of the result set we're // going to return that converts the ODBC values from sp_columns @@ -1157,12 +1139,12 @@ public java.sql.ResultSet getProcedureColumns(String catalog, return rs; } - private static final String[] getProceduresColumnNames = {/* 1 */ PROCEDURE_CAT, /* 2 */ PROCEDURE_SCHEM, /* 3 */ PROCEDURE_NAME, - /* 4 */ NUM_INPUT_PARAMS, /* 5 */ NUM_OUTPUT_PARAMS, /* 6 */ NUM_RESULT_SETS, /* 7 */ REMARKS, /* 8 */ PROCEDURE_TYPE}; + private static final String[] getProceduresColumnNames = {/* 1 */ PROCEDURE_CAT, /* 2 */ PROCEDURE_SCHEM, + /* 3 */ PROCEDURE_NAME, /* 4 */ NUM_INPUT_PARAMS, /* 5 */ NUM_OUTPUT_PARAMS, /* 6 */ NUM_RESULT_SETS, + /* 7 */ REMARKS, /* 8 */ PROCEDURE_TYPE}; @Override - public java.sql.ResultSet getProcedures(String catalog, - String schema, + public java.sql.ResultSet getProcedures(String catalog, String schema, String proc) throws SQLServerException, SQLTimeoutException { if (loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn()) { loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString()); @@ -1170,14 +1152,15 @@ public java.sql.ResultSet getProcedures(String catalog, checkClosed(); /* - * sp_stored_procedures [ [ @sp_name = ] 'name' ] [ , [ @sp_owner = ] 'schema'] [ , [ @sp_qualifier = ] 'qualifier' ] [ , [@fUsePattern = ] - * 'fUsePattern' ] + * sp_stored_procedures [ [ @sp_name = ] 'name' ] [ , [ @sp_owner = ] 'schema'] [ , [ @sp_qualifier = ] + * 'qualifier' ] [ , [@fUsePattern = ] 'fUsePattern' ] */ String[] arguments = new String[3]; arguments[0] = EscapeIDName(proc); arguments[1] = schema; arguments[2] = catalog; - return getResultSetWithProvidedColumnNames(catalog, CallableHandles.SP_STORED_PROCEDURES, arguments, getProceduresColumnNames); + return getResultSetWithProvidedColumnNames(catalog, CallableHandles.SP_STORED_PROCEDURES, arguments, + getProceduresColumnNames); } @Override @@ -1187,9 +1170,7 @@ public String getProcedureTerm() throws SQLServerException { } @Override - public ResultSet getPseudoColumns(String catalog, - String schemaPattern, - String tableNamePattern, + public ResultSet getPseudoColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException { if (loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn()) { loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString()); @@ -1253,13 +1234,11 @@ private java.sql.ResultSet getSchemasInternal(String catalog, s = "select " + schemaName + " 'TABLE_SCHEM',"; if (null != catalog && catalog.length() == 0) { s += "null 'TABLE_CATALOG' "; - } - else { + } else { s += " CASE WHEN " + schemaName + " IN " + constSchemas + " THEN null ELSE "; if (null != catalog && catalog.length() != 0) { s += "'" + catalog + "' "; - } - else + } else s += " DB_NAME() "; s += " END 'TABLE_CATALOG' "; @@ -1274,8 +1253,7 @@ private java.sql.ResultSet getSchemasInternal(String catalog, else s += " where "; s += schemaName + " in " + constSchemas; - } - else if (null != schemaPattern) + } else if (null != schemaPattern) s += " where " + schemaName + " like ? "; s += " order by 2, 1"; @@ -1286,8 +1264,7 @@ else if (null != schemaPattern) if (null == schemaPattern) { catalog = null; rs = getResultSetFromInternalQueries(catalog, s); - } - else { + } else { // The prepared statement is not closed after execution. // Yes we will "leak a server handle" per execution but the @@ -1301,8 +1278,7 @@ else if (null != schemaPattern) } @Override - public java.sql.ResultSet getSchemas(String catalog, - String schemaPattern) throws SQLException { + public java.sql.ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException { if (loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn()) { loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString()); } @@ -1340,12 +1316,11 @@ public String getSystemFunctions() throws SQLServerException { // CTS certification. } - private static final String[] getTablePrivilegesColumnNames = {/* 1 */ TABLE_CAT, /* 2 */ TABLE_SCHEM, /* 3 */ TABLE_NAME, /* 4 */ GRANTOR, - /* 5 */ GRANTEE, /* 6 */ PRIVILEGE, /* 7 */ IS_GRANTABLE}; + private static final String[] getTablePrivilegesColumnNames = {/* 1 */ TABLE_CAT, /* 2 */ TABLE_SCHEM, + /* 3 */ TABLE_NAME, /* 4 */ GRANTOR, /* 5 */ GRANTEE, /* 6 */ PRIVILEGE, /* 7 */ IS_GRANTABLE}; @Override - public java.sql.ResultSet getTablePrivileges(String catalog, - String schema, + public java.sql.ResultSet getTablePrivileges(String catalog, String schema, String table) throws SQLServerException, SQLTimeoutException { if (loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn()) { loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString()); @@ -1354,15 +1329,16 @@ public java.sql.ResultSet getTablePrivileges(String catalog, table = EscapeIDName(table); schema = EscapeIDName(schema); /* - * sp_table_privileges [ @table_name = ] 'table_name' [ , [ @table_owner = ] 'table_owner' ] [ , [ @table_qualifier = ] 'table_qualifier' ] [ - * , [@fUsePattern =] 'fUsePattern'] + * sp_table_privileges [ @table_name = ] 'table_name' [ , [ @table_owner = ] 'table_owner' ] [ , + * [ @table_qualifier = ] 'table_qualifier' ] [ , [@fUsePattern =] 'fUsePattern'] */ String[] arguments = new String[3]; arguments[0] = table; arguments[1] = schema; arguments[2] = catalog; - return getResultSetWithProvidedColumnNames(catalog, CallableHandles.SP_TABLE_PRIVILEGES, arguments, getTablePrivilegesColumnNames); + return getResultSetWithProvidedColumnNames(catalog, CallableHandles.SP_TABLE_PRIVILEGES, arguments, + getTablePrivilegesColumnNames); } @Override @@ -1425,7 +1401,8 @@ public String getURL() throws SQLServerException { // making sure no security info is exposed. if (!name.equals(SQLServerDriverBooleanProperty.INTEGRATED_SECURITY.toString()) - && !name.equals(SQLServerDriverStringProperty.USER.toString()) && !name.equals(SQLServerDriverStringProperty.PASSWORD.toString()) + && !name.equals(SQLServerDriverStringProperty.USER.toString()) + && !name.equals(SQLServerDriverStringProperty.PASSWORD.toString()) && !name.equals(SQLServerDriverStringProperty.KEY_STORE_SECRET.toString())) { String val = info[index].value; // skip empty strings @@ -1434,14 +1411,11 @@ public String getURL() throws SQLServerException { // number as these go in the front if (name.equals(SQLServerDriverStringProperty.SERVER_NAME.toString())) { serverName = val; - } - else if (name.equals(SQLServerDriverStringProperty.INSTANCE_NAME.toString())) { + } else if (name.equals(SQLServerDriverStringProperty.INSTANCE_NAME.toString())) { instanceName = val; - } - else if (name.equals(SQLServerDriverIntProperty.PORT_NUMBER.toString())) { + } else if (name.equals(SQLServerDriverIntProperty.PORT_NUMBER.toString())) { portNumber = val; - } - else { + } else { // build name value pairs separated by a semi colon url.append(name); url.append("="); @@ -1487,8 +1461,7 @@ public String getUserName() throws SQLServerException, SQLTimeoutException { assert next; result = rs.getString(1); - } - finally { + } finally { if (rs != null) { rs.close(); } @@ -1499,20 +1472,21 @@ public String getUserName() throws SQLServerException, SQLTimeoutException { return result; } - private static final String[] getVersionColumnsColumnNames = {/* 1 */ SCOPE, /* 2 */ COLUMN_NAME, /* 3 */ DATA_TYPE, /* 4 */ TYPE_NAME, - /* 5 */ COLUMN_SIZE, /* 6 */ BUFFER_LENGTH, /* 7 */ DECIMAL_DIGITS, /* 8 */ PSEUDO_COLUMN}; + private static final String[] getVersionColumnsColumnNames = {/* 1 */ SCOPE, /* 2 */ COLUMN_NAME, /* 3 */ DATA_TYPE, + /* 4 */ TYPE_NAME, /* 5 */ COLUMN_SIZE, /* 6 */ BUFFER_LENGTH, /* 7 */ DECIMAL_DIGITS, + /* 8 */ PSEUDO_COLUMN}; @Override - public java.sql.ResultSet getVersionColumns(String catalog, - String schema, + public java.sql.ResultSet getVersionColumns(String catalog, String schema, String table) throws SQLServerException, SQLTimeoutException { if (loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn()) { loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString()); } checkClosed(); /* - * sp_special_columns [@table_name =] 'table_name' [,[@table_owner =] 'table_owner'] [,[@qualifier =] 'qualifier'] [,[@col_type =] 'col_type'] - * [,[@scope =] 'scope'] [,[@nullable =] 'nullable'] [,[@ODBCVer =] 'ODBCVer'] ; + * sp_special_columns [@table_name =] 'table_name' [,[@table_owner =] 'table_owner'] [,[@qualifier =] + * 'qualifier'] [,[@col_type =] 'col_type'] [,[@scope =] 'scope'] [,[@nullable =] 'nullable'] [,[@ODBCVer =] + * 'ODBCVer'] ; */ String[] arguments = new String[7]; arguments[0] = table; @@ -1522,8 +1496,8 @@ public java.sql.ResultSet getVersionColumns(String catalog, arguments[4] = "T"; // scope arguments[5] = "U"; // nullable arguments[6] = "3"; // odbc ver - SQLServerResultSet rs = getResultSetWithProvidedColumnNames(catalog, CallableHandles.SP_SPECIAL_COLUMNS, arguments, - getVersionColumnsColumnNames); + SQLServerResultSet rs = getResultSetWithProvidedColumnNames(catalog, CallableHandles.SP_SPECIAL_COLUMNS, + arguments, getVersionColumnsColumnNames); // Hook in a filter on the DATA_TYPE column of the result set we're // going to return that converts the ODBC values from sp_columns @@ -1683,8 +1657,7 @@ public boolean supportsConvert() throws SQLServerException { } @Override - public boolean supportsConvert(int fromType, - int toType) throws SQLServerException { + public boolean supportsConvert(int fromType, int toType) throws SQLServerException { checkClosed(); return true; } @@ -1994,8 +1967,7 @@ public boolean supportsResultSetType(int type) throws SQLServerException { } @Override - public boolean supportsResultSetConcurrency(int type, - int concurrency) throws SQLServerException { + public boolean supportsResultSetConcurrency(int type, int concurrency) throws SQLServerException { checkClosed(); checkResultType(type); checkConcurrencyType(concurrency); @@ -2137,9 +2109,7 @@ public boolean supportsBatchUpdates() throws SQLServerException { } @Override - public java.sql.ResultSet getUDTs(String catalog, - String schemaPattern, - String typeNamePattern, + public java.sql.ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, int[] types) throws SQLServerException, SQLTimeoutException { if (loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn()) { loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString()); @@ -2181,8 +2151,7 @@ public int getDatabaseMajorVersion() throws SQLServerException { s = s.substring(0, p); try { return Integer.parseInt(s); - } - catch (NumberFormatException e) { + } catch (NumberFormatException e) { return 0; } } @@ -2197,8 +2166,7 @@ public int getDatabaseMinorVersion() throws SQLServerException { s = s.substring(p + 1, q); try { return Integer.parseInt(s); - } - catch (NumberFormatException e) { + } catch (NumberFormatException e) { return 0; } } @@ -2243,9 +2211,7 @@ public boolean supportsResultSetHoldability(int holdability) throws SQLServerExc } @Override - public ResultSet getAttributes(String catalog, - String schemaPattern, - String typeNamePattern, + public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern, String attributeNamePattern) throws SQLServerException, SQLTimeoutException { if (loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn()) { loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString()); @@ -2276,8 +2242,7 @@ public ResultSet getAttributes(String catalog, } @Override - public ResultSet getSuperTables(String catalog, - String schemaPattern, + public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern) throws SQLServerException, SQLTimeoutException { if (loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn()) { loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString()); @@ -2291,8 +2256,7 @@ public ResultSet getSuperTables(String catalog, } @Override - public ResultSet getSuperTypes(String catalog, - String schemaPattern, + public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern) throws SQLServerException, SQLTimeoutException { if (loggerExternal.isLoggable(Level.FINER) && Util.IsActivityTraceOn()) { loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString()); @@ -2350,8 +2314,11 @@ public boolean locatorsUpdateCopy() throws SQLException { } } -// Filter to convert DATA_TYPE column values from the ODBC types -// returned by SQL Server to their equivalent JDBC types. + +/** + * Provides filter to convert DATA_TYPE column values from the ODBC types returned by SQL Server to their equivalent + * JDBC types. + */ final class DataTypeFilter extends IntColumnFilter { private static final int ODBC_SQL_GUID = -11; private static final int ODBC_SQL_WCHAR = -8; @@ -2388,6 +2355,7 @@ int oneValueToAnother(int odbcType) { } + class ZeroFixupFilter extends IntColumnFilter { int oneValueToAnother(int precl) { if (0 == precl) @@ -2397,14 +2365,14 @@ int oneValueToAnother(int precl) { } } -// abstract class converts one value to another solely based on the column -// integer value -// apply to integer columns only + +/** + * Converts one value to another solely based on the column integer value. Apply to integer columns only + */ abstract class IntColumnFilter extends ColumnFilter { abstract int oneValueToAnother(int value); - final Object apply(Object value, - JDBCType asJDBCType) throws SQLServerException { + final Object apply(Object value, JDBCType asJDBCType) throws SQLServerException { if (value == null) return value; // Assumption: values will only be requested in integral or textual @@ -2433,16 +2401,17 @@ final Object apply(Object value, } -// Filter to convert int identity column values from 0,1 to YES, NO -// There is a mismatch between what the stored proc returns and what the -// JDBC spec expects. + +/** + * Provides filter to convert int identity column values from 0,1 to YES, NO There is a mismatch between what the stored + * proc returns and what the JDBC spec expects. + */ class IntColumnIdentityFilter extends ColumnFilter { private static String zeroOneToYesNo(int i) { return 0 == i ? "NO" : "YES"; } - final Object apply(Object value, - JDBCType asJDBCType) throws SQLServerException { + final Object apply(Object value, JDBCType asJDBCType) throws SQLServerException { if (value == null) return value; // Assumption: values will only be requested in integral or textual @@ -2477,5 +2446,4 @@ final Object apply(Object value, return value; } } - -} \ No newline at end of file +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java index 5f67f93db..30a0c4d76 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -22,11 +19,11 @@ import org.ietf.jgss.GSSCredential; + /** - * SQLServerDriver implements the java.sql.Driver for SQLServerConnect. + * Implements the java.sql.Driver for SQLServerConnect. * */ - final class SQLServerDriverPropertyInfo { private final String name; @@ -39,10 +36,7 @@ final String getName() { private final boolean required; private final String[] choices; - SQLServerDriverPropertyInfo(String name, - String defaultValue, - boolean required, - String[] choices) { + SQLServerDriverPropertyInfo(String name, String defaultValue, boolean required, String[] choices) { this.name = name; this.description = SQLServerResource.getResource("R_" + name + "PropertyDescription"); this.defaultValue = defaultValue; @@ -51,7 +45,8 @@ final String getName() { } DriverPropertyInfo build(Properties connProperties) { - String propValue = name.equals(SQLServerDriverStringProperty.PASSWORD.toString()) ? "" : connProperties.getProperty(name); + String propValue = name.equals(SQLServerDriverStringProperty.PASSWORD.toString()) ? "" : connProperties + .getProperty(name); if (null == propValue) propValue = defaultValue; @@ -65,6 +60,7 @@ DriverPropertyInfo build(Properties connProperties) { } } + enum SqlAuthentication { NotSpecified, SqlPassword, @@ -76,17 +72,15 @@ static SqlAuthentication valueOfString(String value) throws SQLServerException { if (value.toLowerCase(Locale.US).equalsIgnoreCase(SqlAuthentication.NotSpecified.toString())) { method = SqlAuthentication.NotSpecified; - } - else if (value.toLowerCase(Locale.US).equalsIgnoreCase(SqlAuthentication.SqlPassword.toString())) { + } else if (value.toLowerCase(Locale.US).equalsIgnoreCase(SqlAuthentication.SqlPassword.toString())) { method = SqlAuthentication.SqlPassword; - } - else if (value.toLowerCase(Locale.US).equalsIgnoreCase(SqlAuthentication.ActiveDirectoryPassword.toString())) { + } else if (value.toLowerCase(Locale.US) + .equalsIgnoreCase(SqlAuthentication.ActiveDirectoryPassword.toString())) { method = SqlAuthentication.ActiveDirectoryPassword; - } - else if (value.toLowerCase(Locale.US).equalsIgnoreCase(SqlAuthentication.ActiveDirectoryIntegrated.toString())) { + } else if (value.toLowerCase(Locale.US) + .equalsIgnoreCase(SqlAuthentication.ActiveDirectoryIntegrated.toString())) { method = SqlAuthentication.ActiveDirectoryIntegrated; - } - else { + } else { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidConnectionSetting")); Object[] msgArgs = {"authentication", value}; throw new SQLServerException(null, form.format(msgArgs), null, 0, false); @@ -95,6 +89,7 @@ else if (value.toLowerCase(Locale.US).equalsIgnoreCase(SqlAuthentication.ActiveD } } + enum ColumnEncryptionSetting { Enabled, Disabled; @@ -104,11 +99,9 @@ static ColumnEncryptionSetting valueOfString(String value) throws SQLServerExcep if (value.toLowerCase(Locale.US).equalsIgnoreCase(ColumnEncryptionSetting.Enabled.toString())) { method = ColumnEncryptionSetting.Enabled; - } - else if (value.toLowerCase(Locale.US).equalsIgnoreCase(ColumnEncryptionSetting.Disabled.toString())) { + } else if (value.toLowerCase(Locale.US).equalsIgnoreCase(ColumnEncryptionSetting.Disabled.toString())) { method = ColumnEncryptionSetting.Disabled; - } - else { + } else { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidConnectionSetting")); Object[] msgArgs = {"columnEncryptionSetting", value}; throw new SQLServerException(form.format(msgArgs), null); @@ -117,6 +110,7 @@ else if (value.toLowerCase(Locale.US).equalsIgnoreCase(ColumnEncryptionSetting.D } } + enum SSLProtocol { TLS("TLS"), TLS_V10("TLSv1"), @@ -138,17 +132,13 @@ static SSLProtocol valueOfString(String value) throws SQLServerException { if (value.toLowerCase(Locale.ENGLISH).equalsIgnoreCase(SSLProtocol.TLS.toString())) { protocol = SSLProtocol.TLS; - } - else if (value.toLowerCase(Locale.ENGLISH).equalsIgnoreCase(SSLProtocol.TLS_V10.toString())) { + } else if (value.toLowerCase(Locale.ENGLISH).equalsIgnoreCase(SSLProtocol.TLS_V10.toString())) { protocol = SSLProtocol.TLS_V10; - } - else if (value.toLowerCase(Locale.ENGLISH).equalsIgnoreCase(SSLProtocol.TLS_V11.toString())) { + } else if (value.toLowerCase(Locale.ENGLISH).equalsIgnoreCase(SSLProtocol.TLS_V11.toString())) { protocol = SSLProtocol.TLS_V11; - } - else if (value.toLowerCase(Locale.ENGLISH).equalsIgnoreCase(SSLProtocol.TLS_V12.toString())) { + } else if (value.toLowerCase(Locale.ENGLISH).equalsIgnoreCase(SSLProtocol.TLS_V12.toString())) { protocol = SSLProtocol.TLS_V12; - } - else { + } else { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidSSLProtocol")); Object[] msgArgs = {value}; throw new SQLServerException(null, form.format(msgArgs), null, 0, false); @@ -157,6 +147,7 @@ else if (value.toLowerCase(Locale.ENGLISH).equalsIgnoreCase(SSLProtocol.TLS_V12. } } + enum KeyStoreAuthentication { JavaKeyStorePassword; @@ -165,8 +156,7 @@ static KeyStoreAuthentication valueOfString(String value) throws SQLServerExcept if (value.toLowerCase(Locale.US).equalsIgnoreCase(KeyStoreAuthentication.JavaKeyStorePassword.toString())) { method = KeyStoreAuthentication.JavaKeyStorePassword; - } - else { + } else { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidConnectionSetting")); Object[] msgArgs = {"keyStoreAuthentication", value}; throw new SQLServerException(form.format(msgArgs), null); @@ -175,19 +165,19 @@ static KeyStoreAuthentication valueOfString(String value) throws SQLServerExcept } } + enum AuthenticationScheme { nativeAuthentication, javaKerberos; - + static AuthenticationScheme valueOfString(String value) throws SQLServerException { AuthenticationScheme scheme; if (value.toLowerCase(Locale.US).equalsIgnoreCase(AuthenticationScheme.javaKerberos.toString())) { scheme = AuthenticationScheme.javaKerberos; - } - else if (value.toLowerCase(Locale.US).equalsIgnoreCase(AuthenticationScheme.nativeAuthentication.toString())) { + } else if (value.toLowerCase(Locale.US) + .equalsIgnoreCase(AuthenticationScheme.nativeAuthentication.toString())) { scheme = AuthenticationScheme.nativeAuthentication; - } - else { + } else { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidAuthenticationScheme")); Object[] msgArgs = {value}; throw new SQLServerException(null, form.format(msgArgs), null, 0, false); @@ -196,6 +186,7 @@ else if (value.toLowerCase(Locale.US).equalsIgnoreCase(AuthenticationScheme.nati } } + enum ApplicationIntent { READ_WRITE("readwrite"), READ_ONLY("readonly"); @@ -203,12 +194,16 @@ enum ApplicationIntent { // the value of the enum private final String value; - // constructor that sets the string value of the enum + /** + * Constructs a ApplicationIntent that sets the string value of the enum. + */ private ApplicationIntent(String value) { this.value = value; } - // returns the string value of enum + /** + * Returns the string value of enum. + */ public String toString() { return value; } @@ -220,11 +215,9 @@ static ApplicationIntent valueOfString(String value) throws SQLServerException { value = value.toUpperCase(Locale.US).toLowerCase(Locale.US); if (value.equalsIgnoreCase(ApplicationIntent.READ_ONLY.toString())) { applicationIntent = ApplicationIntent.READ_ONLY; - } - else if (value.equalsIgnoreCase(ApplicationIntent.READ_WRITE.toString())) { + } else if (value.equalsIgnoreCase(ApplicationIntent.READ_WRITE.toString())) { applicationIntent = ApplicationIntent.READ_WRITE; - } - else { + } else { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidapplicationIntent")); Object[] msgArgs = {value}; throw new SQLServerException(null, form.format(msgArgs), null, 0, false); @@ -234,68 +227,65 @@ else if (value.equalsIgnoreCase(ApplicationIntent.READ_WRITE.toString())) { } } + enum SQLServerDriverObjectProperty { GSS_CREDENTIAL("gsscredential", null); private final String name; private final String defaultValue; - private SQLServerDriverObjectProperty(String name, - String defaultValue) { + private SQLServerDriverObjectProperty(String name, String defaultValue) { this.name = name; this.defaultValue = defaultValue; } /** - * returning string due to structure of DRIVER_PROPERTIES_PROPERTY_ONLY + * Returns string due to structure of DRIVER_PROPERTIES_PROPERTY_ONLY. + * * @return */ public String getDefaultValue() { return defaultValue; } - + public String toString() { return name; } } - -enum SQLServerDriverStringProperty -{ - APPLICATION_INTENT ("applicationIntent", ApplicationIntent.READ_WRITE.toString()), - APPLICATION_NAME ("applicationName", SQLServerDriver.DEFAULT_APP_NAME), - DATABASE_NAME ("databaseName", ""), - FAILOVER_PARTNER ("failoverPartner", ""), - HOSTNAME_IN_CERTIFICATE ("hostNameInCertificate", ""), - INSTANCE_NAME ("instanceName", ""), - JAAS_CONFIG_NAME ("jaasConfigurationName", "SQLJDBCDriver"), - PASSWORD ("password", ""), - RESPONSE_BUFFERING ("responseBuffering", "adaptive"), - SELECT_METHOD ("selectMethod", "direct"), - SERVER_NAME ("serverName", ""), - SERVER_SPN ("serverSpn", ""), - TRUST_STORE_TYPE ("trustStoreType", "JKS"), - TRUST_STORE ("trustStore", ""), - TRUST_STORE_PASSWORD ("trustStorePassword", ""), - TRUST_MANAGER_CLASS ("trustManagerClass", ""), - TRUST_MANAGER_CONSTRUCTOR_ARG("trustManagerConstructorArg", ""), - USER ("user", ""), - WORKSTATION_ID ("workstationID", Util.WSIDNotAvailable), - AUTHENTICATION_SCHEME ("authenticationScheme", AuthenticationScheme.nativeAuthentication.toString()), - AUTHENTICATION ("authentication", SqlAuthentication.NotSpecified.toString()), - ACCESS_TOKEN ("accessToken", ""), - COLUMN_ENCRYPTION ("columnEncryptionSetting", ColumnEncryptionSetting.Disabled.toString()), - KEY_STORE_AUTHENTICATION ("keyStoreAuthentication", ""), - KEY_STORE_SECRET ("keyStoreSecret", ""), - KEY_STORE_LOCATION ("keyStoreLocation", ""), - SSL_PROTOCOL ("sslProtocol", SSLProtocol.TLS.toString()), - ; +enum SQLServerDriverStringProperty { + APPLICATION_INTENT("applicationIntent", ApplicationIntent.READ_WRITE.toString()), + APPLICATION_NAME("applicationName", SQLServerDriver.DEFAULT_APP_NAME), + DATABASE_NAME("databaseName", ""), + FAILOVER_PARTNER("failoverPartner", ""), + HOSTNAME_IN_CERTIFICATE("hostNameInCertificate", ""), + INSTANCE_NAME("instanceName", ""), + JAAS_CONFIG_NAME("jaasConfigurationName", "SQLJDBCDriver"), + PASSWORD("password", ""), + RESPONSE_BUFFERING("responseBuffering", "adaptive"), + SELECT_METHOD("selectMethod", "direct"), + SERVER_NAME("serverName", ""), + SERVER_SPN("serverSpn", ""), + TRUST_STORE_TYPE("trustStoreType", "JKS"), + TRUST_STORE("trustStore", ""), + TRUST_STORE_PASSWORD("trustStorePassword", ""), + TRUST_MANAGER_CLASS("trustManagerClass", ""), + TRUST_MANAGER_CONSTRUCTOR_ARG("trustManagerConstructorArg", ""), + USER("user", ""), + WORKSTATION_ID("workstationID", Util.WSIDNotAvailable), + AUTHENTICATION_SCHEME("authenticationScheme", AuthenticationScheme.nativeAuthentication.toString()), + AUTHENTICATION("authentication", SqlAuthentication.NotSpecified.toString()), + ACCESS_TOKEN("accessToken", ""), + COLUMN_ENCRYPTION("columnEncryptionSetting", ColumnEncryptionSetting.Disabled.toString()), + KEY_STORE_AUTHENTICATION("keyStoreAuthentication", ""), + KEY_STORE_SECRET("keyStoreSecret", ""), + KEY_STORE_LOCATION("keyStoreLocation", ""), + SSL_PROTOCOL("sslProtocol", SSLProtocol.TLS.toString()),; private final String name; private final String defaultValue; - private SQLServerDriverStringProperty(String name, - String defaultValue) { + private SQLServerDriverStringProperty(String name, String defaultValue) { this.name = name; this.defaultValue = defaultValue; } @@ -309,23 +299,22 @@ public String toString() { } } + enum SQLServerDriverIntProperty { - PACKET_SIZE ("packetSize", TDS.DEFAULT_PACKET_SIZE), - LOCK_TIMEOUT ("lockTimeout", -1), - LOGIN_TIMEOUT ("loginTimeout", 15), - QUERY_TIMEOUT ("queryTimeout", -1), - PORT_NUMBER ("portNumber", 1433), - SOCKET_TIMEOUT ("socketTimeout", 0), + PACKET_SIZE("packetSize", TDS.DEFAULT_PACKET_SIZE), + LOCK_TIMEOUT("lockTimeout", -1), + LOGIN_TIMEOUT("loginTimeout", 15), + QUERY_TIMEOUT("queryTimeout", -1), + PORT_NUMBER("portNumber", 1433), + SOCKET_TIMEOUT("socketTimeout", 0), SERVER_PREPARED_STATEMENT_DISCARD_THRESHOLD("serverPreparedStatementDiscardThreshold", SQLServerConnection.DEFAULT_SERVER_PREPARED_STATEMENT_DISCARD_THRESHOLD), - STATEMENT_POOLING_CACHE_SIZE ("statementPoolingCacheSize", SQLServerConnection.DEFAULT_STATEMENT_POOLING_CACHE_SIZE), - CANCEL_QUERY_TIMEOUT ("cancelQueryTimeout", -1), - ; - + STATEMENT_POOLING_CACHE_SIZE("statementPoolingCacheSize", SQLServerConnection.DEFAULT_STATEMENT_POOLING_CACHE_SIZE), + CANCEL_QUERY_TIMEOUT("cancelQueryTimeout", -1),; + private final String name; private final int defaultValue; - private SQLServerDriverIntProperty(String name, - int defaultValue) { + private SQLServerDriverIntProperty(String name, int defaultValue) { this.name = name; this.defaultValue = defaultValue; } @@ -339,28 +328,27 @@ public String toString() { } } -enum SQLServerDriverBooleanProperty -{ - DISABLE_STATEMENT_POOLING ("disableStatementPooling", true), - ENCRYPT ("encrypt", false), - INTEGRATED_SECURITY ("integratedSecurity", false), - LAST_UPDATE_COUNT ("lastUpdateCount", true), - MULTI_SUBNET_FAILOVER ("multiSubnetFailover", false), - SERVER_NAME_AS_ACE ("serverNameAsACE", false), - SEND_STRING_PARAMETERS_AS_UNICODE ("sendStringParametersAsUnicode", true), - SEND_TIME_AS_DATETIME ("sendTimeAsDatetime", true), - TRANSPARENT_NETWORK_IP_RESOLUTION ("TransparentNetworkIPResolution", true), - TRUST_SERVER_CERTIFICATE ("trustServerCertificate", false), - XOPEN_STATES ("xopenStates", false), - FIPS ("fips", false), + +enum SQLServerDriverBooleanProperty { + DISABLE_STATEMENT_POOLING("disableStatementPooling", true), + ENCRYPT("encrypt", false), + INTEGRATED_SECURITY("integratedSecurity", false), + LAST_UPDATE_COUNT("lastUpdateCount", true), + MULTI_SUBNET_FAILOVER("multiSubnetFailover", false), + SERVER_NAME_AS_ACE("serverNameAsACE", false), + SEND_STRING_PARAMETERS_AS_UNICODE("sendStringParametersAsUnicode", true), + SEND_TIME_AS_DATETIME("sendTimeAsDatetime", true), + TRANSPARENT_NETWORK_IP_RESOLUTION("TransparentNetworkIPResolution", true), + TRUST_SERVER_CERTIFICATE("trustServerCertificate", false), + XOPEN_STATES("xopenStates", false), + FIPS("fips", false), ENABLE_PREPARE_ON_FIRST_PREPARED_STATEMENT("enablePrepareOnFirstPreparedStatementCall", SQLServerConnection.DEFAULT_ENABLE_PREPARE_ON_FIRST_PREPARED_STATEMENT_CALL), - USE_BULK_COPY_FOR_BATCH_INSERT ("useBulkCopyForBatchInsert", false); + USE_BULK_COPY_FOR_BATCH_INSERT("useBulkCopyForBatchInsert", false); private final String name; private final boolean defaultValue; - private SQLServerDriverBooleanProperty(String name, - boolean defaultValue) { + private SQLServerDriverBooleanProperty(String name, boolean defaultValue) { this.name = name; this.defaultValue = defaultValue; } @@ -374,83 +362,169 @@ public String toString() { } } + +/** + * Provides methods to connect to a SQL Server database and to obtain information about the JDBC driver. + */ public final class SQLServerDriver implements java.sql.Driver { - static final String PRODUCT_NAME = "Microsoft JDBC Driver " + SQLJdbcVersion.major + "." + SQLJdbcVersion.minor + " for SQL Server"; + static final String PRODUCT_NAME = "Microsoft JDBC Driver " + SQLJdbcVersion.major + "." + SQLJdbcVersion.minor + + " for SQL Server"; static final String DEFAULT_APP_NAME = "Microsoft JDBC Driver for SQL Server"; private static final String[] TRUE_FALSE = {"true", "false"}; - private static final SQLServerDriverPropertyInfo[] DRIVER_PROPERTIES = - { - // default required available choices - // property name value property (if appropriate) - new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.APPLICATION_INTENT.toString(), SQLServerDriverStringProperty.APPLICATION_INTENT.getDefaultValue(), false, new String[]{ApplicationIntent.READ_ONLY.toString(), ApplicationIntent.READ_WRITE.toString()}), - new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.APPLICATION_NAME.toString(), SQLServerDriverStringProperty.APPLICATION_NAME.getDefaultValue(), false, null), - new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.COLUMN_ENCRYPTION.toString(), SQLServerDriverStringProperty.COLUMN_ENCRYPTION.getDefaultValue(), false, new String[] {ColumnEncryptionSetting.Disabled.toString(), ColumnEncryptionSetting.Enabled.toString()}), - new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.DATABASE_NAME.toString(), SQLServerDriverStringProperty.DATABASE_NAME.getDefaultValue(), false, null), - new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.DISABLE_STATEMENT_POOLING.toString(), Boolean.toString(SQLServerDriverBooleanProperty.DISABLE_STATEMENT_POOLING.getDefaultValue()), false, new String[] {"true"}), - new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.ENCRYPT.toString(), Boolean.toString(SQLServerDriverBooleanProperty.ENCRYPT.getDefaultValue()), false, TRUE_FALSE), - new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.FAILOVER_PARTNER.toString(), SQLServerDriverStringProperty.FAILOVER_PARTNER.getDefaultValue(), false, null), - new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.HOSTNAME_IN_CERTIFICATE.toString(), SQLServerDriverStringProperty.HOSTNAME_IN_CERTIFICATE.getDefaultValue(), false, null), - new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.INSTANCE_NAME.toString(), SQLServerDriverStringProperty.INSTANCE_NAME.getDefaultValue(), false, null), - new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.INTEGRATED_SECURITY.toString(), Boolean.toString(SQLServerDriverBooleanProperty.INTEGRATED_SECURITY.getDefaultValue()), false, TRUE_FALSE), - new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.KEY_STORE_AUTHENTICATION.toString(), SQLServerDriverStringProperty.KEY_STORE_AUTHENTICATION.getDefaultValue(), false, new String[] {KeyStoreAuthentication.JavaKeyStorePassword.toString()}), - new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.KEY_STORE_SECRET .toString(), SQLServerDriverStringProperty.KEY_STORE_SECRET.getDefaultValue(), false, null), - new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.KEY_STORE_LOCATION .toString(), SQLServerDriverStringProperty.KEY_STORE_LOCATION.getDefaultValue(), false, null), - new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.LAST_UPDATE_COUNT.toString(), Boolean.toString(SQLServerDriverBooleanProperty.LAST_UPDATE_COUNT.getDefaultValue()), false, TRUE_FALSE), - new SQLServerDriverPropertyInfo(SQLServerDriverIntProperty.LOCK_TIMEOUT.toString(), Integer.toString(SQLServerDriverIntProperty.LOCK_TIMEOUT.getDefaultValue()), false, null), - new SQLServerDriverPropertyInfo(SQLServerDriverIntProperty.LOGIN_TIMEOUT.toString(), Integer.toString(SQLServerDriverIntProperty.LOGIN_TIMEOUT.getDefaultValue()), false, null), - new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.MULTI_SUBNET_FAILOVER.toString(), Boolean.toString(SQLServerDriverBooleanProperty.MULTI_SUBNET_FAILOVER.getDefaultValue()), false, TRUE_FALSE), - new SQLServerDriverPropertyInfo(SQLServerDriverIntProperty.PACKET_SIZE.toString(), Integer.toString(SQLServerDriverIntProperty.PACKET_SIZE.getDefaultValue()), false, null), - new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.PASSWORD.toString(), SQLServerDriverStringProperty.PASSWORD.getDefaultValue(), true, null), - new SQLServerDriverPropertyInfo(SQLServerDriverIntProperty.PORT_NUMBER.toString(), Integer.toString(SQLServerDriverIntProperty.PORT_NUMBER.getDefaultValue()), false, null), - new SQLServerDriverPropertyInfo(SQLServerDriverIntProperty.QUERY_TIMEOUT.toString(), Integer.toString(SQLServerDriverIntProperty.QUERY_TIMEOUT.getDefaultValue()), false, null), - new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.RESPONSE_BUFFERING.toString(), SQLServerDriverStringProperty.RESPONSE_BUFFERING.getDefaultValue(), false, new String[] {"adaptive", "full"}), - new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.SELECT_METHOD.toString(), SQLServerDriverStringProperty.SELECT_METHOD.getDefaultValue(), false, new String[] {"direct", "cursor"}), - new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.SEND_STRING_PARAMETERS_AS_UNICODE.toString(), Boolean.toString(SQLServerDriverBooleanProperty.SEND_STRING_PARAMETERS_AS_UNICODE.getDefaultValue()), false, TRUE_FALSE), - new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.SERVER_NAME_AS_ACE.toString(), Boolean.toString(SQLServerDriverBooleanProperty.SERVER_NAME_AS_ACE.getDefaultValue()), false, TRUE_FALSE), - new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.SERVER_NAME.toString(), SQLServerDriverStringProperty.SERVER_NAME.getDefaultValue(), false, null), - new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.SERVER_SPN.toString(), SQLServerDriverStringProperty.SERVER_SPN.getDefaultValue(), false, null), - new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.TRANSPARENT_NETWORK_IP_RESOLUTION.toString(), Boolean.toString(SQLServerDriverBooleanProperty.TRANSPARENT_NETWORK_IP_RESOLUTION.getDefaultValue()), false, TRUE_FALSE), - new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.TRUST_SERVER_CERTIFICATE.toString(), Boolean.toString(SQLServerDriverBooleanProperty.TRUST_SERVER_CERTIFICATE.getDefaultValue()), false, TRUE_FALSE), - new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.TRUST_STORE_TYPE.toString(), SQLServerDriverStringProperty.TRUST_STORE_TYPE.getDefaultValue(), false, null), - new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.TRUST_STORE.toString(), SQLServerDriverStringProperty.TRUST_STORE.getDefaultValue(), false, null), - new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.TRUST_STORE_PASSWORD.toString(), SQLServerDriverStringProperty.TRUST_STORE_PASSWORD.getDefaultValue(), false, null), - new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.TRUST_MANAGER_CLASS.toString(), SQLServerDriverStringProperty.TRUST_MANAGER_CLASS.getDefaultValue(), false, null), - new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.TRUST_MANAGER_CONSTRUCTOR_ARG.toString(), SQLServerDriverStringProperty.TRUST_MANAGER_CONSTRUCTOR_ARG.getDefaultValue(), false, null), - new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.SEND_TIME_AS_DATETIME.toString(), Boolean.toString(SQLServerDriverBooleanProperty.SEND_TIME_AS_DATETIME.getDefaultValue()), false, TRUE_FALSE), - new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.USER.toString(), SQLServerDriverStringProperty.USER.getDefaultValue(), true, null), - new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.WORKSTATION_ID.toString(), SQLServerDriverStringProperty.WORKSTATION_ID.getDefaultValue(), false, null), - new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.XOPEN_STATES.toString(), Boolean.toString(SQLServerDriverBooleanProperty.XOPEN_STATES.getDefaultValue()), false, TRUE_FALSE), - new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.AUTHENTICATION_SCHEME.toString(), SQLServerDriverStringProperty.AUTHENTICATION_SCHEME.getDefaultValue(), false, new String[] {AuthenticationScheme.javaKerberos.toString(),AuthenticationScheme.nativeAuthentication.toString()}), - new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.AUTHENTICATION.toString(), SQLServerDriverStringProperty.AUTHENTICATION.getDefaultValue(), false, new String[] {SqlAuthentication.NotSpecified.toString(),SqlAuthentication.SqlPassword.toString(),SqlAuthentication.ActiveDirectoryPassword.toString(),SqlAuthentication.ActiveDirectoryIntegrated.toString()}), - new SQLServerDriverPropertyInfo(SQLServerDriverIntProperty.SOCKET_TIMEOUT.toString(), Integer.toString(SQLServerDriverIntProperty.SOCKET_TIMEOUT.getDefaultValue()), false, null), - new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.FIPS.toString(), Boolean.toString(SQLServerDriverBooleanProperty.FIPS.getDefaultValue()), false, TRUE_FALSE), - new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.ENABLE_PREPARE_ON_FIRST_PREPARED_STATEMENT.toString(), Boolean.toString(SQLServerDriverBooleanProperty.ENABLE_PREPARE_ON_FIRST_PREPARED_STATEMENT.getDefaultValue()), false,TRUE_FALSE), - new SQLServerDriverPropertyInfo(SQLServerDriverIntProperty.SERVER_PREPARED_STATEMENT_DISCARD_THRESHOLD.toString(), Integer.toString(SQLServerDriverIntProperty.SERVER_PREPARED_STATEMENT_DISCARD_THRESHOLD.getDefaultValue()), false, null), - new SQLServerDriverPropertyInfo(SQLServerDriverIntProperty.STATEMENT_POOLING_CACHE_SIZE.toString(), Integer.toString(SQLServerDriverIntProperty.STATEMENT_POOLING_CACHE_SIZE.getDefaultValue()), false, null), - new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.JAAS_CONFIG_NAME.toString(), SQLServerDriverStringProperty.JAAS_CONFIG_NAME.getDefaultValue(), false, null), - new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.SSL_PROTOCOL.toString(), SQLServerDriverStringProperty.SSL_PROTOCOL.getDefaultValue(), false, new String[] {SSLProtocol.TLS.toString(), SSLProtocol.TLS_V10.toString(), SSLProtocol.TLS_V11.toString(), SSLProtocol.TLS_V12.toString()}), - new SQLServerDriverPropertyInfo(SQLServerDriverIntProperty.CANCEL_QUERY_TIMEOUT.toString(), Integer.toString(SQLServerDriverIntProperty.CANCEL_QUERY_TIMEOUT.getDefaultValue()), false, null), - new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.USE_BULK_COPY_FOR_BATCH_INSERT.toString(), Boolean.toString(SQLServerDriverBooleanProperty.USE_BULK_COPY_FOR_BATCH_INSERT.getDefaultValue()), false, TRUE_FALSE), - }; - - // Properties that can only be set by using Properties. - // Cannot set in connection string + private static final SQLServerDriverPropertyInfo[] DRIVER_PROPERTIES = { + // default required available choices + // property name value property (if appropriate) + new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.APPLICATION_INTENT.toString(), + SQLServerDriverStringProperty.APPLICATION_INTENT.getDefaultValue(), false, + new String[] {ApplicationIntent.READ_ONLY.toString(), ApplicationIntent.READ_WRITE.toString()}), + new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.APPLICATION_NAME.toString(), + SQLServerDriverStringProperty.APPLICATION_NAME.getDefaultValue(), false, null), + new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.COLUMN_ENCRYPTION.toString(), + SQLServerDriverStringProperty.COLUMN_ENCRYPTION.getDefaultValue(), false, + new String[] {ColumnEncryptionSetting.Disabled.toString(), + ColumnEncryptionSetting.Enabled.toString()}), + new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.DATABASE_NAME.toString(), + SQLServerDriverStringProperty.DATABASE_NAME.getDefaultValue(), false, null), + new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.DISABLE_STATEMENT_POOLING.toString(), + Boolean.toString(SQLServerDriverBooleanProperty.DISABLE_STATEMENT_POOLING.getDefaultValue()), false, + new String[] {"true"}), + new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.ENCRYPT.toString(), + Boolean.toString(SQLServerDriverBooleanProperty.ENCRYPT.getDefaultValue()), false, TRUE_FALSE), + new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.FAILOVER_PARTNER.toString(), + SQLServerDriverStringProperty.FAILOVER_PARTNER.getDefaultValue(), false, null), + new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.HOSTNAME_IN_CERTIFICATE.toString(), + SQLServerDriverStringProperty.HOSTNAME_IN_CERTIFICATE.getDefaultValue(), false, null), + new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.INSTANCE_NAME.toString(), + SQLServerDriverStringProperty.INSTANCE_NAME.getDefaultValue(), false, null), + new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.INTEGRATED_SECURITY.toString(), + Boolean.toString(SQLServerDriverBooleanProperty.INTEGRATED_SECURITY.getDefaultValue()), false, + TRUE_FALSE), + new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.KEY_STORE_AUTHENTICATION.toString(), + SQLServerDriverStringProperty.KEY_STORE_AUTHENTICATION.getDefaultValue(), false, + new String[] {KeyStoreAuthentication.JavaKeyStorePassword.toString()}), + new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.KEY_STORE_SECRET.toString(), + SQLServerDriverStringProperty.KEY_STORE_SECRET.getDefaultValue(), false, null), + new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.KEY_STORE_LOCATION.toString(), + SQLServerDriverStringProperty.KEY_STORE_LOCATION.getDefaultValue(), false, null), + new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.LAST_UPDATE_COUNT.toString(), + Boolean.toString(SQLServerDriverBooleanProperty.LAST_UPDATE_COUNT.getDefaultValue()), false, + TRUE_FALSE), + new SQLServerDriverPropertyInfo(SQLServerDriverIntProperty.LOCK_TIMEOUT.toString(), + Integer.toString(SQLServerDriverIntProperty.LOCK_TIMEOUT.getDefaultValue()), false, null), + new SQLServerDriverPropertyInfo(SQLServerDriverIntProperty.LOGIN_TIMEOUT.toString(), + Integer.toString(SQLServerDriverIntProperty.LOGIN_TIMEOUT.getDefaultValue()), false, null), + new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.MULTI_SUBNET_FAILOVER.toString(), + Boolean.toString(SQLServerDriverBooleanProperty.MULTI_SUBNET_FAILOVER.getDefaultValue()), false, + TRUE_FALSE), + new SQLServerDriverPropertyInfo(SQLServerDriverIntProperty.PACKET_SIZE.toString(), + Integer.toString(SQLServerDriverIntProperty.PACKET_SIZE.getDefaultValue()), false, null), + new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.PASSWORD.toString(), + SQLServerDriverStringProperty.PASSWORD.getDefaultValue(), true, null), + new SQLServerDriverPropertyInfo(SQLServerDriverIntProperty.PORT_NUMBER.toString(), + Integer.toString(SQLServerDriverIntProperty.PORT_NUMBER.getDefaultValue()), false, null), + new SQLServerDriverPropertyInfo(SQLServerDriverIntProperty.QUERY_TIMEOUT.toString(), + Integer.toString(SQLServerDriverIntProperty.QUERY_TIMEOUT.getDefaultValue()), false, null), + new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.RESPONSE_BUFFERING.toString(), + SQLServerDriverStringProperty.RESPONSE_BUFFERING.getDefaultValue(), false, + new String[] {"adaptive", "full"}), + new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.SELECT_METHOD.toString(), + SQLServerDriverStringProperty.SELECT_METHOD.getDefaultValue(), false, + new String[] {"direct", "cursor"}), + new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.SEND_STRING_PARAMETERS_AS_UNICODE.toString(), + Boolean.toString( + SQLServerDriverBooleanProperty.SEND_STRING_PARAMETERS_AS_UNICODE.getDefaultValue()), + false, TRUE_FALSE), + new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.SERVER_NAME_AS_ACE.toString(), + Boolean.toString(SQLServerDriverBooleanProperty.SERVER_NAME_AS_ACE.getDefaultValue()), false, + TRUE_FALSE), + new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.SERVER_NAME.toString(), + SQLServerDriverStringProperty.SERVER_NAME.getDefaultValue(), false, null), + new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.SERVER_SPN.toString(), + SQLServerDriverStringProperty.SERVER_SPN.getDefaultValue(), false, null), + new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.TRANSPARENT_NETWORK_IP_RESOLUTION.toString(), + Boolean.toString( + SQLServerDriverBooleanProperty.TRANSPARENT_NETWORK_IP_RESOLUTION.getDefaultValue()), + false, TRUE_FALSE), + new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.TRUST_SERVER_CERTIFICATE.toString(), + Boolean.toString(SQLServerDriverBooleanProperty.TRUST_SERVER_CERTIFICATE.getDefaultValue()), false, + TRUE_FALSE), + new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.TRUST_STORE_TYPE.toString(), + SQLServerDriverStringProperty.TRUST_STORE_TYPE.getDefaultValue(), false, null), + new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.TRUST_STORE.toString(), + SQLServerDriverStringProperty.TRUST_STORE.getDefaultValue(), false, null), + new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.TRUST_STORE_PASSWORD.toString(), + SQLServerDriverStringProperty.TRUST_STORE_PASSWORD.getDefaultValue(), false, null), + new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.TRUST_MANAGER_CLASS.toString(), + SQLServerDriverStringProperty.TRUST_MANAGER_CLASS.getDefaultValue(), false, null), + new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.TRUST_MANAGER_CONSTRUCTOR_ARG.toString(), + SQLServerDriverStringProperty.TRUST_MANAGER_CONSTRUCTOR_ARG.getDefaultValue(), false, null), + new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.SEND_TIME_AS_DATETIME.toString(), + Boolean.toString(SQLServerDriverBooleanProperty.SEND_TIME_AS_DATETIME.getDefaultValue()), false, + TRUE_FALSE), + new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.USER.toString(), + SQLServerDriverStringProperty.USER.getDefaultValue(), true, null), + new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.WORKSTATION_ID.toString(), + SQLServerDriverStringProperty.WORKSTATION_ID.getDefaultValue(), false, null), + new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.XOPEN_STATES.toString(), + Boolean.toString(SQLServerDriverBooleanProperty.XOPEN_STATES.getDefaultValue()), false, TRUE_FALSE), + new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.AUTHENTICATION_SCHEME.toString(), + SQLServerDriverStringProperty.AUTHENTICATION_SCHEME.getDefaultValue(), false, + new String[] {AuthenticationScheme.javaKerberos.toString(), + AuthenticationScheme.nativeAuthentication.toString()}), + new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.AUTHENTICATION.toString(), + SQLServerDriverStringProperty.AUTHENTICATION.getDefaultValue(), false, + new String[] {SqlAuthentication.NotSpecified.toString(), SqlAuthentication.SqlPassword.toString(), + SqlAuthentication.ActiveDirectoryPassword.toString(), + SqlAuthentication.ActiveDirectoryIntegrated.toString()}), + new SQLServerDriverPropertyInfo(SQLServerDriverIntProperty.SOCKET_TIMEOUT.toString(), + Integer.toString(SQLServerDriverIntProperty.SOCKET_TIMEOUT.getDefaultValue()), false, null), + new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.FIPS.toString(), + Boolean.toString(SQLServerDriverBooleanProperty.FIPS.getDefaultValue()), false, TRUE_FALSE), + new SQLServerDriverPropertyInfo( + SQLServerDriverBooleanProperty.ENABLE_PREPARE_ON_FIRST_PREPARED_STATEMENT.toString(), + Boolean.toString(SQLServerDriverBooleanProperty.ENABLE_PREPARE_ON_FIRST_PREPARED_STATEMENT + .getDefaultValue()), + false, TRUE_FALSE), + new SQLServerDriverPropertyInfo( + SQLServerDriverIntProperty.SERVER_PREPARED_STATEMENT_DISCARD_THRESHOLD.toString(), + Integer.toString( + SQLServerDriverIntProperty.SERVER_PREPARED_STATEMENT_DISCARD_THRESHOLD.getDefaultValue()), + false, null), + new SQLServerDriverPropertyInfo(SQLServerDriverIntProperty.STATEMENT_POOLING_CACHE_SIZE.toString(), + Integer.toString(SQLServerDriverIntProperty.STATEMENT_POOLING_CACHE_SIZE.getDefaultValue()), false, + null), + new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.JAAS_CONFIG_NAME.toString(), + SQLServerDriverStringProperty.JAAS_CONFIG_NAME.getDefaultValue(), false, null), + new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.SSL_PROTOCOL.toString(), + SQLServerDriverStringProperty.SSL_PROTOCOL.getDefaultValue(), false, + new String[] {SSLProtocol.TLS.toString(), SSLProtocol.TLS_V10.toString(), + SSLProtocol.TLS_V11.toString(), SSLProtocol.TLS_V12.toString()}), + new SQLServerDriverPropertyInfo(SQLServerDriverIntProperty.CANCEL_QUERY_TIMEOUT.toString(), + Integer.toString(SQLServerDriverIntProperty.CANCEL_QUERY_TIMEOUT.getDefaultValue()), false, null), + new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.USE_BULK_COPY_FOR_BATCH_INSERT.toString(), + Boolean.toString(SQLServerDriverBooleanProperty.USE_BULK_COPY_FOR_BATCH_INSERT.getDefaultValue()), + false, TRUE_FALSE),}; + + /** + * Properties that can only be set by using Properties. Cannot set in connection string + */ private static final SQLServerDriverPropertyInfo[] DRIVER_PROPERTIES_PROPERTY_ONLY = { - // default required available choices - // property name value property (if appropriate) - new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.ACCESS_TOKEN.toString(), SQLServerDriverStringProperty.ACCESS_TOKEN.getDefaultValue(), false, null), - new SQLServerDriverPropertyInfo(SQLServerDriverObjectProperty.GSS_CREDENTIAL.toString(), SQLServerDriverObjectProperty.GSS_CREDENTIAL.getDefaultValue(), false, null), - }; - - private static final String driverPropertiesSynonyms[][] = { - {"database", SQLServerDriverStringProperty.DATABASE_NAME.toString()}, - {"userName",SQLServerDriverStringProperty.USER.toString()}, - {"server",SQLServerDriverStringProperty.SERVER_NAME.toString()}, - {"port", SQLServerDriverIntProperty.PORT_NUMBER.toString()} - }; - static private final AtomicInteger baseID = new AtomicInteger(0); // Unique id generator for each instance (used for logging). - final private int instanceID; // Unique id for this instance. + // default required available choices + // property name value property (if appropriate) + new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.ACCESS_TOKEN.toString(), + SQLServerDriverStringProperty.ACCESS_TOKEN.getDefaultValue(), false, null), + new SQLServerDriverPropertyInfo(SQLServerDriverObjectProperty.GSS_CREDENTIAL.toString(), + SQLServerDriverObjectProperty.GSS_CREDENTIAL.getDefaultValue(), false, null),}; + + private static final String driverPropertiesSynonyms[][] = { + {"database", SQLServerDriverStringProperty.DATABASE_NAME.toString()}, + {"userName", SQLServerDriverStringProperty.USER.toString()}, + {"server", SQLServerDriverStringProperty.SERVER_NAME.toString()}, + {"port", SQLServerDriverIntProperty.PORT_NUMBER.toString()}}; + static private final AtomicInteger baseID = new AtomicInteger(0); // Unique id generator for each instance (used for + // logging). + final private int instanceID; // Unique id for this instance. final private String traceID; // Returns unique id for each instance. @@ -462,8 +536,10 @@ final public String toString() { return traceID; } - static final private java.util.logging.Logger loggerExternal = java.util.logging.Logger.getLogger("com.microsoft.sqlserver.jdbc.Driver"); - static final private java.util.logging.Logger parentLogger = java.util.logging.Logger.getLogger("com.microsoft.sqlserver.jdbc"); + static final private java.util.logging.Logger loggerExternal = java.util.logging.Logger + .getLogger("com.microsoft.sqlserver.jdbc.Driver"); + static final private java.util.logging.Logger parentLogger = java.util.logging.Logger + .getLogger("com.microsoft.sqlserver.jdbc"); final private String loggingClassName; String getClassNameLogging() { @@ -476,8 +552,7 @@ String getClassNameLogging() { static { try { java.sql.DriverManager.registerDriver(new SQLServerDriver()); - } - catch (SQLException e) { + } catch (SQLException e) { if (drLogger.isLoggable(Level.FINER) && Util.IsActivityTraceOn()) { drLogger.finer("Error registering driver: " + e); } @@ -490,8 +565,10 @@ public SQLServerDriver() { loggingClassName = "com.microsoft.sqlserver.jdbc." + "SQLServerDriver:" + instanceID; } - // Helper function used to fixup the case sensitivity, synonyms and remove unknown tokens from the - // properties + /** + * Provides Helper function used to fix the case sensitivity, synonyms and remove unknown tokens from the + * properties. + */ static Properties fixupProperties(Properties props) throws SQLServerException { // assert props !=null Properties fixedup = new Properties(); @@ -509,11 +586,9 @@ static Properties fixupProperties(Properties props) throws SQLServerException { if (null != val) { // replace with the driver approved name fixedup.setProperty(newname, val); - } - else if(newname.equalsIgnoreCase("gsscredential") && (props.get(name) instanceof GSSCredential)){ - fixedup.put(newname, props.get(name)); - } - else { + } else if (newname.equalsIgnoreCase("gsscredential") && (props.get(name) instanceof GSSCredential)) { + fixedup.put(newname, props.get(name)); + } else { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidpropertyValue")); Object[] msgArgs = {name}; throw new SQLServerException(null, form.format(msgArgs), null, 0, false); @@ -524,9 +599,11 @@ else if(newname.equalsIgnoreCase("gsscredential") && (props.get(name) instanceof return fixedup; } - // Helper function used to merge together the property set extracted from the url and the - // user supplied property set passed in by the caller. This function is used by both SQLServerDriver.connect - // and SQLServerDataSource.getConnectionInternal to centralize this property merging code. + /** + * Provides Helper function used to merge together the property set extracted from the url and the user supplied + * property set passed in by the caller. This function is used by both SQLServerDriver.connect and + * SQLServerDataSource.getConnectionInternal to centralize this property merging code. + */ static Properties mergeURLAndSuppliedProperties(Properties urlProps, Properties suppliedProperties) throws SQLServerException { if (null == suppliedProperties) @@ -558,15 +635,14 @@ static Properties mergeURLAndSuppliedProperties(Properties urlProps, } /** - * normalize the property names + * Returns the normalized the property names. * * @param name - * name to normalize + * name to normalize * @param logger * @return the normalized property name */ - static String getNormalizedPropertyName(String name, - Logger logger) { + static String getNormalizedPropertyName(String name, Logger logger) { if (null == name) return name; @@ -587,15 +663,14 @@ static String getNormalizedPropertyName(String name, } /** - * get property-only names that do not work with connection string + * Returns the property-only names that do not work with connection string. * * @param name - * to normalize + * to normalize * @param logger * @return the normalized property name */ - static String getPropertyOnlyName(String name, - Logger logger) { + static String getPropertyOnlyName(String name, Logger logger) { if (null == name) return name; @@ -610,8 +685,7 @@ static String getPropertyOnlyName(String name, return null; } - /* L0 */ public java.sql.Connection connect(String Url, - Properties suppliedProperties) throws SQLServerException { + public java.sql.Connection connect(String Url, Properties suppliedProperties) throws SQLServerException { loggerExternal.entering(getClassNameLogging(), "connect", "Arguments not traced."); SQLServerConnection result = null; @@ -620,8 +694,7 @@ static String getPropertyOnlyName(String name, if (connectProperties != null) { if (Util.use43Wrapper()) { result = new SQLServerConnection43(toString()); - } - else { + } else { result = new SQLServerConnection(toString()); } result.connect(connectProperties, null); @@ -630,20 +703,20 @@ static String getPropertyOnlyName(String name, return result; } - private Properties parseAndMergeProperties(String Url, - Properties suppliedProperties) throws SQLServerException { + private Properties parseAndMergeProperties(String Url, Properties suppliedProperties) throws SQLServerException { if (Url == null) { throw new SQLServerException(null, SQLServerException.getErrString("R_nullConnection"), null, 0, false); } Properties connectProperties = Util.parseUrl(Url, drLogger); if (connectProperties == null) - return null; // If we are the wrong driver dont throw an exception + return null; // If we are the wrong driver dont throw an exception // put the user properties into the connect properties int nTimeout = DriverManager.getLoginTimeout(); if (nTimeout > 0) { - connectProperties.put(SQLServerDriverIntProperty.LOGIN_TIMEOUT.toString(), Integer.valueOf(nTimeout).toString()); + connectProperties.put(SQLServerDriverIntProperty.LOGIN_TIMEOUT.toString(), + Integer.valueOf(nTimeout).toString()); } // Merge connectProperties (from URL) and supplied properties from user. @@ -651,7 +724,7 @@ private Properties parseAndMergeProperties(String Url, return connectProperties; } - /* L0 */ public boolean acceptsURL(String url) throws SQLServerException { + public boolean acceptsURL(String url) throws SQLServerException { loggerExternal.entering(getClassNameLogging(), "acceptsURL", "Arguments not traced."); if (null == url) { @@ -661,8 +734,7 @@ private Properties parseAndMergeProperties(String Url, boolean result = false; try { result = (Util.parseUrl(url, drLogger) != null); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { // ignore the exception from the parse URL failure, if we cant parse the URL we do not accept em result = false; } @@ -670,8 +742,7 @@ private Properties parseAndMergeProperties(String Url, return result; } - public DriverPropertyInfo[] getPropertyInfo(String Url, - Properties Info) throws SQLServerException { + public DriverPropertyInfo[] getPropertyInfo(String Url, Properties Info) throws SQLServerException { loggerExternal.entering(getClassNameLogging(), "getPropertyInfo", "Arguments not traced."); Properties connProperties = parseAndMergeProperties(Url, Info); @@ -708,7 +779,7 @@ public Logger getParentLogger() throws SQLFeatureNotSupportedException { return parentLogger; } - /* L0 */ public boolean jdbcCompliant() { + public boolean jdbcCompliant() { loggerExternal.entering(getClassNameLogging(), "jdbcCompliant"); loggerExternal.exiting(getClassNameLogging(), "jdbcCompliant", Boolean.TRUE); return true; diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerEncryptionAlgorithm.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerEncryptionAlgorithm.java index a6bf63340..1805ff57c 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerEncryptionAlgorithm.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerEncryptionAlgorithm.java @@ -1,35 +1,32 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -/* - * Abstract base class for all AE encryption algorithms. It exposes two functions 1. encryptData - This function is used by the driver under the - * covers to transparently encrypt AE enabled column data. 2. decryptData - This function is used by the driver under the covers to transparently - * decrypt AE enabled column data. - */ -abstract class SQLServerEncryptionAlgorithm { - - /** - * Perform encryption of the plain text - * - * @param plainText - * data to be encrypted - * @return cipher text after encryption - */ - abstract byte[] encryptData(byte[] plainText) throws SQLServerException; - - /** - * Decrypt cipher text to plain text - * - * @param cipherText - * data to be decrypted - * @return plain text after decryption - */ - abstract byte[] decryptData(byte[] cipherText) throws SQLServerException; -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +/* + * Abstract base class for all AE encryption algorithms. It exposes two functions 1. encryptData - This function is used + * by the driver under the covers to transparently encrypt AE enabled column data. 2. decryptData - This function is + * used by the driver under the covers to transparently decrypt AE enabled column data. + */ +abstract class SQLServerEncryptionAlgorithm { + + /** + * Perform encryption of the plain text + * + * @param plainText + * data to be encrypted + * @return cipher text after encryption + */ + abstract byte[] encryptData(byte[] plainText) throws SQLServerException; + + /** + * Decrypt cipher text to plain text + * + * @param cipherText + * data to be decrypted + * @return plain text after decryption + */ + abstract byte[] decryptData(byte[] cipherText) throws SQLServerException; +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerEncryptionAlgorithmFactory.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerEncryptionAlgorithmFactory.java index ef896a7c0..f32274e1e 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerEncryptionAlgorithmFactory.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerEncryptionAlgorithmFactory.java @@ -1,34 +1,30 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -/** - * - * Abstract base class for all the encryption algorithm factory classes. - * - */ -abstract class SQLServerEncryptionAlgorithmFactory { - - /** - * - * @param columnEncryptionKey - * key which will be used in encryption/decryption - * @param encryptionType - * specifies kind of encryption - * @param encryptionAlgorithm - * name of encryption algorithm - * @return created SQLServerEncryptionAlgorithm instance - * @throws SQLServerException - * when an error occurs - */ - abstract SQLServerEncryptionAlgorithm create(SQLServerSymmetricKey columnEncryptionKey, - SQLServerEncryptionType encryptionType, - String encryptionAlgorithm) throws SQLServerException; - -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +/** + * + * Abstract base class for all the encryption algorithm factory classes. + * + */ +abstract class SQLServerEncryptionAlgorithmFactory { + + /** + * + * @param columnEncryptionKey + * key which will be used in encryption/decryption + * @param encryptionType + * specifies kind of encryption + * @param encryptionAlgorithm + * name of encryption algorithm + * @return created SQLServerEncryptionAlgorithm instance + * @throws SQLServerException + * when an error occurs + */ + abstract SQLServerEncryptionAlgorithm create(SQLServerSymmetricKey columnEncryptionKey, + SQLServerEncryptionType encryptionType, String encryptionAlgorithm) throws SQLServerException; + +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerEncryptionAlgorithmFactoryList.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerEncryptionAlgorithmFactoryList.java index a7eb1c0de..9e8f35f61 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerEncryptionAlgorithmFactoryList.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerEncryptionAlgorithmFactoryList.java @@ -1,79 +1,78 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -import java.text.MessageFormat; -import java.util.concurrent.ConcurrentHashMap; - -/** - * Maintain list of all the encryption algorithm factory classes - */ -final class SQLServerEncryptionAlgorithmFactoryList { - - private ConcurrentHashMap encryptionAlgoFactoryMap; - - private static final SQLServerEncryptionAlgorithmFactoryList instance = new SQLServerEncryptionAlgorithmFactoryList(); - - private SQLServerEncryptionAlgorithmFactoryList() { - encryptionAlgoFactoryMap = new ConcurrentHashMap<>(); - encryptionAlgoFactoryMap.putIfAbsent(SQLServerAeadAes256CbcHmac256Algorithm.algorithmName, new SQLServerAeadAes256CbcHmac256Factory()); - } - - static SQLServerEncryptionAlgorithmFactoryList getInstance() { - return instance; - } - - /** - * @return list of registered algorithms separated by comma - */ - String getRegisteredCipherAlgorithmNames() { - StringBuffer stringBuff = new StringBuffer(); - boolean first = true; - for (String key : encryptionAlgoFactoryMap.keySet()) { - if (first) { - stringBuff.append("'"); - first = false; - } - else { - stringBuff.append(", '"); - } - stringBuff.append(key); - stringBuff.append("'"); - - } - return stringBuff.toString(); - } - - /** - * Return instance for given algorithm - * - * @param key - * @param encryptionType - * @param algorithmName - * @return instance for given algorithm - * @throws SQLServerException - */ - SQLServerEncryptionAlgorithm getAlgorithm(SQLServerSymmetricKey key, - SQLServerEncryptionType encryptionType, - String algorithmName) throws SQLServerException { - SQLServerEncryptionAlgorithm encryptionAlgorithm = null; - SQLServerEncryptionAlgorithmFactory factory = null; - if (!encryptionAlgoFactoryMap.containsKey(algorithmName)) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_UnknownColumnEncryptionAlgorithm")); - Object[] msgArgs = {algorithmName, SQLServerEncryptionAlgorithmFactoryList.getInstance().getRegisteredCipherAlgorithmNames()}; - throw new SQLServerException(this, form.format(msgArgs), null, 0, false); - } - - factory = encryptionAlgoFactoryMap.get(algorithmName); - assert null != factory : "Null Algorithm Factory class detected"; - encryptionAlgorithm = factory.create(key, encryptionType, algorithmName); - return encryptionAlgorithm; - } - -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +import java.text.MessageFormat; +import java.util.concurrent.ConcurrentHashMap; + + +/** + * Maintain list of all the encryption algorithm factory classes + */ +final class SQLServerEncryptionAlgorithmFactoryList { + + private ConcurrentHashMap encryptionAlgoFactoryMap; + + private static final SQLServerEncryptionAlgorithmFactoryList instance = new SQLServerEncryptionAlgorithmFactoryList(); + + private SQLServerEncryptionAlgorithmFactoryList() { + encryptionAlgoFactoryMap = new ConcurrentHashMap<>(); + encryptionAlgoFactoryMap.putIfAbsent(SQLServerAeadAes256CbcHmac256Algorithm.algorithmName, + new SQLServerAeadAes256CbcHmac256Factory()); + } + + static SQLServerEncryptionAlgorithmFactoryList getInstance() { + return instance; + } + + /** + * @return list of registered algorithms separated by comma + */ + String getRegisteredCipherAlgorithmNames() { + StringBuffer stringBuff = new StringBuffer(); + boolean first = true; + for (String key : encryptionAlgoFactoryMap.keySet()) { + if (first) { + stringBuff.append("'"); + first = false; + } else { + stringBuff.append(", '"); + } + stringBuff.append(key); + stringBuff.append("'"); + + } + return stringBuff.toString(); + } + + /** + * Return instance for given algorithm + * + * @param key + * @param encryptionType + * @param algorithmName + * @return instance for given algorithm + * @throws SQLServerException + */ + SQLServerEncryptionAlgorithm getAlgorithm(SQLServerSymmetricKey key, SQLServerEncryptionType encryptionType, + String algorithmName) throws SQLServerException { + SQLServerEncryptionAlgorithm encryptionAlgorithm = null; + SQLServerEncryptionAlgorithmFactory factory = null; + if (!encryptionAlgoFactoryMap.containsKey(algorithmName)) { + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_UnknownColumnEncryptionAlgorithm")); + Object[] msgArgs = {algorithmName, + SQLServerEncryptionAlgorithmFactoryList.getInstance().getRegisteredCipherAlgorithmNames()}; + throw new SQLServerException(this, form.format(msgArgs), null, 0, false); + } + + factory = encryptionAlgoFactoryMap.get(algorithmName); + assert null != factory : "Null Algorithm Factory class detected"; + encryptionAlgorithm = factory.create(key, encryptionType, algorithmName); + return encryptionAlgorithm; + } + +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerEncryptionType.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerEncryptionType.java index 3e7812e17..3205d471c 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerEncryptionType.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerEncryptionType.java @@ -1,46 +1,44 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -import java.text.MessageFormat; - -/** - * - * Encryption types supported - * - */ -enum SQLServerEncryptionType { - Deterministic ((byte) 1), - Randomized ((byte) 2), - PlainText ((byte) 0); - - final byte value; - - SQLServerEncryptionType(byte val) { - this.value = val; - } - - byte getValue() { - return this.value; - } - - static SQLServerEncryptionType of(byte val) throws SQLServerException { - for (SQLServerEncryptionType type : values()) - if (val == type.value) - return type; - - // Invalid type. - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_unknownColumnEncryptionType")); - Object[] msgArgs = {val}; - SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), null, true); - - // Make the compiler happy. - return null; - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +import java.text.MessageFormat; + + +/** + * + * Encryption types supported + * + */ +enum SQLServerEncryptionType { + Deterministic((byte) 1), + Randomized((byte) 2), + PlainText((byte) 0); + + final byte value; + + SQLServerEncryptionType(byte val) { + this.value = val; + } + + byte getValue() { + return this.value; + } + + static SQLServerEncryptionType of(byte val) throws SQLServerException { + for (SQLServerEncryptionType type : values()) + if (val == type.value) + return type; + + // Invalid type. + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_unknownColumnEncryptionType")); + Object[] msgArgs = {val}; + SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), null, true); + + // Make the compiler happy. + return null; + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerException.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerException.java index 18cf1bbac..0f54156a8 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerException.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerException.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -13,18 +10,13 @@ import java.util.UUID; import java.util.logging.Level; -/** - * SQLServerException is thrown from any point in the driver that throws a java.sql.SQLException. SQLServerException handles both SQL 92 and XOPEN - * state codes. They are switchable via a user specified connection property. SQLServerExceptions are written to any open log files the user has - * specified. - */ enum SQLState { - STATEMENT_CANCELED ("HY008"), - DATA_EXCEPTION_NOT_SPECIFIC ("22000"), - DATA_EXCEPTION_DATETIME_FIELD_OVERFLOW ("22008"), - DATA_EXCEPTION_LENGTH_MISMATCH ("22026"), - COL_NOT_FOUND ("42S22"); + STATEMENT_CANCELED("HY008"), + DATA_EXCEPTION_NOT_SPECIFIC("22000"), + DATA_EXCEPTION_DATETIME_FIELD_OVERFLOW("22008"), + DATA_EXCEPTION_LENGTH_MISMATCH("22026"), + COL_NOT_FOUND("42S22"); private final String sqlStateCode; @@ -37,6 +29,7 @@ final String getSQLStateCode() { } } + enum DriverError { NOT_SET(0); @@ -51,7 +44,17 @@ final int getErrorCode() { } } + +/** + * Represents the exception thrown from any point in the driver that throws a java.sql.SQLException. SQLServerException + * handles both SQL 92 and XOPEN state codes. They are switchable via a user specified connection property. + * SQLServerExceptions are written to any open log files the user has specified. + */ public final class SQLServerException extends java.sql.SQLException { + /** + * Always update serialVersionUID when prompted + */ + private static final long serialVersionUID = -2195310557661496761L; static final String EXCEPTION_XOPEN_CONNECTION_CANT_ESTABLISH = "08001"; static final String EXCEPTION_XOPEN_CONNECTION_DOES_NOT_EXIST = "08003"; static final String EXCEPTION_XOPEN_CONNECTION_FAILURE = "08006"; // After connection was connected OK @@ -61,7 +64,8 @@ public final class SQLServerException extends java.sql.SQLException { static final int LOGON_FAILED = 18456; static final int PASSWORD_EXPIRED = 18488; static final int USER_ACCOUNT_LOCKED = 18486; - static java.util.logging.Logger exLogger = java.util.logging.Logger.getLogger("com.microsoft.sqlserver.jdbc.internals.SQLServerException"); + static java.util.logging.Logger exLogger = java.util.logging.Logger + .getLogger("com.microsoft.sqlserver.jdbc.internals.SQLServerException"); // Facility for driver-specific error codes static final int DRIVER_ERROR_NONE = 0; @@ -77,7 +81,7 @@ public final class SQLServerException extends java.sql.SQLException { static final int DATA_CLASSIFICATION_NOT_EXPECTED = 11; static final int DATA_CLASSIFICATION_INVALID_LABEL_INDEX = 12; static final int DATA_CLASSIFICATION_INVALID_INFORMATION_TYPE_INDEX = 13; - + private int driverErrorCode = DRIVER_ERROR_NONE; final int getDriverErrorCode() { @@ -89,18 +93,16 @@ final void setDriverErrorCode(int value) { } /** - * Log an exception to the driver log file + * Logs an exception to the driver log file. * * @param o - * the io buffer that generated the exception + * the io buffer that generated the exception * @param errText - * the excception message + * the excception message * @param bStack - * true to generate the stack trace + * true to generate the stack trace */ - private void logException(Object o, - String errText, - boolean bStack) { + private void logException(Object o, String errText, boolean bStack) { String id = ""; if (o != null) id = o.toString(); @@ -133,97 +135,80 @@ static String getErrString(String errCode) { } /** - * Make a new SQLException + * Construct a SQLServerException. * * @param errText - * the exception message + * the exception message * @param sqlState - * the statement + * the statement * @param driverError - * the driver error object + * the driver error object * @param cause - * The exception that caused this exception + * The exception that caused this exception */ - public SQLServerException(String errText, - SQLState sqlState, - DriverError driverError, - Throwable cause) { + SQLServerException(String errText, SQLState sqlState, DriverError driverError, Throwable cause) { this(errText, sqlState.getSQLStateCode(), driverError.getErrorCode(), cause); } - public SQLServerException(String errText, - String errState, - int errNum, - Throwable cause) { + SQLServerException(String errText, String errState, int errNum, Throwable cause) { super(errText, errState, errNum); initCause(cause); logException(null, errText, true); - ActivityCorrelator.setCurrentActivityIdSentFlag(); // set the activityid flag so that we don't send the current ActivityId later. + ActivityCorrelator.setCurrentActivityIdSentFlag(); // set the activityid flag so that we don't send the current + // ActivityId later. } - public SQLServerException(String errText, - Throwable cause) { + SQLServerException(String errText, Throwable cause) { super(errText); initCause(cause); logException(null, errText, true); ActivityCorrelator.setCurrentActivityIdSentFlag(); } - /* L0 */ public SQLServerException(Object obj, - String errText, - String errState, - int errNum, - boolean bStack) { + SQLServerException(Object obj, String errText, String errState, int errNum, boolean bStack) { super(errText, errState, errNum); logException(obj, errText, bStack); ActivityCorrelator.setCurrentActivityIdSentFlag(); } /** - * Make a new SQLException + * Constructs a new SQLServerException. * * @param obj - * the object + * the object * @param errText - * the exception message + * the exception message * @param errState - * the exception state + * the exception state * @param streamError - * the StreamError object + * the StreamError object * @param bStack - * true to generate the stack trace + * true to generate the stack trace */ - /* L0 */ public SQLServerException(Object obj, - String errText, - String errState, - StreamError streamError, - boolean bStack) { + SQLServerException(Object obj, String errText, String errState, StreamError streamError, boolean bStack) { super(errText, errState, streamError.getErrorNumber()); // Log SQL error with info from StreamError. - errText = "Msg " + streamError.getErrorNumber() + ", Level " + streamError.getErrorSeverity() + ", State " + streamError.getErrorState() - + ", " + errText; + errText = "Msg " + streamError.getErrorNumber() + ", Level " + streamError.getErrorSeverity() + ", State " + + streamError.getErrorState() + ", " + errText; logException(obj, errText, bStack); } /** - * Build a new SQL Exception from an error detected by the driver. + * Constructs a SQLServerException from an error detected by the driver. * * @param con - * the connection + * the connection * @param obj * @param errText - * the excception message + * the excception message * @param state - * he excpeption state + * he excpeption state * @param bStack - * true to generate the stack trace + * true to generate the stack trace * @throws SQLServerException */ - /* L0 */static void makeFromDriverError(SQLServerConnection con, - Object obj, - String errText, - String state, + static void makeFromDriverError(SQLServerConnection con, Object obj, String errText, String state, boolean bStack) throws SQLServerException { // The sql error code is 0 since the error was not returned from the database // The state code is supplied by the calling code as XOPEN compliant. @@ -237,8 +222,8 @@ public SQLServerException(String errText, if (con == null || !con.xopenStates) stateCode = mapFromXopen(state); - SQLServerException theException = new SQLServerException(obj, SQLServerException.checkAndAppendClientConnId(errText, con), stateCode, 0, - bStack); + SQLServerException theException = new SQLServerException(obj, + SQLServerException.checkAndAppendClientConnId(errText, con), stateCode, 0, bStack); if ((null != state && state.equals(EXCEPTION_XOPEN_CONNECTION_FAILURE)) && (null != con)) { con.notifyPooledConnection(theException); // note this close wont close the connection if there is an associated pooled connection. @@ -249,27 +234,24 @@ public SQLServerException(String errText, } /** - * Build a new SQL Exception from a streamError detected by the driver. + * Builds a new SQL Exception from a streamError detected by the driver. * * @param con - * the connection + * the connection * @param obj * @param errText - * the excception message + * the excception message * @param streamError * @param bStack - * true to generate the stack trace + * true to generate the stack trace * @throws SQLServerException */ - /* L0 */ static void makeFromDatabaseError(SQLServerConnection con, - Object obj, - String errText, - StreamError streamError, + static void makeFromDatabaseError(SQLServerConnection con, Object obj, String errText, StreamError streamError, boolean bStack) throws SQLServerException { String state = generateStateCode(con, streamError.getErrorNumber(), streamError.getErrorState()); - SQLServerException theException = new SQLServerException(obj, SQLServerException.checkAndAppendClientConnId(errText, con), state, streamError, - bStack); + SQLServerException theException = new SQLServerException(obj, + SQLServerException.checkAndAppendClientConnId(errText, con), state, streamError, bStack); theException.setDriverErrorCode(DRIVER_ERROR_FROM_DATABASE); // Close the connection if we get a severity 20 or higher error class (nClass is severity of error). @@ -282,9 +264,7 @@ public SQLServerException(String errText, } // This code is same as the conversion logic that previously existed in connecthelper. - static void ConvertConnectExceptionToSQLServerException(String hostName, - int portNumber, - SQLServerConnection conn, + static void ConvertConnectExceptionToSQLServerException(String hostName, int portNumber, SQLServerConnection conn, Exception ex) throws SQLServerException { Exception connectException = ex; // Throw the exception if exception was caught by code above (stored in connectException). @@ -294,18 +274,19 @@ static void ConvertConnectExceptionToSQLServerException(String hostName, MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_tcpipConnectionFailed")); Object[] msgArgs = {hostName, Integer.toString(portNumber), formDetail.format(msgArgsDetail)}; String s = form.format(msgArgs); - SQLServerException.makeFromDriverError(conn, conn, s, SQLServerException.EXCEPTION_XOPEN_CONNECTION_CANT_ESTABLISH, false); + SQLServerException.makeFromDriverError(conn, conn, s, + SQLServerException.EXCEPTION_XOPEN_CONNECTION_CANT_ESTABLISH, false); } } /** - * Map XOPEN states. + * Maps XOPEN states. * * @param state - * the state + * the state * @return the mapped state */ - /* L0 */ static String mapFromXopen(String state) { + static String mapFromXopen(String state) { // Exceptions generated by the driver (not the database) are instanced with an XOPEN state code // since the SQL99 states cant be located on the web (must pay) and the XOPEN states appear to // be specific. Therefore if the driver is in SQL 99 mode we must map to SQL 99 state codes. @@ -328,19 +309,17 @@ static void ConvertConnectExceptionToSQLServerException(String hostName, } /** - * Generate the JDBC state code based on the error number returned from the database + * Generates the JDBC state code based on the error number returned from the database. * * @param con - * the connection + * the connection * @param errNum - * the error number + * the error number * @param databaseState - * the database state + * the database state * @return the state code */ - /* L0 */ static String generateStateCode(SQLServerConnection con, - int errNum, - int databaseState) { + static String generateStateCode(SQLServerConnection con, int errNum, int databaseState) { // Generate a SQL 99 or XOPEN state from a database generated error code boolean xopenStates = (con != null && con.xopenStates); if (xopenStates) { @@ -359,21 +338,20 @@ static void ConvertConnectExceptionToSQLServerException(String hostName, } return "42000"; // Use XOPEN 'Syntax error or access violation' // The error code came from the db but XOPEN does not have a specific case for it. - } - else { + } else { switch (errNum) { // case 18456: return "08001"; //username password wrong at login case 8152: return "22001"; // String data right truncation case 515: // 2.2705 case 547: - return "23000"; // Integrity constraint violation + return "23000"; // Integrity constraint violation case 2601: - return "23000"; // Integrity constraint violation + return "23000"; // Integrity constraint violation case 2714: return "S0001"; // table already exists case 208: - return "S0002"; // table not found + return "S0002"; // table not found case 1205: return "40001"; // deadlock detected case 2627: @@ -384,16 +362,16 @@ static void ConvertConnectExceptionToSQLServerException(String hostName, } /** - * Append ClientConnectionId to an error message if applicable + * Appends ClientConnectionId to an error message if applicable. * * @param errMsg - * - the orginal error message. + * - the orginal error message. * @param conn - * - the SQLServerConnection object - * @return error string concated by ClientConnectionId(in string format) if applicable, otherwise, return original error string. + * - the SQLServerConnection object + * @return error string concated by ClientConnectionId(in string format) if applicable, otherwise, return original + * error string. */ - static String checkAndAppendClientConnId(String errMsg, - SQLServerConnection conn) throws SQLServerException { + static String checkAndAppendClientConnId(String errMsg, SQLServerConnection conn) throws SQLServerException { if (null != conn && conn.attachConnId()) { UUID clientConnId = conn.getClientConIdInternal(); assert null != clientConnId; @@ -403,16 +381,16 @@ static String checkAndAppendClientConnId(String errMsg, sb.append(LOG_CLIENT_CONNECTION_ID_PREFIX); sb.append(clientConnId.toString()); return sb.toString(); - } - else { + } else { return errMsg; } } static void throwNotSupportedException(SQLServerConnection con, Object obj) throws SQLServerException { - SQLServerException.makeFromDriverError(con, obj, SQLServerException.getErrString("R_notSupported"), null, false); + SQLServerException.makeFromDriverError(con, obj, SQLServerException.getErrString("R_notSupported"), null, + false); } - + static void throwFeatureNotSupportedException() throws SQLFeatureNotSupportedException { throw new SQLFeatureNotSupportedException(SQLServerException.getErrString("R_notSupported")); } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerJdbc43.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerJdbc43.java index 1100f132d..4c7f2db6f 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerJdbc43.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerJdbc43.java @@ -1,20 +1,18 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; import java.sql.BatchUpdateException; + /** * Shims for JDBC 4.3 JAR. * - * JDBC 4.3 public methods should always check the SQLServerJdbcVersion first to make sure that they are not operable in any earlier driver version. - * That is, they should throw an exception, be a no-op, or whatever. + * JDBC 4.3 public methods should always check the SQLServerJdbcVersion first to make sure that they are not operable in + * any earlier driver version. That is, they should throw an exception, be a no-op, or whatever. */ final class DriverJDBCVersion { @@ -22,12 +20,11 @@ final class DriverJDBCVersion { static final int major = 4; static final int minor = 3; - static final void checkSupportsJDBC43() { - } + static final void checkSupportsJDBC43() {} static final void throwBatchUpdateException(SQLServerException lastError, long[] updateCounts) throws BatchUpdateException { - throw new BatchUpdateException(lastError.getMessage(), lastError.getSQLState(), lastError.getErrorCode(), updateCounts, - new Throwable(lastError.getMessage())); + throw new BatchUpdateException(lastError.getMessage(), lastError.getSQLState(), lastError.getErrorCode(), + updateCounts, new Throwable(lastError.getMessage())); } -} \ No newline at end of file +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerKeyVaultAuthenticationCallback.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerKeyVaultAuthenticationCallback.java index dc4bddda1..daa475b99 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerKeyVaultAuthenticationCallback.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerKeyVaultAuthenticationCallback.java @@ -1,27 +1,26 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; +/** + * Provides a callback delegate which is to be implemented by the client code + * + */ public interface SQLServerKeyVaultAuthenticationCallback { /** - * The authentication callback delegate which is to be implemented by the client code + * Returns the acesss token of the authentication request * * @param authority - * - Identifier of the authority, a URL. + * - Identifier of the authority, a URL. * @param resource - * - Identifier of the target resource that is the recipient of the requested token, a URL. + * - Identifier of the target resource that is the recipient of the requested token, a URL. * @param scope - * - The scope of the authentication request. + * - The scope of the authentication request. * @return access token */ - public String getAccessToken(String authority, - String resource, - String scope); -} \ No newline at end of file + public String getAccessToken(String authority, String resource, String scope); +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerLob.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerLob.java index 1849915be..0fdee293d 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerLob.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerLob.java @@ -1,18 +1,16 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; import java.sql.SQLException; + abstract class SQLServerLob { /** - * Function for the result set to maintain blobs it has created + * Provides functionality for the result set to maintain blobs it has created. * * @throws SQLException */ diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerMetaData.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerMetaData.java index 00614ff8b..da9db54b7 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerMetaData.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerMetaData.java @@ -1,202 +1,203 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -import java.text.MessageFormat; - -/** - * - * This class represents metadata for a column. It is used in the ISQLServerDataRecord interface to pass column metadata to the table-valued - * parameter. - * - */ -public class SQLServerMetaData { - - String columnName = null; - int javaSqlType; - int precision = 0; - int scale = 0; - boolean useServerDefault = false; - boolean isUniqueKey = false; - SQLServerSortOrder sortOrder = SQLServerSortOrder.Unspecified; - int sortOrdinal; - private SQLCollation collation; - - static final int defaultSortOrdinal = -1; - - /** - * Creates a new SQLServerMetaData - * - * @param columnName - * the name of the column - * @param sqlType - * the SQL type of the column - */ - public SQLServerMetaData(String columnName, - int sqlType) { - this.columnName = columnName; - this.javaSqlType = sqlType; - } - - /** - * creates a new SQLServerMetaData - * - * @param columnName - * the name of the column - * @param sqlType - * the SQL type of the column - * @param precision - * the precision of the column - * @param scale - * the scale of the column - */ - public SQLServerMetaData(String columnName, - int sqlType, - int precision, - int scale) { - this.columnName = columnName; - this.javaSqlType = sqlType; - this.precision = precision; - this.scale = scale; - } - - /** - * Creates a new SQLServerMetaData - * - * @param columnName - * the name of the column - * @param sqlType - * the sql type of the column - * @param precision - * the precision of the column - * @param scale - * the scale of the column - * @param useServerDefault - * specifies if this column should use the default server value; Default value is false. - * @param isUniqueKey - * indicates if the column in the table-valued parameter is unique; Default value is false. - * @param sortOrder - * indicates the sort order for a column; Default value is SQLServerSortOrder.Unspecified. - * @param sortOrdinal - * specifies ordinal of the sort column; sortOrdinal starts from 0; Default value is -1. - * @throws SQLServerException - * when an error occurs - */ - public SQLServerMetaData(String columnName, - int sqlType, - int precision, - int scale, - boolean useServerDefault, - boolean isUniqueKey, - SQLServerSortOrder sortOrder, - int sortOrdinal) throws SQLServerException { - this.columnName = columnName; - this.javaSqlType = sqlType; - this.precision = precision; - this.scale = scale; - this.useServerDefault = useServerDefault; - this.isUniqueKey = isUniqueKey; - this.sortOrder = sortOrder; - this.sortOrdinal = sortOrdinal; - validateSortOrder(); - } - - /** - * Initializes a new instance of SQLServerMetaData from another SQLServerMetaData object. - * - * @param sqlServerMetaData - * the object passed to initialize a new instance of SQLServerMetaData - */ - public SQLServerMetaData(SQLServerMetaData sqlServerMetaData) { - this.columnName = sqlServerMetaData.columnName; - this.javaSqlType = sqlServerMetaData.javaSqlType; - this.precision = sqlServerMetaData.precision; - this.scale = sqlServerMetaData.scale; - this.useServerDefault = sqlServerMetaData.useServerDefault; - this.isUniqueKey = sqlServerMetaData.isUniqueKey; - this.sortOrder = sqlServerMetaData.sortOrder; - this.sortOrdinal = sqlServerMetaData.sortOrdinal; - } - - /** - * - * @return Retrieves the column name. - */ - public String getColumName() { - return columnName; - } - - /** - * - * @return Retrieves the java sql type. - */ - public int getSqlType() { - return javaSqlType; - } - - /** - * - * @return retrieves the precision of the type passed to the column. - */ - public int getPrecision() { - return precision; - } - - /** - * - * @return retrieves the scale of the type passed to the column. - */ - public int getScale() { - return scale; - } - - /** - * - * @return returns whether the column uses the default server value. - */ - public boolean useServerDefault() { - return useServerDefault; - } - - /** - * - * @return retrieves the whether the column is unique. - */ - public boolean isUniqueKey() { - return isUniqueKey; - } - - /** - * - * @return retrieves the sort order. - */ - public SQLServerSortOrder getSortOrder() { - return sortOrder; - } - - /** - * - * @return retrieves the sort ordinal. - */ - public int getSortOrdinal() { - return sortOrdinal; - } - - SQLCollation getCollation() { - return this.collation; - } - - void validateSortOrder() throws SQLServerException { - // should specify both sort order and ordinal, or neither - if ((SQLServerSortOrder.Unspecified == sortOrder) != (defaultSortOrdinal == sortOrdinal)) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_TVPMissingSortOrderOrOrdinal")); - throw new SQLServerException(form.format(new Object[] {sortOrder, sortOrdinal}), null, 0, null); - } - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +import java.text.MessageFormat; + + +/** + * + * Represents metadata for a column. It is used in the ISQLServerDataRecord interface to pass column metadata to the + * table-valued parameter. + * + */ +public class SQLServerMetaData { + + String columnName = null; + int javaSqlType; + int precision = 0; + int scale = 0; + boolean useServerDefault = false; + boolean isUniqueKey = false; + SQLServerSortOrder sortOrder = SQLServerSortOrder.Unspecified; + int sortOrdinal; + private SQLCollation collation; + + static final int defaultSortOrdinal = -1; + + /** + * Constructs a SQLServerMetaData with the column name and SQL type. + * + * @param columnName + * the name of the column + * @param sqlType + * the SQL type of the column + */ + public SQLServerMetaData(String columnName, int sqlType) { + this.columnName = columnName; + this.javaSqlType = sqlType; + } + + /** + * Constructs a SQLServerMetaData with the column name, SQL type, precision, and scale. + * + * @param columnName + * the name of the column + * @param sqlType + * the SQL type of the column + * @param precision + * the precision of the column + * @param scale + * the scale of the column + */ + public SQLServerMetaData(String columnName, int sqlType, int precision, int scale) { + this.columnName = columnName; + this.javaSqlType = sqlType; + this.precision = precision; + this.scale = scale; + } + + /** + * Constructs a SQLServerMetaData. + * + * @param columnName + * the name of the column + * @param sqlType + * the sql type of the column + * @param precision + * the precision of the column + * @param scale + * the scale of the column + * @param useServerDefault + * specifies if this column should use the default server value; Default value is false. + * @param isUniqueKey + * indicates if the column in the table-valued parameter is unique; Default value is false. + * @param sortOrder + * indicates the sort order for a column; Default value is SQLServerSortOrder.Unspecified. + * @param sortOrdinal + * specifies ordinal of the sort column; sortOrdinal starts from 0; Default value is -1. + * @throws SQLServerException + * when an error occurs + */ + public SQLServerMetaData(String columnName, int sqlType, int precision, int scale, boolean useServerDefault, + boolean isUniqueKey, SQLServerSortOrder sortOrder, int sortOrdinal) throws SQLServerException { + this.columnName = columnName; + this.javaSqlType = sqlType; + this.precision = precision; + this.scale = scale; + this.useServerDefault = useServerDefault; + this.isUniqueKey = isUniqueKey; + this.sortOrder = sortOrder; + this.sortOrdinal = sortOrdinal; + validateSortOrder(); + } + + /** + * Constructs a SQLServerMetaData from another SQLServerMetaData object. + * + * @param sqlServerMetaData + * the object passed to initialize a new instance of SQLServerMetaData + */ + public SQLServerMetaData(SQLServerMetaData sqlServerMetaData) { + this.columnName = sqlServerMetaData.columnName; + this.javaSqlType = sqlServerMetaData.javaSqlType; + this.precision = sqlServerMetaData.precision; + this.scale = sqlServerMetaData.scale; + this.useServerDefault = sqlServerMetaData.useServerDefault; + this.isUniqueKey = sqlServerMetaData.isUniqueKey; + this.sortOrder = sqlServerMetaData.sortOrder; + this.sortOrdinal = sqlServerMetaData.sortOrdinal; + } + + /** + * Returns the column name. + * + * @return column name + */ + public String getColumName() { + return columnName; + } + + /** + * Returns the java sql type. + * + * @return java sql type + */ + public int getSqlType() { + return javaSqlType; + } + + /** + * Returns the precision of the type passed to the column. + * + * @return precision + */ + public int getPrecision() { + return precision; + } + + /** + * Returns the scale of the type passed to the column. + * + * @return scale + */ + public int getScale() { + return scale; + } + + /** + * Returns whether the column uses the default server value. + * + * @return whether the column uses the default server value. + */ + public boolean useServerDefault() { + return useServerDefault; + } + + /** + * Returns whether the column is unique. + * + * @return whether the column is unique. + */ + public boolean isUniqueKey() { + return isUniqueKey; + } + + /** + * Returns the sort order. + * + * @return sort order + */ + public SQLServerSortOrder getSortOrder() { + return sortOrder; + } + + /** + * Returns the sort ordinal. + * + * @return sort ordinal + */ + public int getSortOrdinal() { + return sortOrdinal; + } + + /** + * Returns the collation. + * + * @return SQL collation + */ + SQLCollation getCollation() { + return this.collation; + } + + void validateSortOrder() throws SQLServerException { + // should specify both sort order and ordinal, or neither + if ((SQLServerSortOrder.Unspecified == sortOrder) != (defaultSortOrdinal == sortOrdinal)) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_TVPMissingSortOrderOrOrdinal")); + throw new SQLServerException(form.format(new Object[] {sortOrder, sortOrdinal}), null, 0, null); + } + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerNClob.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerNClob.java index f3930381c..dfa9fb12d 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerNClob.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerNClob.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -18,10 +15,10 @@ import java.sql.SQLException; import java.util.logging.Logger; + /** - * SQLServerNClob represents a National Character Set LOB object and implements java.sql.NClob. + * Represents a National Character Set LOB object and implements java.sql.NClob. */ - public final class SQLServerNClob extends SQLServerClobBase implements NClob { /** @@ -37,8 +34,7 @@ public final class SQLServerNClob extends SQLServerClobBase implements NClob { super(connection, "", connection.getDatabaseCollation(), logger, null); } - SQLServerNClob(BaseInputStream stream, - TypeInfo typeInfo) throws SQLServerException, UnsupportedEncodingException { + SQLServerNClob(BaseInputStream stream, TypeInfo typeInfo) throws SQLServerException, UnsupportedEncodingException { super(null, stream, typeInfo.getSQLCollation(), logger, typeInfo); } @@ -58,14 +54,12 @@ public Reader getCharacterStream() throws SQLException { } @Override - public Reader getCharacterStream(long pos, - long length) throws SQLException { + public Reader getCharacterStream(long pos, long length) throws SQLException { return super.getCharacterStream(pos, length); } @Override - public String getSubString(long pos, - int length) throws SQLException { + public String getSubString(long pos, int length) throws SQLException { return super.getSubString(pos, length); } @@ -80,14 +74,12 @@ void fillFromStream() throws SQLException { } @Override - public long position(Clob searchstr, - long start) throws SQLException { + public long position(Clob searchstr, long start) throws SQLException { return super.position(searchstr, start); } @Override - public long position(String searchstr, - long start) throws SQLException { + public long position(String searchstr, long start) throws SQLException { return super.position(searchstr, start); } @@ -107,16 +99,12 @@ public Writer setCharacterStream(long pos) throws SQLException { } @Override - public int setString(long pos, - String s) throws SQLException { + public int setString(long pos, String s) throws SQLException { return super.setString(pos, s); } @Override - public int setString(long pos, - String str, - int offset, - int len) throws SQLException { + public int setString(long pos, String str, int offset, int len) throws SQLException { return super.setString(pos, str, offset, len); } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerParameterMetaData.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerParameterMetaData.java index f9ebd3b1c..49cf07a34 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerParameterMetaData.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerParameterMetaData.java @@ -1,15 +1,11 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; import java.sql.ParameterMetaData; -import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; @@ -23,14 +19,15 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; + /** - * SQLServerParameterMetaData provides JDBC 3.0 meta data for prepared statement parameters. + * Provides meta data for prepared statement parameters. * - * The API javadoc for JDBC API methods that this class implements are not repeated here. Please see Sun's JDBC API interfaces javadoc for those - * details. + * The API javadoc for JDBC API methods that this class implements are not repeated here. Please see Sun's JDBC API + * interfaces javadoc for those details. * - * Prepared statements are executed with SET FMT ONLY to retrieve column meta data Callable statements : sp_sp_sproc_columns is called to retrieve - * names and meta data for the procedures params. + * Prepared statements are executed with SET FMT ONLY to retrieve column meta data Callable statements : + * sp_sp_sproc_columns is called to retrieve names and meta data for the procedures params. */ public final class SQLServerParameterMetaData implements ParameterMetaData { @@ -43,16 +40,17 @@ public final class SQLServerParameterMetaData implements ParameterMetaData { /* Used for callable statement meta data */ private Statement stmtCall; private SQLServerResultSet rsProcedureMeta; - + protected boolean procedureIsFound = false; static final private java.util.logging.Logger logger = java.util.logging.Logger .getLogger("com.microsoft.sqlserver.jdbc.internals.SQLServerParameterMetaData"); - static private final AtomicInteger baseID = new AtomicInteger(0); // Unique id generator for each instance (used for logging). + static private final AtomicInteger baseID = new AtomicInteger(0); // Unique id generator for each instance (used for + // logging). final private String traceID = " SQLServerParameterMetaData:" + nextInstanceID(); boolean isTVP = false; - + private String stringToParse = null; private int indexToBeginParse = -1; @@ -62,7 +60,7 @@ private static int nextInstanceID() { } /** - * This is a helper function to provide an ID string suitable for tracing. + * Provides a helper function to provide an ID string suitable for tracing. * * @return traceID string */ @@ -72,16 +70,15 @@ final public String toString() { } /** - * Parse the columns in a column set. + * Parses the columns in a column set. * * @param columnSet - * the list of columns + * the list of columns * @param columnStartToken - * the token that prfixes the column set - * @throws SQLServerException + * the token that prfixes the column set + * @throws SQLServerException */ - private String parseColumns(String columnSet, - String columnStartToken) throws SQLServerException { + private String parseColumns(String columnSet, String columnStartToken) throws SQLServerException { StringTokenizer st = new StringTokenizer(columnSet, " =?<>!\r\n\t\f", true); final int START = 0; final int PARAMNAME = 1; @@ -96,16 +93,16 @@ private String parseColumns(String columnSet, String sToken = st.nextToken(); sTokenIndex = sTokenIndex + sToken.length(); - + if (sToken.equalsIgnoreCase(columnStartToken)) { nState = PARAMNAME; continue; } if (nState == START) continue; - if ((sToken.charAt(0) == '=') || sToken.equalsIgnoreCase("is") || (sToken.charAt(0) == '<') || (sToken.charAt(0) == '>') - || sToken.equalsIgnoreCase("like") || sToken.equalsIgnoreCase("not") || sToken.equalsIgnoreCase("in") - || (sToken.charAt(0) == '!')) { + if ((sToken.charAt(0) == '=') || sToken.equalsIgnoreCase("is") || (sToken.charAt(0) == '<') + || (sToken.charAt(0) == '>') || sToken.equalsIgnoreCase("like") || sToken.equalsIgnoreCase("not") + || sToken.equalsIgnoreCase("in") || (sToken.charAt(0) == '!')) { nState = PARAMVALUE; continue; } @@ -134,16 +131,15 @@ private String parseColumns(String columnSet, } /** - * Parse the column set in an insert syntax. + * Parses the column set in an insert syntax. * * @param sql - * the sql syntax + * the sql syntax * @param columnMarker - * the token that denotes the start of the column set - * @throws SQLServerException + * the token that denotes the start of the column set + * @throws SQLServerException */ - private String parseInsertColumns(String sql, - String columnMarker) throws SQLServerException { + private String parseInsertColumns(String sql, String columnMarker) throws SQLServerException { StringTokenizer st = new StringTokenizer(sql, " (),", true); int nState = 0; String sLastField = null; @@ -153,7 +149,7 @@ private String parseInsertColumns(String sql, while (st.hasMoreTokens()) { String sToken = st.nextToken(); sTokenIndex = sTokenIndex + sToken.length(); - + if (sToken.equalsIgnoreCase(columnMarker)) { nState = 1; continue; @@ -180,7 +176,8 @@ private String parseInsertColumns(String sql, if (sToken.charAt(0) != ',') { sLastField = escapeParse(st, sToken); - // in case the parameter has braces in its name, e.g. [c2_nvarchar(max)], the original sToken variable just + // in case the parameter has braces in its name, e.g. [c2_nvarchar(max)], the original sToken + // variable just // contains [c2_nvarchar, sLastField actually has the whole name [c2_nvarchar(max)] sTokenIndex = sTokenIndex + (sLastField.length() - sToken.length()); } @@ -206,7 +203,7 @@ class QueryMeta { Map queryMetaMap = null; /* - * Parse query metadata. + * Parses query metadata. */ private void parseQueryMeta(ResultSet rsQueryMeta) throws SQLServerException { Pattern datatypePattern = Pattern.compile("(.*)\\((.*)(\\)|,(.*)\\))"); @@ -220,8 +217,8 @@ private void parseQueryMeta(ResultSet rsQueryMeta) throws SQLServerException { if (null == typename) { typename = rsQueryMeta.getString("suggested_user_type_name"); - SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con - .prepareCall("select max_length, precision, scale, is_nullable from sys.assembly_types where name = ?"); + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con.prepareCall( + "select max_length, precision, scale, is_nullable from sys.assembly_types where name = ?"); pstmt.setNString(1, typename); ResultSet assemblyRs = pstmt.executeQuery(); if (assemblyRs.next()) { @@ -230,8 +227,7 @@ private void parseQueryMeta(ResultSet rsQueryMeta) throws SQLServerException { qm.scale = assemblyRs.getInt("scale"); ssType = SSType.UDT; } - } - else { + } else { qm.precision = rsQueryMeta.getInt("suggested_precision"); qm.scale = rsQueryMeta.getInt("suggested_scale"); @@ -241,24 +237,24 @@ private void parseQueryMeta(ResultSet rsQueryMeta) throws SQLServerException { ssType = SSType.of(matcher.group(1)); if (typename.equalsIgnoreCase("varchar(max)") || typename.equalsIgnoreCase("varbinary(max)")) { qm.precision = SQLServerDatabaseMetaData.MAXLOBSIZE; - } - else if (typename.equalsIgnoreCase("nvarchar(max)")) { + } else if (typename.equalsIgnoreCase("nvarchar(max)")) { qm.precision = SQLServerDatabaseMetaData.MAXLOBSIZE / 2; - } - else if (SSType.Category.CHARACTER == ssType.category || SSType.Category.BINARY == ssType.category + } else if (SSType.Category.CHARACTER == ssType.category + || SSType.Category.BINARY == ssType.category || SSType.Category.NCHARACTER == ssType.category) { try { - // For character/binary data types "suggested_precision" is 0. So get the precision from the type itself. + // For character/binary data types "suggested_precision" is 0. So get the precision from + // the type itself. qm.precision = Integer.parseInt(matcher.group(2)); - } - catch (NumberFormatException e) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_metaDataErrorForParameter")); + } catch (NumberFormatException e) { + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_metaDataErrorForParameter")); Object[] msgArgs = {paramOrdinal}; - SQLServerException.makeFromDriverError(con, stmtParent, form.format(msgArgs) + " " + e.toString(), null, false); + SQLServerException.makeFromDriverError(con, stmtParent, + form.format(msgArgs) + " " + e.toString(), null, false); } } - } - else + } else ssType = SSType.of(typename); // For float and real types suggested_precision returns the number of bits, not digits. @@ -266,26 +262,19 @@ else if (SSType.Category.CHARACTER == ssType.category || SSType.Category.BINARY // https://msdn.microsoft.com/en-CA/library/ms173773.aspx // real is float(24) and is 7 digits. Float is 15 digits. qm.precision = 15; - } - else if (SSType.REAL == ssType) { + } else if (SSType.REAL == ssType) { qm.precision = 7; - } - else if (SSType.TEXT == ssType) { + } else if (SSType.TEXT == ssType) { qm.precision = SQLServerDatabaseMetaData.MAXLOBSIZE; - } - else if (SSType.NTEXT == ssType) { + } else if (SSType.NTEXT == ssType) { qm.precision = SQLServerDatabaseMetaData.MAXLOBSIZE / 2; - } - else if (SSType.IMAGE == ssType) { + } else if (SSType.IMAGE == ssType) { qm.precision = SQLServerDatabaseMetaData.MAXLOBSIZE; - } - else if (SSType.GUID == ssType) { + } else if (SSType.GUID == ssType) { qm.precision = SQLServerDatabaseMetaData.uniqueidentifierSize; - } - else if (SSType.TIMESTAMP == ssType) { + } else if (SSType.TIMESTAMP == ssType) { qm.precision = 8; - } - else if (SSType.XML == ssType) { + } else if (SSType.XML == ssType) { qm.precision = SQLServerDatabaseMetaData.MAXLOBSIZE / 2; } @@ -301,11 +290,11 @@ else if (SSType.XML == ssType) { qm.parameterClassName = jdbcType.className(); qm.parameterType = jdbcType.getIntValue(); // The parameter can be signed if it is a NUMERIC type (except bit or tinyint). - qm.isSigned = ((SSType.Category.NUMERIC == ssType.category) && (SSType.BIT != ssType) && (SSType.TINYINT != ssType)); + qm.isSigned = ((SSType.Category.NUMERIC == ssType.category) && (SSType.BIT != ssType) + && (SSType.TINYINT != ssType)); queryMetaMap.put(paramOrdinal, qm); } - } - catch (SQLException e) { + } catch (SQLException e) { throw new SQLServerException(SQLServerException.getErrString("R_metaDataErrorForParameter"), e); } } @@ -330,23 +319,21 @@ private void parseQueryMetaFor2008(ResultSet rsQueryMeta) throws SQLServerExcept queryMetaMap.put(i, qm); } - } - catch (SQLException e) { + } catch (SQLException e) { throw new SQLServerException(SQLServerException.getErrString("R_metaDataErrorForParameter"), e); } } /** - * Escape parser, using the tokenizer tokenizes escaped strings properly e.g.[Table Name, ] + * Parses escaped strings properly e.g.[Table Name, ] using tokenizer. * * @param st - * string tokenizer + * string tokenizer * @param firstToken * @throws SQLServerException * @returns the full token */ - private String escapeParse(StringTokenizer st, - String firstToken) throws SQLServerException { + private String escapeParse(StringTokenizer st, String firstToken) throws SQLServerException { if (null == firstToken) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_NullValue")); @@ -378,24 +365,22 @@ private class MetaInfo { String table; String fields; - MetaInfo(String table, - String fields) { + MetaInfo(String table, String fields) { this.table = table; this.fields = fields; } } /** - * Parse a SQL syntax. + * Parses a SQL syntax. * * @param sql - * String + * String * @param sTableMarker - * the location of the table in the syntax - * @throws SQLServerException + * the location of the table in the syntax + * @throws SQLServerException */ - private MetaInfo parseStatement(String sql, - String sTableMarker) throws SQLServerException { + private MetaInfo parseStatement(String sql, String sTableMarker) throws SQLServerException { StringTokenizer st = new StringTokenizer(sql, " ,\r\n\t\f(", true); /* Find the table */ @@ -405,7 +390,7 @@ private MetaInfo parseStatement(String sql, while (st.hasMoreTokens()) { String sToken = st.nextToken().trim(); - if(sToken.contains("*/")){ + if (sToken.contains("*/")) { sToken = removeCommentsInTheBeginning(sToken, 0, 0, "/*", "*/"); } @@ -421,8 +406,7 @@ private MetaInfo parseStatement(String sql, if (sTableMarker.equalsIgnoreCase("UPDATE")) { metaFields = parseColumns(sql, "SET"); // Get the set fields stringToParse = ""; - } - else if (sTableMarker.equalsIgnoreCase("INTO")) { // insert + } else if (sTableMarker.equalsIgnoreCase("INTO")) { // insert metaFields = parseInsertColumns(sql, "("); // Get the value fields stringToParse = sql.substring(indexToBeginParse); // the index of ')' @@ -431,8 +415,7 @@ else if (sTableMarker.equalsIgnoreCase("INTO")) { // insert parseInsertColumns(stringToParse, "("); stringToParse = stringToParse.substring(indexToBeginParse); // the index of ')' } - } - else { + } else { metaFields = parseColumns(sql, "WHERE"); // Get the where fields stringToParse = ""; } @@ -444,10 +427,10 @@ else if (sTableMarker.equalsIgnoreCase("INTO")) { // insert } /** - * Parse a SQL syntax. + * Parses a SQL syntax. * * @param sql - * the syntax + * the syntax * @throws SQLServerException */ private MetaInfo parseStatement(String sql) throws SQLServerException { @@ -482,12 +465,9 @@ private MetaInfo parseStatement(String sql) throws SQLServerException { return null; } - - private String removeCommentsInTheBeginning(String sql, - int startCommentMarkCount, - int endCommentMarkCount, - String startMark, - String endMark) { + + private String removeCommentsInTheBeginning(String sql, int startCommentMarkCount, int endCommentMarkCount, + String startMark, String endMark) { int startCommentMarkIndex = sql.indexOf(startMark); int endCommentMarkIndex = sql.indexOf(endMark); @@ -498,7 +478,8 @@ private String removeCommentsInTheBeginning(String sql, endCommentMarkIndex = Integer.MAX_VALUE; } - // Base case. startCommentMarkCount is guaranteed to be bigger than 0 because the method is called when /* occurs + // Base case. startCommentMarkCount is guaranteed to be bigger than 0 because the method is called when /* + // occurs if (startCommentMarkCount == endCommentMarkCount) { if (startCommentMarkCount != 0 && endCommentMarkCount != 0) { return sql; @@ -508,7 +489,8 @@ private String removeCommentsInTheBeginning(String sql, // filter out first start comment mark if (startCommentMarkIndex < endCommentMarkIndex) { String sqlWithoutCommentsInBeginning = sql.substring(startCommentMarkIndex + startMark.length()); - return removeCommentsInTheBeginning(sqlWithoutCommentsInBeginning, ++startCommentMarkCount, endCommentMarkCount, startMark, endMark); + return removeCommentsInTheBeginning(sqlWithoutCommentsInBeginning, ++startCommentMarkCount, + endCommentMarkCount, startMark, endMark); } // filter out first end comment mark else { @@ -517,7 +499,8 @@ private String removeCommentsInTheBeginning(String sql, } String sqlWithoutCommentsInBeginning = sql.substring(endCommentMarkIndex + endMark.length()); - return removeCommentsInTheBeginning(sqlWithoutCommentsInBeginning, startCommentMarkCount, ++endCommentMarkCount, startMark, endMark); + return removeCommentsInTheBeginning(sqlWithoutCommentsInBeginning, startCommentMarkCount, + ++endCommentMarkCount, startMark, endMark); } } @@ -538,7 +521,8 @@ String parseProcIdentifier(String procIdentifier) throws SQLServerException { sb.append("@procedure_name="); sb.append(threePartName.getProcedurePart()); } else { - SQLServerException.makeFromDriverError(con, stmtParent, SQLServerException.getErrString("R_noMetadata"), null, false); + SQLServerException.makeFromDriverError(con, stmtParent, SQLServerException.getErrString("R_noMetadata"), + null, false); } return sb.toString(); } @@ -550,16 +534,15 @@ private void checkClosed() throws SQLServerException { } /** - * Create new parameter meta data. + * Construct a SQLServerParameterMetaData parameter meta data. * * @param st - * the prepared statement + * the prepared statement * @param sProcString - * the pricedure name + * the pricedure name * @throws SQLServerException */ - SQLServerParameterMetaData(SQLServerStatement st, - String sProcString) throws SQLServerException { + SQLServerParameterMetaData(SQLServerStatement st, String sProcString) throws SQLServerException { assert null != st; stmtParent = st; @@ -574,18 +557,18 @@ private void checkClosed() throws SQLServerException { // If the CallableStatement/PreparedStatement is a stored procedure call // then we can extract metadata using sp_sproc_columns if (null != st.procedureName) { - s = (SQLServerStatement) con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); + s = (SQLServerStatement) con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, + ResultSet.CONCUR_READ_ONLY); String sProc = parseProcIdentifier(st.procedureName); if (con.isKatmaiOrLater()) rsProcedureMeta = s.executeQueryInternal("exec sp_sproc_columns_100 " + sProc + ", @ODBCVer=3"); else rsProcedureMeta = s.executeQueryInternal("exec sp_sproc_columns " + sProc + ", @ODBCVer=3"); - + // if rsProcedureMeta has next row, it means the stored procedure is found if (rsProcedureMeta.next()) { procedureIsFound = true; - } - else { + } else { procedureIsFound = false; } rsProcedureMeta.beforeFirst(); @@ -609,22 +592,25 @@ private void checkClosed() throws SQLServerException { if (con.getServerMajorVersion() >= SQL_SERVER_2012_VERSION) { // new implementation for SQL verser 2012 and above String preparedSQL = con.replaceParameterMarkers(((SQLServerPreparedStatement) stmtParent).userSQL, - ((SQLServerPreparedStatement) stmtParent).inOutParam, ((SQLServerPreparedStatement) stmtParent).bReturnValueSyntax); + ((SQLServerPreparedStatement) stmtParent).userSQLParamPositions, + ((SQLServerPreparedStatement) stmtParent).inOutParam, + ((SQLServerPreparedStatement) stmtParent).bReturnValueSyntax); - SQLServerCallableStatement cstmt = (SQLServerCallableStatement) con.prepareCall("exec sp_describe_undeclared_parameters ?"); + SQLServerCallableStatement cstmt = (SQLServerCallableStatement) con + .prepareCall("exec sp_describe_undeclared_parameters ?"); cstmt.setNString(1, preparedSQL); parseQueryMeta(cstmt.executeQueryInternal()); cstmt.close(); - } - else { + } else { // old implementation for SQL server 2008 stringToParse = sProcString; ArrayList metaInfoList = new ArrayList<>(); - + while (stringToParse.length() > 0) { MetaInfo metaInfo = parseStatement(stringToParse); if (null == metaInfo) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_cantIdentifyTableMetadata")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_cantIdentifyTableMetadata")); Object[] msgArgs = {stringToParse}; SQLServerException.makeFromDriverError(con, stmtParent, form.format(msgArgs), null, false); } @@ -634,7 +620,7 @@ private void checkClosed() throws SQLServerException { if (metaInfoList.size() <= 0 || metaInfoList.get(0).fields.length() <= 0) { return; } - + StringBuilder sbColumns = new StringBuilder(); for (MetaInfo mi : metaInfoList) { @@ -648,15 +634,14 @@ private void checkClosed() throws SQLServerException { for (int i = 0; i < metaInfoList.size(); i++) { if (i == 0) { sbTablesAndJoins = sbTablesAndJoins.append(metaInfoList.get(i).table); - } - else { + } else { if (metaInfoList.get(i).table.equals(metaInfoList.get(i - 1).table) && metaInfoList.get(i).fields.equals(metaInfoList.get(i - 1).fields)) { continue; } - sbTablesAndJoins = sbTablesAndJoins - .append(" LEFT JOIN " + metaInfoList.get(i).table + " ON " + metaInfoList.get(i - 1).table + "." - + metaInfoList.get(i - 1).fields + "=" + metaInfoList.get(i).table + "." + metaInfoList.get(i).fields); + sbTablesAndJoins = sbTablesAndJoins.append(" LEFT JOIN " + metaInfoList.get(i).table + + " ON " + metaInfoList.get(i - 1).table + "." + metaInfoList.get(i - 1).fields + + "=" + metaInfoList.get(i).table + "." + metaInfoList.get(i).fields); } } @@ -673,14 +658,11 @@ private void checkClosed() throws SQLServerException { // Do not need to wrapper SQLServerException again catch (SQLServerException e) { throw e; - } - catch (SQLException e) { + } catch (SQLException e) { SQLServerException.makeFromDriverError(con, stmtParent, e.toString(), null, false); - } - catch(StringIndexOutOfBoundsException e){ + } catch (StringIndexOutOfBoundsException e) { SQLServerException.makeFromDriverError(con, stmtParent, e.toString(), null, false); - } - finally { + } finally { if (null != stmt) stmt.close(); } @@ -697,8 +679,7 @@ public T unwrap(Class iface) throws SQLException { T t; try { t = iface.cast(this); - } - catch (ClassCastException e) { + } catch (ClassCastException e) { throw new SQLServerException(e.getMessage(), e); } return t; @@ -709,15 +690,14 @@ private void verifyParameterPosition(int param) throws SQLServerException { try { if (((SQLServerPreparedStatement) stmtParent).bReturnValueSyntax && isTVP) { bFound = rsProcedureMeta.absolute(param); + } else { + bFound = rsProcedureMeta.absolute(param + 1); // Note row 1 is the 'return value' meta data } - else { - bFound = rsProcedureMeta.absolute(param + 1); // Note row 1 is the 'return value' meta data - } - } - catch (SQLException e) { + } catch (SQLException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_metaDataErrorForParameter")); Object[] msgArgs = {param}; - SQLServerException.makeFromDriverError(con, stmtParent, form.format(msgArgs) + " " + e.toString(), null, false); + SQLServerException.makeFromDriverError(con, stmtParent, form.format(msgArgs) + " " + e.toString(), null, + false); } if (!bFound) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidParameterNumber")); @@ -728,7 +708,8 @@ private void verifyParameterPosition(int param) throws SQLServerException { private void checkParam(int n) throws SQLServerException { if (!queryMetaMap.containsKey(n)) { - SQLServerException.makeFromDriverError(con, stmtParent, SQLServerException.getErrString("R_noMetadata"), null, false); + SQLServerException.makeFromDriverError(con, stmtParent, SQLServerException.getErrString("R_noMetadata"), + null, false); } } @@ -740,14 +721,12 @@ public String getParameterClassName(int param) throws SQLServerException { // PreparedStatement. checkParam(param); return queryMetaMap.get(param).parameterClassName; - } - else { + } else { verifyParameterPosition(param); JDBCType jdbcType = JDBCType.of(rsProcedureMeta.getShort("DATA_TYPE")); return jdbcType.className(); } - } - catch (SQLException e) { + } catch (SQLException e) { SQLServerException.makeFromDriverError(con, stmtParent, e.toString(), null, false); return null; } @@ -760,16 +739,14 @@ public int getParameterCount() throws SQLServerException { if (rsProcedureMeta == null) { // PreparedStatement return queryMetaMap.size(); - } - else { + } else { rsProcedureMeta.last(); int nCount = rsProcedureMeta.getRow() - 1; if (nCount < 0) nCount = 0; return nCount; } - } - catch (SQLException e) { + } catch (SQLException e) { SQLServerException.makeFromDriverError(con, stmtParent, e.toString(), null, false); return 0; } @@ -783,8 +760,7 @@ public int getParameterMode(int param) throws SQLServerException { checkParam(param); // if it is not a stored proc, the param can only be input. return parameterModeIn; - } - else { + } else { verifyParameterPosition(param); int n = rsProcedureMeta.getInt("COLUMN_TYPE"); switch (n) { @@ -796,8 +772,7 @@ public int getParameterMode(int param) throws SQLServerException { return parameterModeUnknown; } } - } - catch (SQLException e) { + } catch (SQLException e) { SQLServerException.makeFromDriverError(con, stmtParent, e.toString(), null, false); return parameterModeUnknown; } @@ -813,8 +788,7 @@ public int getParameterType(int param) throws SQLServerException { // PreparedStatement. checkParam(param); parameterType = queryMetaMap.get(param).parameterType; - } - else { + } else { verifyParameterPosition(param); parameterType = rsProcedureMeta.getShort("DATA_TYPE"); } @@ -834,8 +808,7 @@ public int getParameterType(int param) throws SQLServerException { } return parameterType; - } - catch (SQLException e) { + } catch (SQLException e) { SQLServerException.makeFromDriverError(con, stmtParent, e.toString(), null, false); return 0; } @@ -849,13 +822,11 @@ public String getParameterTypeName(int param) throws SQLServerException { // PreparedStatement. checkParam(param); return queryMetaMap.get(param).parameterTypeName; - } - else { + } else { verifyParameterPosition(param); return rsProcedureMeta.getString("TYPE_NAME"); } - } - catch (SQLException e) { + } catch (SQLException e) { SQLServerException.makeFromDriverError(con, stmtParent, e.toString(), null, false); return null; } @@ -869,14 +840,12 @@ public int getPrecision(int param) throws SQLServerException { // PreparedStatement. checkParam(param); return queryMetaMap.get(param).precision; - } - else { + } else { verifyParameterPosition(param); int nPrec = rsProcedureMeta.getInt("PRECISION"); return nPrec; } - } - catch (SQLException e) { + } catch (SQLException e) { SQLServerException.makeFromDriverError(con, stmtParent, e.toString(), null, false); return 0; } @@ -890,14 +859,12 @@ public int getScale(int param) throws SQLServerException { // PreparedStatement. checkParam(param); return queryMetaMap.get(param).scale; - } - else { + } else { verifyParameterPosition(param); int nScale = rsProcedureMeta.getInt("SCALE"); return nScale; } - } - catch (SQLException e) { + } catch (SQLException e) { SQLServerException.makeFromDriverError(con, stmtParent, e.toString(), null, false); return 0; } @@ -911,8 +878,7 @@ public int isNullable(int param) throws SQLServerException { // PreparedStatement. checkParam(param); return queryMetaMap.get(param).isNullable; - } - else { + } else { verifyParameterPosition(param); int nNull = rsProcedureMeta.getInt("NULLABLE"); if (nNull == 1) @@ -921,20 +887,19 @@ public int isNullable(int param) throws SQLServerException { return parameterNoNulls; return parameterNullableUnknown; } - } - catch (SQLException e) { + } catch (SQLException e) { SQLServerException.makeFromDriverError(con, stmtParent, e.toString(), null, false); return parameterNoNulls; } } /** - * Verify a supplied parameter index is valid + * Returns if a supplied parameter index is valid. * * @param param - * the param index + * the param index * @throws SQLServerException - * when an error occurs + * when an error occurs * @return boolean */ @Override @@ -945,13 +910,11 @@ public boolean isSigned(int param) throws SQLServerException { // PreparedStatement. checkParam(param); return queryMetaMap.get(param).isSigned; - } - else { + } else { verifyParameterPosition(param); return JDBCType.of(rsProcedureMeta.getShort("DATA_TYPE")).isSigned(); } - } - catch (SQLException e) { + } catch (SQLException e) { SQLServerException.makeFromDriverError(con, stmtParent, e.toString(), null, false); return false; } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPooledConnection.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPooledConnection.java index f17368e6f..91b8a5144 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPooledConnection.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPooledConnection.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -19,9 +16,10 @@ import javax.sql.PooledConnection; import javax.sql.StatementEventListener; + /** - * SQLServerPooledConnection represents a database physical connection in a connection pool. If provides methods for the connection pool manager to - * manage the connection pool. Applications typically do not instantiate these connections directly. + * Represents a physical database connection in a connection pool. If provides methods for the connection pool manager + * to manage the connection pool. Applications typically do not instantiate these connections directly. */ public class SQLServerPooledConnection implements PooledConnection { @@ -31,13 +29,12 @@ public class SQLServerPooledConnection implements PooledConnection { private SQLServerConnectionPoolProxy lastProxyConnection; private String factoryUser, factoryPassword; private java.util.logging.Logger pcLogger; - static private final AtomicInteger basePooledConnectionID = new AtomicInteger(0); // Unique id generator for each PooledConnection instance - // (used for logging). + static private final AtomicInteger basePooledConnectionID = new AtomicInteger(0); // Unique id generator for each + // PooledConnection instance + // (used for logging). private final String traceID; - SQLServerPooledConnection(SQLServerDataSource ds, - String user, - String password) throws SQLException { + SQLServerPooledConnection(SQLServerDataSource ds, String user, String password) throws SQLException { listeners = new Vector<>(); // Piggyback SQLServerDataSource logger for now. pcLogger = SQLServerDataSource.dsLogger; @@ -59,7 +56,7 @@ public class SQLServerPooledConnection implements PooledConnection { } /** - * This is a helper function to provide an ID string suitable for tracing. + * Provides a helper function to provide an ID string suitable for tracing. * * @return traceID String */ @@ -74,10 +71,10 @@ private SQLServerConnection createNewConnection() throws SQLException { } /** - * Creates an object handle for the physical connection that this PooledConnection object represents. + * Returns an object handle for the physical connection that this PooledConnection object represents. * * @throws SQLException - * when an error occurs + * when an error occurs * @return a Connection object that is a handle to this PooledConnection object */ @Override @@ -87,7 +84,8 @@ public Connection getConnection() throws SQLException { synchronized (this) { // If physical connection is closed, throw exception per spec, this PooledConnection is dead. if (physicalConnection == null) { - SQLServerException.makeFromDriverError(null, this, SQLServerException.getErrString("R_physicalConnectionIsClosed"), "", true); + SQLServerException.makeFromDriverError(null, this, + SQLServerException.getErrString("R_physicalConnectionIsClosed"), "", true); } // Check with security manager to insure caller has rights to connect. @@ -108,7 +106,8 @@ public Connection getConnection() throws SQLException { // if there was a last proxy connection send reset physicalConnection.resetPooledConnection(); if (pcLogger.isLoggable(Level.FINE) && !lastProxyConnection.isClosed()) - pcLogger.fine(toString() + "proxy " + lastProxyConnection.toString() + " is not closed before getting the connection."); + pcLogger.fine(toString() + "proxy " + lastProxyConnection.toString() + + " is not closed before getting the connection."); // use internal close so there wont be an event due to us closing the connection, if not closed already. lastProxyConnection.internalClose(); } @@ -121,11 +120,11 @@ public Connection getConnection() throws SQLException { } } - // Notify any interested parties (e.g. pooling managers) of a ConnectionEvent activity - // on the connection. Calling notifyEvent with null event will place the - // connection back in the pool. Calling notifyEvent with a non-null event is - // used to notify the pooling manager that the connection is bad and should be removed - // from the pool. + /** + * Notifies any interested parties (e.g. pooling managers) of a ConnectionEvent activity on the connection. Calling + * notifyEvent with null event will place the connection back in the pool. Calling notifyEvent with a non-null event + * is used to notify the pooling manager that the connection is bad and should be removed from the pool. + */ void notifyEvent(SQLServerException e) { if (pcLogger.isLoggable(Level.FINER)) pcLogger.finer(toString() + " Exception:" + e + safeCID()); @@ -153,8 +152,7 @@ void notifyEvent(SQLServerException e) { if (pcLogger.isLoggable(Level.FINER)) pcLogger.finer(toString() + " notifyEvent:connectionClosed " + safeCID()); listener.connectionClosed(ev); - } - else { + } else { if (pcLogger.isLoggable(Level.FINER)) pcLogger.finer(toString() + " notifyEvent:connectionErrorOccurred " + safeCID()); listener.connectionErrorOccurred(ev); diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement.java index 063dabe39..34b42e50a 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -32,23 +29,23 @@ import java.util.Vector; import java.util.logging.Level; +import com.microsoft.sqlserver.jdbc.SQLServerConnection.CityHash128Key; import com.microsoft.sqlserver.jdbc.SQLServerConnection.PreparedStatementHandle; -import com.microsoft.sqlserver.jdbc.SQLServerConnection.Sha1HashKey; + /** - * SQLServerPreparedStatement provides JDBC prepared statement functionality. SQLServerPreparedStatement provides methods for the user to supply - * parameters as any native Java type and many Java object types. + * Provides an implementation of java.sql.PreparedStatement interface that assists in preparing Statements for SQL + * Server. *

- * SQLServerPreparedStatement prepares a statement using SQL Server's sp_prepexec and re-uses the returned statement handle for each subsequent - * execution of the statement (typically using different parameters provided by the user) + * SQLServerPreparedStatement prepares a statement using SQL Server's sp_prepexec and re-uses the returned statement + * handle for each subsequent execution of the statement (typically using different parameters provided by the user) *

- * SQLServerPreparedStatement supports batching whereby a set of prepared statements are executed in a single database round trip to improve runtime - * performance. + * SQLServerPreparedStatement supports batching whereby a set of prepared statements are executed in a single database + * round trip to improve runtime performance. *

- * The API javadoc for JDBC API methods that this class implements are not repeated here. Please see Sun's JDBC API interfaces javadoc for those - * details. + * The API javadoc for JDBC API methods that this class implements are not repeated here. Please see Sun's JDBC API + * interfaces javadoc for those details. */ - public class SQLServerPreparedStatement extends SQLServerStatement implements ISQLServerPreparedStatement { /** Flag to indicate that it is an internal query to retrieve encryption metadata. */ boolean isInternalEncryptionQuery = false; @@ -65,6 +62,9 @@ public class SQLServerPreparedStatement extends SQLServerStatement implements IS /** Processed SQL statement text, may not be same as what user initially passed. */ final String userSQL; + /** Parameter positions in processed SQL statement text. */ + final int[] userSQLParamPositions; + /** SQL statement with expanded parameter tokens */ private String preparedSQL; @@ -75,11 +75,12 @@ public class SQLServerPreparedStatement extends SQLServerStatement implements IS private PreparedStatementHandle cachedPreparedStatementHandle; /** Hash of user supplied SQL statement used for various cache lookups */ - private Sha1HashKey sqlTextCacheKey; + private CityHash128Key sqlTextCacheKey; /** - * Array with parameter names generated in buildParamTypeDefinitions For mapping encryption information to parameters, as the second result set - * returned by sp_describe_parameter_encryption doesn't depend on order of input parameter + * Array with parameter names generated in buildParamTypeDefinitions For mapping encryption information to + * parameters, as the second result set returned by sp_describe_parameter_encryption doesn't depend on order of + * input parameter **/ private ArrayList parameterNames; @@ -89,9 +90,9 @@ public class SQLServerPreparedStatement extends SQLServerStatement implements IS /** * The number of OUT parameters to skip in the response to get to the first app-declared OUT parameter. * - * When executing prepared and callable statements and/or statements that produce cursored results, the first OUT parameters returned by the - * server contain the internal values like the prepared statement handle and the cursor ID and row count. This value indicates how many of those - * internal OUT parameters were in the response. + * When executing prepared and callable statements and/or statements that produce cursored results, the first OUT + * parameters returned by the server contain the internal values like the prepared statement handle and the cursor + * ID and row count. This value indicates how many of those internal OUT parameters were in the response. */ int outParamIndexAdjustment; @@ -107,30 +108,33 @@ public class SQLServerPreparedStatement extends SQLServerStatement implements IS private void setPreparedStatementHandle(int handle) { this.prepStmtHandle = handle; } - + /** * boolean value for deciding if the driver should use bulk copy API for batch inserts */ private boolean useBulkCopyForBatchInsert; - - /** Gets the prepared statement's useBulkCopyForBatchInsert value. + + /** + * Returns the prepared statement's useBulkCopyForBatchInsert value. * - * @return - * Per the description. - * @throws SQLServerException when an error occurs - */ + * @return Per the description. + * @throws SQLServerException + * when an error occurs + */ @SuppressWarnings("unused") private boolean getUseBulkCopyForBatchInsert() throws SQLServerException { checkClosed(); return useBulkCopyForBatchInsert; } - - /** Sets the prepared statement's useBulkCopyForBatchInsert value. + + /** + * Sets the prepared statement's useBulkCopyForBatchInsert value. * * @param useBulkCopyForBatchInsert - * the boolean value - * @throws SQLServerException when an error occurs - */ + * the boolean value + * @throws SQLServerException + * when an error occurs + */ @SuppressWarnings("unused") private void setUseBulkCopyForBatchInsert(boolean useBulkCopyForBatchInsert) throws SQLServerException { checkClosed(); @@ -176,32 +180,29 @@ private boolean resetPrepStmtHandle(boolean discardCurrentCacheItem) { private boolean encryptionMetadataIsRetrieved = false; private String localUserSQL; - + // Internal function used in tracing String getClassNameInternal() { return "SQLServerPreparedStatement"; } /** - * Create a new prepaed statement. + * Constructs a SQLServerPreparedStatement. * * @param conn - * the connection + * the connection * @param sql - * the user's sql + * the user's sql * @param nRSType - * the result set type + * the result set type * @param nRSConcur - * the result set concurrency + * the result set concurrency * @param stmtColEncSetting - * the statement column encryption setting + * the statement column encryption setting * @throws SQLServerException - * when an error occurs + * when an error occurs */ - SQLServerPreparedStatement(SQLServerConnection conn, - String sql, - int nRSType, - int nRSConcur, + SQLServerPreparedStatement(SQLServerConnection conn, String sql, int nRSType, int nRSConcur, SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException { super(conn, nRSType, nRSConcur, stmtColEncSetting); @@ -214,7 +215,7 @@ String getClassNameInternal() { stmtPoolable = true; // Create a cache key for this statement. - sqlTextCacheKey = new Sha1HashKey(sql); + sqlTextCacheKey = new CityHash128Key(sql); // Parse or fetch SQL metadata from cache. ParsedSQLCacheItem parsedSQL = getCachedParsedSQL(sqlTextCacheKey); @@ -222,8 +223,7 @@ String getClassNameInternal() { if (null != connection && connection.isStatementPoolingEnabled()) { isExecutedAtLeastOnce = true; } - } - else { + } else { parsedSQL = parseAndCacheSQL(sqlTextCacheKey, sql); } @@ -231,12 +231,13 @@ String getClassNameInternal() { procedureName = parsedSQL.procedureName; bReturnValueSyntax = parsedSQL.bReturnValueSyntax; userSQL = parsedSQL.processedSQL; - initParams(parsedSQL.parameterCount); + userSQLParamPositions = parsedSQL.parameterPositions; + initParams(userSQLParamPositions.length); useBulkCopyForBatchInsert = conn.getUseBulkCopyForBatchInsert(); } /** - * Close the prepared statement's prepared handle. + * Closes the prepared statement's prepared handle. */ private void closePreparedHandle() { if (!hasPreparedStatementHandle()) @@ -247,9 +248,9 @@ private void closePreparedHandle() { // on the server anyway. if (connection.isSessionUnAvailable()) { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.finer(this + ": Not closing PreparedHandle:" + prepStmtHandle + "; connection is already closed."); - } - else { + loggerExternal.finer( + this + ": Not closing PreparedHandle:" + prepStmtHandle + "; connection is already closed."); + } else { isExecutedAtLeastOnce = false; final int handleToClose = prepStmtHandle; @@ -257,11 +258,12 @@ private void closePreparedHandle() { if (resetPrepStmtHandle(false)) { connection.returnCachedPreparedStatementHandle(cachedPreparedStatementHandle); } - // If no reference to a statement pool cache item is found handle unprepare actions through batching @ connection level. + // If no reference to a statement pool cache item is found handle unprepare actions through batching @ + // connection level. else if (connection.isPreparedStatementUnprepareBatchingEnabled()) { - connection.enqueueUnprepareStatementHandle(connection.new PreparedStatementHandle(null, handleToClose, executedSqlDirectly, true)); - } - else { + connection.enqueueUnprepareStatementHandle( + connection.new PreparedStatementHandle(null, handleToClose, executedSqlDirectly, true)); + } else { // Non batched behavior (same as pre batch clean-up implementation) if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.finer(this + ": Closing PreparedHandle:" + handleToClose); @@ -274,9 +276,10 @@ final class PreparedHandleClose extends UninterruptableTDSCommand { final boolean doExecute() throws SQLServerException { TDSWriter tdsWriter = startRequest(TDS.PKT_RPC); tdsWriter.writeShort((short) 0xFFFF); // procedure name length -> use ProcIDs - tdsWriter.writeShort(executedSqlDirectly ? TDS.PROCID_SP_UNPREPARE : TDS.PROCID_SP_CURSORUNPREPARE); - tdsWriter.writeByte((byte) 0); // RPC procedure option 1 - tdsWriter.writeByte((byte) 0); // RPC procedure option 2 + tdsWriter.writeShort( + executedSqlDirectly ? TDS.PROCID_SP_UNPREPARE : TDS.PROCID_SP_CURSORUNPREPARE); + tdsWriter.writeByte((byte) 0); // RPC procedure option 1 + tdsWriter.writeByte((byte) 0); // RPC procedure option 2 tdsWriter.writeRPCInt(null, handleToClose, false); TDSParser.parse(startResponse(), getLogContext()); return true; @@ -286,10 +289,10 @@ final boolean doExecute() throws SQLServerException { // Try to close the server cursor. Any failure is caught, logged, and ignored. try { executeCommand(new PreparedHandleClose()); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.log(Level.FINER, this + ": Error (ignored) closing PreparedHandle:" + handleToClose, e); + loggerExternal.log(Level.FINER, + this + ": Error (ignored) closing PreparedHandle:" + handleToClose, e); } if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) @@ -304,9 +307,10 @@ final boolean doExecute() throws SQLServerException { /** * Closes this prepared statement. * - * Note that the public Statement.close() method performs all of the cleanup work through this internal method which cannot throw any exceptions. - * This is done deliberately to ensure that ALL of the object's client-side and server-side state is cleaned up as best as possible, even under - * conditions which would normally result in exceptions being thrown. + * Note that the public Statement.close() method performs all of the cleanup work through this internal method which + * cannot throw any exceptions. This is done deliberately to ensure that ALL of the object's client-side and + * server-side state is cleaned up as best as possible, even under conditions which would normally result in + * exceptions being thrown. */ final void closeInternal() { super.closeInternal(); @@ -318,12 +322,11 @@ final void closeInternal() { try { if (null != internalStmt) internalStmt.close(); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.finer("Ignored error closing internal statement: " + e.getErrorCode() + " " + e.getMessage()); - } - finally { + loggerExternal + .finer("Ignored error closing internal statement: " + e.getErrorCode() + " " + e.getMessage()); + } finally { internalStmt = null; } @@ -332,10 +335,10 @@ final void closeInternal() { } /** - * Intialize the statement parameters. + * Initializes the statement parameters. * * @param nParams - * Number of parameters to Intialize. + * Number of parameters to initialize. */ final void initParams(int nParams) { inOutParam = new Parameter[nParams]; @@ -359,11 +362,10 @@ public final void clearParameters() throws SQLServerException { } /** - * Determines whether the statement needs to be reprepared based on a change in any of the type definitions of any of the parameters due to - * changes in scale, length, etc., and, if so, sets the new type definition string. + * Determines whether the statement needs to be reprepared based on a change in any of the type definitions of any + * of the parameters due to changes in scale, length, etc., and, if so, sets the new type definition string. */ - private boolean buildPreparedStrings(Parameter[] params, - boolean renewDefinition) throws SQLServerException { + private boolean buildPreparedStrings(Parameter[] params, boolean renewDefinition) throws SQLServerException { String newTypeDefinitions = buildParamTypeDefinitions(params, renewDefinition); if (null != preparedTypeDefinitions && newTypeDefinitions.equalsIgnoreCase(preparedTypeDefinitions)) return false; @@ -371,7 +373,7 @@ private boolean buildPreparedStrings(Parameter[] params, preparedTypeDefinitions = newTypeDefinitions; /* Replace the parameter marker '?' with the param numbers @p1, @p2 etc */ - preparedSQL = connection.replaceParameterMarkers(userSQL, params, bReturnValueSyntax); + preparedSQL = connection.replaceParameterMarkers(userSQL, userSQLParamPositions, params, bReturnValueSyntax); if (bRequestedGeneratedKeys) preparedSQL = preparedSQL + identityQuery; @@ -379,18 +381,17 @@ private boolean buildPreparedStrings(Parameter[] params, } /** - * Build the parameter type definitons for a JDBC prepared statement that will be used to prepare the statement. + * Builds the parameter type definitons for a JDBC prepared statement that will be used to prepare the statement. * * @param params - * the statement parameters + * the statement parameters * @param renewDefinition - * True if renewing parameter definition, False otherwise + * True if renewing parameter definition, False otherwise * @throws SQLServerException - * when an error occurs. + * when an error occurs. * @return the required data type defintions. */ - private String buildParamTypeDefinitions(Parameter[] params, - boolean renewDefinition) throws SQLServerException { + private String buildParamTypeDefinitions(Parameter[] params, boolean renewDefinition) throws SQLServerException { StringBuilder sb = new StringBuilder(); int nCols = params.length; char cParamName[] = new char[10]; @@ -436,7 +437,7 @@ public java.sql.ResultSet executeQuery() throws SQLServerException, SQLTimeoutEx } /** - * Execute a query without cursoring for metadata. + * Executes a query without cursoring for metadata. * * @throws SQLServerException * @return ResultSet @@ -461,7 +462,8 @@ public int executeUpdate() throws SQLServerException, SQLTimeoutException { // this shouldn't happen, caller probably meant to call executeLargeUpdate if (updateCount < Integer.MIN_VALUE || updateCount > Integer.MAX_VALUE) - SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_updateCountOutofRange"), null, true); + SQLServerException.makeFromDriverError(connection, this, + SQLServerException.getErrString("R_updateCountOutofRange"), null, true); loggerExternal.exiting(getClassNameLogging(), "executeUpdate", updateCount); @@ -496,8 +498,7 @@ public boolean execute() throws SQLServerException, SQLTimeoutException { private final class PrepStmtExecCmd extends TDSCommand { private final SQLServerPreparedStatement stmt; - PrepStmtExecCmd(SQLServerPreparedStatement stmt, - int executeMethod) { + PrepStmtExecCmd(SQLServerPreparedStatement stmt, int executeMethod) { super(stmt.toString() + " executeXXX", queryTimeout, cancelQueryTimeoutSeconds); this.stmt = stmt; stmt.executeMethod = executeMethod; @@ -539,7 +540,8 @@ final void doExecutePreparedStatement(PrepStmtExecCmd command) throws SQLServerE hasNewTypeDefinitions = buildPreparedStrings(inOutParam, false); } - if ((Util.shouldHonorAEForParameters(stmtColumnEncriptionSetting, connection)) && (0 < inOutParam.length) && !isInternalEncryptionQuery) { + if ((Util.shouldHonorAEForParameters(stmtColumnEncriptionSetting, connection)) && (0 < inOutParam.length) + && !isInternalEncryptionQuery) { // retrieve paramater encryption metadata if they are not retrieved yet if (!encryptionMetadataIsRetrieved) { @@ -551,7 +553,8 @@ final void doExecutePreparedStatement(PrepStmtExecCmd command) throws SQLServerE setMaxRowsAndMaxFieldSize(); } - // fix an issue when inserting unicode into non-encrypted nchar column using setString() and AE is on on Connection + // fix an issue when inserting unicode into non-encrypted nchar column using setString() and AE is on on + // Connection hasNewTypeDefinitions = buildPreparedStrings(inOutParam, true); } @@ -573,8 +576,7 @@ final void doExecutePreparedStatement(PrepStmtExecCmd command) throws SQLServerE ensureExecuteResultsReader(command.startResponse(getIsResponseBufferingAdaptive())); startResults(); getNextResult(); - } - catch (SQLException e) { + } catch (SQLException e) { if (retryBasedOnFailedReuseOfCachedHandle(e, attempt, needsPrepare, false)) continue; else @@ -584,32 +586,36 @@ final void doExecutePreparedStatement(PrepStmtExecCmd command) throws SQLServerE } if (EXECUTE_QUERY == executeMethod && null == resultSet) { - SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_noResultset"), null, true); - } - else if (EXECUTE_UPDATE == executeMethod && null != resultSet) { - SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_resultsetGeneratedForUpdate"), null, false); + SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_noResultset"), + null, true); + } else if (EXECUTE_UPDATE == executeMethod && null != resultSet) { + SQLServerException.makeFromDriverError(connection, this, + SQLServerException.getErrString("R_resultsetGeneratedForUpdate"), null, false); } } - /** Should the execution be retried because the re-used cached handle could not be re-used due to server side state changes? */ - private boolean retryBasedOnFailedReuseOfCachedHandle(SQLException e, - int attempt, - boolean needsPrepare, + /** + * Returns if the execution should be retried because the re-used cached handle could not be re-used due to server + * side state changes. + */ + private boolean retryBasedOnFailedReuseOfCachedHandle(SQLException e, int attempt, boolean needsPrepare, boolean isBatch) { // Only retry based on these error codes and if statementPooling is enabled: - // 586: The prepared statement handle %d is not valid in this context. Please verify that current database, user default schema, and + // 586: The prepared statement handle %d is not valid in this context. Please verify that current database, user + // default schema, and // ANSI_NULLS and QUOTED_IDENTIFIER set options are not changed since the handle is prepared. // 8179: Could not find prepared statement with handle %d. if (needsPrepare && !isBatch) return false; - return 1 == attempt && (586 == e.getErrorCode() || 8179 == e.getErrorCode()) && connection.isStatementPoolingEnabled(); + return 1 == attempt && (586 == e.getErrorCode() || 8179 == e.getErrorCode()) + && connection.isStatementPoolingEnabled(); } /** - * Consume the OUT parameter for the statement object itself. + * Consumes the OUT parameter for the statement object itself. * - * When a prepared statement handle is expected as the first OUT parameter from PreparedStatement or CallableStatement execution, then it gets - * consumed here. + * When a prepared statement handle is expected as the first OUT parameter from PreparedStatement or + * CallableStatement execution, then it gets consumed here. */ boolean consumeExecOutParam(TDSReader tdsReader) throws SQLServerException { final class PrepStmtExecOutParamHandler extends StmtExecOutParamHandler { @@ -623,7 +629,8 @@ boolean onRetValue(TDSReader tdsReader) throws SQLServerException { // If a prepared statement handle is expected then consume it // and continue processing. expectPrepStmtHandle = false; - Parameter param = new Parameter(Util.shouldHonorAEForParameters(stmtColumnEncriptionSetting, connection)); + Parameter param = new Parameter( + Util.shouldHonorAEForParameters(stmtColumnEncriptionSetting, connection)); param.skipRetValStatus(tdsReader); setPreparedStatementHandle(param.getInt(tdsReader)); @@ -631,7 +638,8 @@ boolean onRetValue(TDSReader tdsReader) throws SQLServerException { // Cache the reference to the newly created handle, NOT for cursorable handles. if (null == cachedPreparedStatementHandle && !isCursorable(executeMethod)) { cachedPreparedStatementHandle = connection.registerCachedPreparedStatementHandle( - new Sha1HashKey(preparedSQL, preparedTypeDefinitions), prepStmtHandle, executedSqlDirectly); + new CityHash128Key(preparedSQL, preparedTypeDefinitions), prepStmtHandle, + executedSqlDirectly); } param.skipValue(tdsReader, true); @@ -651,10 +659,9 @@ boolean onRetValue(TDSReader tdsReader) throws SQLServerException { } /** - * Send the statement parameters by RPC + * Sends the statement parameters by RPC. */ - void sendParamsByRPC(TDSWriter tdsWriter, - Parameter[] params) throws SQLServerException { + void sendParamsByRPC(TDSWriter tdsWriter, Parameter[] params) throws SQLServerException { char cParamName[]; for (int index = 0; index < params.length; index++) { if (JDBCType.TVP == params[index].getJdbcType()) { @@ -669,8 +676,8 @@ void sendParamsByRPC(TDSWriter tdsWriter, private void buildServerCursorPrepExecParams(TDSWriter tdsWriter) throws SQLServerException { if (getStatementLogger().isLoggable(java.util.logging.Level.FINE)) - getStatementLogger() - .fine(toString() + ": calling sp_cursorprepexec: PreparedHandle:" + getPreparedStatementHandle() + ", SQL:" + preparedSQL); + getStatementLogger().fine(toString() + ": calling sp_cursorprepexec: PreparedHandle:" + + getPreparedStatementHandle() + ", SQL:" + preparedSQL); expectPrepStmtHandle = true; executedSqlDirectly = false; @@ -679,8 +686,8 @@ private void buildServerCursorPrepExecParams(TDSWriter tdsWriter) throws SQLServ tdsWriter.writeShort((short) 0xFFFF); // procedure name length -> use ProcIDs tdsWriter.writeShort(TDS.PROCID_SP_CURSORPREPEXEC); - tdsWriter.writeByte((byte) 0); // RPC procedure option 1 - tdsWriter.writeByte((byte) 0); // RPC procedure option 2 + tdsWriter.writeByte((byte) 0); // RPC procedure option 1 + tdsWriter.writeByte((byte) 0); // RPC procedure option 2 // // IN (reprepare): Old handle to unprepare before repreparing @@ -700,8 +707,8 @@ private void buildServerCursorPrepExecParams(TDSWriter tdsWriter) throws SQLServ // IN // Note: we must strip out SCROLLOPT_PARAMETERIZED_STMT if we don't // actually have any parameters. - tdsWriter.writeRPCInt(null, getResultSetScrollOpt() & ~((0 == preparedTypeDefinitions.length()) ? TDS.SCROLLOPT_PARAMETERIZED_STMT : 0), - false); + tdsWriter.writeRPCInt(null, getResultSetScrollOpt() + & ~((0 == preparedTypeDefinitions.length()) ? TDS.SCROLLOPT_PARAMETERIZED_STMT : 0), false); // IN tdsWriter.writeRPCInt(null, getResultSetCCOpt(), false); @@ -712,7 +719,8 @@ private void buildServerCursorPrepExecParams(TDSWriter tdsWriter) throws SQLServ private void buildPrepExecParams(TDSWriter tdsWriter) throws SQLServerException { if (getStatementLogger().isLoggable(java.util.logging.Level.FINE)) - getStatementLogger().fine(toString() + ": calling sp_prepexec: PreparedHandle:" + getPreparedStatementHandle() + ", SQL:" + preparedSQL); + getStatementLogger().fine(toString() + ": calling sp_prepexec: PreparedHandle:" + + getPreparedStatementHandle() + ", SQL:" + preparedSQL); expectPrepStmtHandle = true; executedSqlDirectly = true; @@ -721,8 +729,8 @@ private void buildPrepExecParams(TDSWriter tdsWriter) throws SQLServerException tdsWriter.writeShort((short) 0xFFFF); // procedure name length -> use ProcIDs tdsWriter.writeShort(TDS.PROCID_SP_PREPEXEC); - tdsWriter.writeByte((byte) 0); // RPC procedure option 1 - tdsWriter.writeByte((byte) 0); // RPC procedure option 2 + tdsWriter.writeByte((byte) 0); // RPC procedure option 1 + tdsWriter.writeByte((byte) 0); // RPC procedure option 2 // // IN (reprepare): Old handle to unprepare before repreparing @@ -748,8 +756,8 @@ private void buildExecSQLParams(TDSWriter tdsWriter) throws SQLServerException { tdsWriter.writeShort((short) 0xFFFF); // procedure name length -> use ProcIDs tdsWriter.writeShort(TDS.PROCID_SP_EXECUTESQL); - tdsWriter.writeByte((byte) 0); // RPC procedure option 1 - tdsWriter.writeByte((byte) 0); // RPC procedure option 2 + tdsWriter.writeByte((byte) 0); // RPC procedure option 1 + tdsWriter.writeByte((byte) 0); // RPC procedure option 2 // No handle used. resetPrepStmtHandle(false); @@ -764,8 +772,8 @@ private void buildExecSQLParams(TDSWriter tdsWriter) throws SQLServerException { private void buildServerCursorExecParams(TDSWriter tdsWriter) throws SQLServerException { if (getStatementLogger().isLoggable(java.util.logging.Level.FINE)) - getStatementLogger() - .fine(toString() + ": calling sp_cursorexecute: PreparedHandle:" + getPreparedStatementHandle() + ", SQL:" + preparedSQL); + getStatementLogger().fine(toString() + ": calling sp_cursorexecute: PreparedHandle:" + + getPreparedStatementHandle() + ", SQL:" + preparedSQL); expectPrepStmtHandle = false; executedSqlDirectly = false; @@ -774,8 +782,8 @@ private void buildServerCursorExecParams(TDSWriter tdsWriter) throws SQLServerEx tdsWriter.writeShort((short) 0xFFFF); // procedure name length -> use ProcIDs tdsWriter.writeShort(TDS.PROCID_SP_CURSOREXECUTE); - tdsWriter.writeByte((byte) 0); // RPC procedure option 1 - tdsWriter.writeByte((byte) 0); // RPC procedure option 2 */ + tdsWriter.writeByte((byte) 0); // RPC procedure option 1 + tdsWriter.writeByte((byte) 0); // RPC procedure option 2 */ // IN assert hasPreparedStatementHandle(); @@ -796,7 +804,8 @@ private void buildServerCursorExecParams(TDSWriter tdsWriter) throws SQLServerEx private void buildExecParams(TDSWriter tdsWriter) throws SQLServerException { if (getStatementLogger().isLoggable(java.util.logging.Level.FINE)) - getStatementLogger().fine(toString() + ": calling sp_execute: PreparedHandle:" + getPreparedStatementHandle() + ", SQL:" + preparedSQL); + getStatementLogger().fine(toString() + ": calling sp_execute: PreparedHandle:" + + getPreparedStatementHandle() + ", SQL:" + preparedSQL); expectPrepStmtHandle = false; executedSqlDirectly = true; @@ -805,8 +814,8 @@ private void buildExecParams(TDSWriter tdsWriter) throws SQLServerException { tdsWriter.writeShort((short) 0xFFFF); // procedure name length -> use ProcIDs tdsWriter.writeShort(TDS.PROCID_SP_EXECUTE); - tdsWriter.writeByte((byte) 0); // RPC procedure option 1 - tdsWriter.writeByte((byte) 0); // RPC procedure option 2 */ + tdsWriter.writeByte((byte) 0); // RPC procedure option 1 + tdsWriter.writeByte((byte) 0); // RPC procedure option 2 */ // IN assert hasPreparedStatementHandle(); @@ -815,9 +824,9 @@ private void buildExecParams(TDSWriter tdsWriter) throws SQLServerException { private void getParameterEncryptionMetadata(Parameter[] params) throws SQLServerException { /* - * The parameter list is created from the data types provided by the user for the parameters. the data types do not need to be the same as in - * the table definition. Also, when string is sent to an int field, the parameter is defined as nvarchar(). Same for varchar - * datatypes, exact length is used. + * The parameter list is created from the data types provided by the user for the parameters. the data types do + * not need to be the same as in the table definition. Also, when string is sent to an int field, the parameter + * is defined as nvarchar(). Same for varchar datatypes, exact length is used. */ SQLServerResultSet rs = null; SQLServerCallableStatement stmt = null; @@ -826,7 +835,8 @@ private void getParameterEncryptionMetadata(Parameter[] params) throws SQLServer try { if (getStatementLogger().isLoggable(java.util.logging.Level.FINE)) { - getStatementLogger().fine("Calling stored procedure sp_describe_parameter_encryption to get parameter encryption information."); + getStatementLogger().fine( + "Calling stored procedure sp_describe_parameter_encryption to get parameter encryption information."); } stmt = (SQLServerCallableStatement) connection.prepareCall("exec sp_describe_parameter_encryption ?,?"); @@ -834,13 +844,12 @@ private void getParameterEncryptionMetadata(Parameter[] params) throws SQLServer stmt.setNString(1, preparedSQL); stmt.setNString(2, preparedTypeDefinitions); rs = (SQLServerResultSet) stmt.executeQueryInternal(); - } - catch (SQLException e) { + } catch (SQLException e) { if (e instanceof SQLServerException) { throw (SQLServerException) e; - } - else { - throw new SQLServerException(SQLServerException.getErrString("R_UnableRetrieveParameterMetadata"), null, 0, e); + } else { + throw new SQLServerException(SQLServerException.getErrString("R_UnableRetrieveParameterMetadata"), null, + 0, e); } } @@ -858,12 +867,12 @@ private void getParameterEncryptionMetadata(Parameter[] params) throws SQLServer if (!cekList.containsKey(currentOrdinal)) { cekEntry = new CekTableEntry(currentOrdinal); cekList.put(cekEntry.ordinal, cekEntry); - } - else { + } else { cekEntry = cekList.get(currentOrdinal); } cekEntry.add(rs.getBytes(DescribeParameterEncryptionResultSet1.EncryptedKey.value()), - rs.getInt(DescribeParameterEncryptionResultSet1.DbId.value()), rs.getInt(DescribeParameterEncryptionResultSet1.KeyId.value()), + rs.getInt(DescribeParameterEncryptionResultSet1.DbId.value()), + rs.getInt(DescribeParameterEncryptionResultSet1.KeyId.value()), rs.getInt(DescribeParameterEncryptionResultSet1.KeyVersion.value()), rs.getBytes(DescribeParameterEncryptionResultSet1.KeyMdVersion.value()), rs.getString(DescribeParameterEncryptionResultSet1.KeyPath.value()), @@ -873,19 +882,19 @@ private void getParameterEncryptionMetadata(Parameter[] params) throws SQLServer if (getStatementLogger().isLoggable(java.util.logging.Level.FINE)) { getStatementLogger().fine("Matadata of CEKs is retrieved."); } - } - catch (SQLException e) { + } catch (SQLException e) { if (e instanceof SQLServerException) { throw (SQLServerException) e; - } - else { - throw new SQLServerException(SQLServerException.getErrString("R_UnableRetrieveParameterMetadata"), null, 0, e); + } else { + throw new SQLServerException(SQLServerException.getErrString("R_UnableRetrieveParameterMetadata"), null, + 0, e); } } // Process the second resultset. if (!stmt.getMoreResults()) { - throw new SQLServerException(this, SQLServerException.getErrString("R_UnexpectedDescribeParamFormat"), null, 0, false); + throw new SQLServerException(this, SQLServerException.getErrString("R_UnexpectedDescribeParamFormat"), null, + 0, false); } // Parameter count in the result set. @@ -901,7 +910,8 @@ private void getParameterEncryptionMetadata(Parameter[] params) throws SQLServer // cekEntry will be null if none of the parameters are encrypted. if ((null != cekEntry) && (cekList.size() < cekOrdinal)) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidEncryptionKeyOridnal")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_InvalidEncryptionKeyOridnal")); Object[] msgArgs = {cekOrdinal, cekEntry.getSize()}; throw new SQLServerException(this, form.format(msgArgs), null, 0, false); } @@ -909,12 +919,12 @@ private void getParameterEncryptionMetadata(Parameter[] params) throws SQLServer .of((byte) rs.getInt(DescribeParameterEncryptionResultSet2.ColumnEncrytionType.value())); if (SQLServerEncryptionType.PlainText != encType) { params[paramIndex].cryptoMeta = new CryptoMetadata(cekEntry, (short) cekOrdinal, - (byte) rs.getInt(DescribeParameterEncryptionResultSet2.ColumnEncryptionAlgorithm.value()), null, encType.value, + (byte) rs.getInt(DescribeParameterEncryptionResultSet2.ColumnEncryptionAlgorithm.value()), + null, encType.value, (byte) rs.getInt(DescribeParameterEncryptionResultSet2.NormalizationRuleVersion.value())); // Decrypt the symmetric key.(This will also validate and throw if needed). SQLServerSecurityUtility.decryptSymmetricKey(params[paramIndex].cryptoMeta, connection); - } - else { + } else { if (true == params[paramIndex].getForceEncryption()) { MessageFormat form = new MessageFormat( SQLServerException.getErrString("R_ForceEncryptionTrue_HonorAETrue_UnencryptedColumn")); @@ -926,19 +936,19 @@ private void getParameterEncryptionMetadata(Parameter[] params) throws SQLServer if (getStatementLogger().isLoggable(java.util.logging.Level.FINE)) { getStatementLogger().fine("Parameter encryption metadata is set."); } - } - catch (SQLException e) { + } catch (SQLException e) { if (e instanceof SQLServerException) { throw (SQLServerException) e; - } - else { - throw new SQLServerException(SQLServerException.getErrString("R_UnableRetrieveParameterMetadata"), null, 0, e); + } else { + throw new SQLServerException(SQLServerException.getErrString("R_UnableRetrieveParameterMetadata"), null, + 0, e); } } if (paramCount != params.length) { // Encryption metadata wasn't sent by the server. - // We expect the metadata to be sent for all the parameters in the original sp_describe_parameter_encryption. + // We expect the metadata to be sent for all the parameters in the original + // sp_describe_parameter_encryption. // For parameters that don't need encryption, the encryption type is set to plaintext. MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_MissingParamEncryptionMetadata")); Object[] msgArgs = {userSQL}; @@ -954,18 +964,20 @@ private void getParameterEncryptionMetadata(Parameter[] params) throws SQLServer connection.resetCurrentCommand(); } - /** Manage re-using cached handles */ - private boolean reuseCachedHandle(boolean hasNewTypeDefinitions, - boolean discardCurrentCacheItem) { + /** + * Manages re-using cached handles. + */ + private boolean reuseCachedHandle(boolean hasNewTypeDefinitions, boolean discardCurrentCacheItem) { // No re-use of caching for cursorable statements (statements that WILL use sp_cursor*) if (isCursorable(executeMethod)) return false; - // If current cache items needs to be discarded or New type definitions found with existing cached handle reference then deregister cached + // If current cache items needs to be discarded or New type definitions found with existing cached handle + // reference then deregister cached // handle. if (discardCurrentCacheItem || hasNewTypeDefinitions) { - if (null != cachedPreparedStatementHandle - && (discardCurrentCacheItem || (hasPreparedStatementHandle() && prepStmtHandle == cachedPreparedStatementHandle.getHandle()))) { + if (null != cachedPreparedStatementHandle && (discardCurrentCacheItem + || (hasPreparedStatementHandle() && prepStmtHandle == cachedPreparedStatementHandle.getHandle()))) { cachedPreparedStatementHandle.removeReference(); } @@ -978,9 +990,12 @@ private boolean reuseCachedHandle(boolean hasNewTypeDefinitions, // Check for new cache reference. if (null == cachedPreparedStatementHandle) { - PreparedStatementHandle cachedHandle = connection.getCachedPreparedStatementHandle(new Sha1HashKey(preparedSQL, preparedTypeDefinitions)); - // If handle was found then re-use, only if AE is not on and is not a batch query with new type definitions (We shouldn't reuse handle - // if it is batch query and has new type definition, or if it is on, make sure encryptionMetadataIsRetrieved is retrieved. + PreparedStatementHandle cachedHandle = connection + .getCachedPreparedStatementHandle(new CityHash128Key(preparedSQL, preparedTypeDefinitions)); + // If handle was found then re-use, only if AE is not on and is not a batch query with new type definitions + // (We shouldn't reuse handle + // if it is batch query and has new type definition, or if it is on, make sure encryptionMetadataIsRetrieved + // is retrieved. if (null != cachedHandle) { if (!connection.isColumnEncryptionSettingEnabled() || (connection.isColumnEncryptionSettingEnabled() && encryptionMetadataIsRetrieved)) { @@ -995,9 +1010,7 @@ private boolean reuseCachedHandle(boolean hasNewTypeDefinitions, return false; } - private boolean doPrepExec(TDSWriter tdsWriter, - Parameter[] params, - boolean hasNewTypeDefinitions, + private boolean doPrepExec(TDSWriter tdsWriter, Parameter[] params, boolean hasNewTypeDefinitions, boolean hasExistingTypeDefinitions) throws SQLServerException { boolean needsPrepare = (hasNewTypeDefinitions && hasExistingTypeDefinitions) || !hasPreparedStatementHandle(); @@ -1009,8 +1022,7 @@ private boolean doPrepExec(TDSWriter tdsWriter, buildServerCursorPrepExecParams(tdsWriter); else buildServerCursorExecParams(tdsWriter); - } - else { + } else { // Move overhead of needing to do prepare & unprepare to only use cases that need more than one execution. // First execution, use sp_executesql, optimizing for asumption we will not re-use statement. if (needsPrepare && !connection.getEnablePrepareOnFirstPreparedStatementCall() && !isExecutedAtLeastOnce) { @@ -1039,16 +1051,14 @@ public final java.sql.ResultSetMetaData getMetaData() throws SQLServerException // if the result is closed, cant get the metadata from it. if (resultSet != null) resultSet.checkClosed(); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { rsclosed = true; } if (resultSet == null || rsclosed) { SQLServerResultSet emptyResultSet = (SQLServerResultSet) buildExecuteMetaData(); if (null != emptyResultSet) rsmd = emptyResultSet.getMetaData(); - } - else if (resultSet != null) { + } else if (resultSet != null) { rsmd = resultSet.getMetaData(); } loggerExternal.exiting(getClassNameLogging(), "getMetaData", rsmd); @@ -1056,8 +1066,8 @@ else if (resultSet != null) { } /** - * Retreive meta data for the statement before executing it. This is called in cases where the driver needs the meta data prior to executing the - * statement. + * Returns meta data for the statement before executing it. This is called in cases where the driver needs the meta + * data prior to executing the statement. * * @throws SQLServerException * @return the result set containing the meta data @@ -1070,8 +1080,7 @@ private ResultSet buildExecuteMetaData() throws SQLServerException { fmtSQL = replaceMarkerWithNull(fmtSQL); internalStmt = (SQLServerStatement) connection.createStatement(); emptyResultSet = internalStmt.executeQueryInternal("set fmtonly on " + fmtSQL + "\nset fmtonly off"); - } - catch (SQLException sqle) { + } catch (SQLException sqle) { if (false == sqle.getMessage().equals(SQLServerException.getErrString("R_noResultset"))) { // if the error is not no resultset then throw a processings error. MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_processingError")); @@ -1086,13 +1095,13 @@ private ResultSet buildExecuteMetaData() throws SQLServerException { /* -------------- JDBC API Implementation ------------------ */ /** - * Set the parameter value for a statement. + * Sets the parameter value for a statement. * * @param index - * The index of the parameter to set starting at 1. + * The index of the parameter to set starting at 1. * @return A reference the to Parameter object created or referenced. * @exception SQLServerException - * The index specified was outside the number of paramters for the statement. + * The index specified was outside the number of paramters for the statement. */ final Parameter setterGetParam(int index) throws SQLServerException { if (index < 1 || index > inOutParam.length) { @@ -1104,64 +1113,45 @@ final Parameter setterGetParam(int index) throws SQLServerException { return inOutParam[index - 1]; } - final void setValue(int parameterIndex, - JDBCType jdbcType, - Object value, - JavaType javaType, + final void setValue(int parameterIndex, JDBCType jdbcType, Object value, JavaType javaType, String tvpName) throws SQLServerException { - setterGetParam(parameterIndex).setValue(jdbcType, value, javaType, null, null, null, null, connection, false, stmtColumnEncriptionSetting, - parameterIndex, userSQL, tvpName); + setterGetParam(parameterIndex).setValue(jdbcType, value, javaType, null, null, null, null, connection, false, + stmtColumnEncriptionSetting, parameterIndex, userSQL, tvpName); } - final void setValue(int parameterIndex, - JDBCType jdbcType, - Object value, - JavaType javaType, + final void setValue(int parameterIndex, JDBCType jdbcType, Object value, JavaType javaType, boolean forceEncrypt) throws SQLServerException { - setterGetParam(parameterIndex).setValue(jdbcType, value, javaType, null, null, null, null, connection, forceEncrypt, - stmtColumnEncriptionSetting, parameterIndex, userSQL, null); + setterGetParam(parameterIndex).setValue(jdbcType, value, javaType, null, null, null, null, connection, + forceEncrypt, stmtColumnEncriptionSetting, parameterIndex, userSQL, null); } - final void setValue(int parameterIndex, - JDBCType jdbcType, - Object value, - JavaType javaType, - Integer precision, - Integer scale, - boolean forceEncrypt) throws SQLServerException { - setterGetParam(parameterIndex).setValue(jdbcType, value, javaType, null, null, precision, scale, connection, forceEncrypt, - stmtColumnEncriptionSetting, parameterIndex, userSQL, null); + final void setValue(int parameterIndex, JDBCType jdbcType, Object value, JavaType javaType, Integer precision, + Integer scale, boolean forceEncrypt) throws SQLServerException { + setterGetParam(parameterIndex).setValue(jdbcType, value, javaType, null, null, precision, scale, connection, + forceEncrypt, stmtColumnEncriptionSetting, parameterIndex, userSQL, null); } - final void setValue(int parameterIndex, - JDBCType jdbcType, - Object value, - JavaType javaType, - Calendar cal, + final void setValue(int parameterIndex, JDBCType jdbcType, Object value, JavaType javaType, Calendar cal, boolean forceEncrypt) throws SQLServerException { - setterGetParam(parameterIndex).setValue(jdbcType, value, javaType, null, cal, null, null, connection, forceEncrypt, - stmtColumnEncriptionSetting, parameterIndex, userSQL, null); + setterGetParam(parameterIndex).setValue(jdbcType, value, javaType, null, cal, null, null, connection, + forceEncrypt, stmtColumnEncriptionSetting, parameterIndex, userSQL, null); } - final void setStream(int parameterIndex, - StreamType streamType, - Object streamValue, - JavaType javaType, + final void setStream(int parameterIndex, StreamType streamType, Object streamValue, JavaType javaType, long length) throws SQLServerException { - setterGetParam(parameterIndex).setValue(streamType.getJDBCType(), streamValue, javaType, new StreamSetterArgs(streamType, length), null, null, - null, connection, false, stmtColumnEncriptionSetting, parameterIndex, userSQL, null); + setterGetParam(parameterIndex).setValue(streamType.getJDBCType(), streamValue, javaType, + new StreamSetterArgs(streamType, length), null, null, null, connection, false, + stmtColumnEncriptionSetting, parameterIndex, userSQL, null); } - final void setSQLXMLInternal(int parameterIndex, - SQLXML value) throws SQLServerException { + final void setSQLXMLInternal(int parameterIndex, SQLXML value) throws SQLServerException { setterGetParam(parameterIndex).setValue(JDBCType.SQLXML, value, JavaType.SQLXML, - new StreamSetterArgs(StreamType.SQLXML, DataTypes.UNKNOWN_STREAM_LENGTH), null, null, null, connection, false, - stmtColumnEncriptionSetting, parameterIndex, userSQL, null); + new StreamSetterArgs(StreamType.SQLXML, DataTypes.UNKNOWN_STREAM_LENGTH), null, null, null, connection, + false, stmtColumnEncriptionSetting, parameterIndex, userSQL, null); } @Override - public final void setAsciiStream(int parameterIndex, - InputStream x) throws SQLException { + public final void setAsciiStream(int parameterIndex, InputStream x) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setAsciiStream", new Object[] {parameterIndex, x}); checkClosed(); @@ -1170,9 +1160,7 @@ public final void setAsciiStream(int parameterIndex, } @Override - public final void setAsciiStream(int n, - java.io.InputStream x, - int length) throws SQLServerException { + public final void setAsciiStream(int n, java.io.InputStream x, int length) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setAsciiStream", new Object[] {n, x, length}); checkClosed(); @@ -1181,9 +1169,7 @@ public final void setAsciiStream(int n, } @Override - public final void setAsciiStream(int parameterIndex, - InputStream x, - long length) throws SQLException { + public final void setAsciiStream(int parameterIndex, InputStream x, long length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setAsciiStream", new Object[] {parameterIndex, x, length}); checkClosed(); @@ -1192,8 +1178,7 @@ public final void setAsciiStream(int parameterIndex, } @Override - public final void setBigDecimal(int paramterIndex, - BigDecimal x) throws SQLServerException { + public final void setBigDecimal(int paramterIndex, BigDecimal x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setBigDecimal", new Object[] {paramterIndex, x}); checkClosed(); @@ -1202,33 +1187,29 @@ public final void setBigDecimal(int paramterIndex, } @Override - public final void setBigDecimal(int paramterIndex, - BigDecimal x, - int precision, + public final void setBigDecimal(int paramterIndex, BigDecimal x, int precision, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setBigDecimal", new Object[] {paramterIndex, x, precision, scale}); + loggerExternal.entering(getClassNameLogging(), "setBigDecimal", + new Object[] {paramterIndex, x, precision, scale}); checkClosed(); setValue(paramterIndex, JDBCType.DECIMAL, x, JavaType.BIGDECIMAL, precision, scale, false); loggerExternal.exiting(getClassNameLogging(), "setBigDecimal"); } @Override - public final void setBigDecimal(int paramterIndex, - BigDecimal x, - int precision, - int scale, + public final void setBigDecimal(int paramterIndex, BigDecimal x, int precision, int scale, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setBigDecimal", new Object[] {paramterIndex, x, precision, scale, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "setBigDecimal", + new Object[] {paramterIndex, x, precision, scale, forceEncrypt}); checkClosed(); setValue(paramterIndex, JDBCType.DECIMAL, x, JavaType.BIGDECIMAL, precision, scale, forceEncrypt); loggerExternal.exiting(getClassNameLogging(), "setBigDecimal"); } @Override - public final void setMoney(int n, - BigDecimal x) throws SQLServerException { + public final void setMoney(int n, BigDecimal x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setMoney", new Object[] {n, x}); checkClosed(); @@ -1237,9 +1218,7 @@ public final void setMoney(int n, } @Override - public final void setMoney(int n, - BigDecimal x, - boolean forceEncrypt) throws SQLServerException { + public final void setMoney(int n, BigDecimal x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setMoney", new Object[] {n, x, forceEncrypt}); checkClosed(); @@ -1248,8 +1227,7 @@ public final void setMoney(int n, } @Override - public final void setSmallMoney(int n, - BigDecimal x) throws SQLServerException { + public final void setSmallMoney(int n, BigDecimal x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setSmallMoney", new Object[] {n, x}); checkClosed(); @@ -1258,9 +1236,7 @@ public final void setSmallMoney(int n, } @Override - public final void setSmallMoney(int n, - BigDecimal x, - boolean forceEncrypt) throws SQLServerException { + public final void setSmallMoney(int n, BigDecimal x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setSmallMoney", new Object[] {n, x, forceEncrypt}); checkClosed(); @@ -1269,8 +1245,7 @@ public final void setSmallMoney(int n, } @Override - public final void setBinaryStream(int parameterIndex, - InputStream x) throws SQLException { + public final void setBinaryStream(int parameterIndex, InputStream x) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setBinaryStreaml", new Object[] {parameterIndex, x}); checkClosed(); @@ -1279,9 +1254,7 @@ public final void setBinaryStream(int parameterIndex, } @Override - public final void setBinaryStream(int n, - java.io.InputStream x, - int length) throws SQLServerException { + public final void setBinaryStream(int n, java.io.InputStream x, int length) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setBinaryStream", new Object[] {n, x, length}); checkClosed(); @@ -1290,9 +1263,7 @@ public final void setBinaryStream(int n, } @Override - public final void setBinaryStream(int parameterIndex, - InputStream x, - long length) throws SQLException { + public final void setBinaryStream(int parameterIndex, InputStream x, long length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setBinaryStream", new Object[] {parameterIndex, x, length}); checkClosed(); @@ -1301,8 +1272,7 @@ public final void setBinaryStream(int parameterIndex, } @Override - public final void setBoolean(int n, - boolean x) throws SQLServerException { + public final void setBoolean(int n, boolean x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setBoolean", new Object[] {n, x}); checkClosed(); @@ -1311,9 +1281,7 @@ public final void setBoolean(int n, } @Override - public final void setBoolean(int n, - boolean x, - boolean forceEncrypt) throws SQLServerException { + public final void setBoolean(int n, boolean x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setBoolean", new Object[] {n, x, forceEncrypt}); checkClosed(); @@ -1322,8 +1290,7 @@ public final void setBoolean(int n, } @Override - public final void setByte(int n, - byte x) throws SQLServerException { + public final void setByte(int n, byte x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setByte", new Object[] {n, x}); checkClosed(); @@ -1332,9 +1299,7 @@ public final void setByte(int n, } @Override - public final void setByte(int n, - byte x, - boolean forceEncrypt) throws SQLServerException { + public final void setByte(int n, byte x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setByte", new Object[] {n, x, forceEncrypt}); checkClosed(); @@ -1343,8 +1308,7 @@ public final void setByte(int n, } @Override - public final void setBytes(int n, - byte x[]) throws SQLServerException { + public final void setBytes(int n, byte x[]) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setBytes", new Object[] {n, x}); checkClosed(); @@ -1353,9 +1317,7 @@ public final void setBytes(int n, } @Override - public final void setBytes(int n, - byte x[], - boolean forceEncrypt) throws SQLServerException { + public final void setBytes(int n, byte x[], boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setBytes", new Object[] {n, x, forceEncrypt}); checkClosed(); @@ -1364,8 +1326,7 @@ public final void setBytes(int n, } @Override - public final void setUniqueIdentifier(int index, - String guid) throws SQLServerException { + public final void setUniqueIdentifier(int index, String guid) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setUniqueIdentifier", new Object[] {index, guid}); checkClosed(); @@ -1374,19 +1335,17 @@ public final void setUniqueIdentifier(int index, } @Override - public final void setUniqueIdentifier(int index, - String guid, - boolean forceEncrypt) throws SQLServerException { + public final void setUniqueIdentifier(int index, String guid, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setUniqueIdentifier", new Object[] {index, guid, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "setUniqueIdentifier", + new Object[] {index, guid, forceEncrypt}); checkClosed(); setValue(index, JDBCType.GUID, guid, JavaType.STRING, forceEncrypt); loggerExternal.exiting(getClassNameLogging(), "setUniqueIdentifier"); } @Override - public final void setDouble(int n, - double x) throws SQLServerException { + public final void setDouble(int n, double x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setDouble", new Object[] {n, x}); checkClosed(); @@ -1395,9 +1354,7 @@ public final void setDouble(int n, } @Override - public final void setDouble(int n, - double x, - boolean forceEncrypt) throws SQLServerException { + public final void setDouble(int n, double x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setDouble", new Object[] {n, x, forceEncrypt}); checkClosed(); @@ -1406,8 +1363,7 @@ public final void setDouble(int n, } @Override - public final void setFloat(int n, - float x) throws SQLServerException { + public final void setFloat(int n, float x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setFloat", new Object[] {n, x}); checkClosed(); @@ -1416,9 +1372,7 @@ public final void setFloat(int n, } @Override - public final void setFloat(int n, - float x, - boolean forceEncrypt) throws SQLServerException { + public final void setFloat(int n, float x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setFloat", new Object[] {n, x, forceEncrypt}); checkClosed(); @@ -1427,8 +1381,7 @@ public final void setFloat(int n, } @Override - public final void setGeometry(int n, - Geometry x) throws SQLServerException { + public final void setGeometry(int n, Geometry x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setGeometry", new Object[] {n, x}); checkClosed(); @@ -1437,8 +1390,7 @@ public final void setGeometry(int n, } @Override - public final void setGeography(int n, - Geography x) throws SQLServerException { + public final void setGeography(int n, Geography x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setGeography", new Object[] {n, x}); checkClosed(); @@ -1447,8 +1399,7 @@ public final void setGeography(int n, } @Override - public final void setInt(int n, - int value) throws SQLServerException { + public final void setInt(int n, int value) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setInt", new Object[] {n, value}); checkClosed(); @@ -1457,9 +1408,7 @@ public final void setInt(int n, } @Override - public final void setInt(int n, - int value, - boolean forceEncrypt) throws SQLServerException { + public final void setInt(int n, int value, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setInt", new Object[] {n, value, forceEncrypt}); checkClosed(); @@ -1468,8 +1417,7 @@ public final void setInt(int n, } @Override - public final void setLong(int n, - long x) throws SQLServerException { + public final void setLong(int n, long x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setLong", new Object[] {n, x}); checkClosed(); @@ -1478,9 +1426,7 @@ public final void setLong(int n, } @Override - public final void setLong(int n, - long x, - boolean forceEncrypt) throws SQLServerException { + public final void setLong(int n, long x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setLong", new Object[] {n, x, forceEncrypt}); checkClosed(); @@ -1489,8 +1435,7 @@ public final void setLong(int n, } @Override - public final void setNull(int index, - int jdbcType) throws SQLServerException { + public final void setNull(int index, int jdbcType) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setNull", new Object[] {index, jdbcType}); checkClosed(); @@ -1498,9 +1443,7 @@ public final void setNull(int index, loggerExternal.exiting(getClassNameLogging(), "setNull"); } - final void setObjectNoType(int index, - Object obj, - boolean forceEncrypt) throws SQLServerException { + final void setObjectNoType(int index, Object obj, boolean forceEncrypt) throws SQLServerException { // Default to the JDBC type of the parameter, determined by a previous setter call or through registerOutParam. // This avoids repreparing unnecessarily for null values. Parameter param = setterGetParam(index); @@ -1514,14 +1457,14 @@ final void setObjectNoType(int index, targetJDBCType = JDBCType.CHAR; setObject(param, null, JavaType.OBJECT, targetJDBCType, null, null, forceEncrypt, index, null); - } - else { + } else { JavaType javaType = JavaType.of(obj); if (JavaType.TVP == javaType) { - tvpName = getTVPNameIfNull(index, null); // will return null if called from preparedStatement + tvpName = getTVPNameIfNull(index, null); // will return null if called from preparedStatement if ((null == tvpName) && (obj instanceof ResultSet)) { - throw new SQLServerException(SQLServerException.getErrString("R_TVPnotWorkWithSetObjectResultSet"), null); + throw new SQLServerException(SQLServerException.getErrString("R_TVPnotWorkWithSetObjectResultSet"), + null); } } targetJDBCType = javaType.getJDBCType(SSType.UNKNOWN, targetJDBCType); @@ -1538,8 +1481,7 @@ final void setObjectNoType(int index, } @Override - public final void setObject(int index, - Object obj) throws SQLServerException { + public final void setObject(int index, Object obj) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setObject", new Object[] {index, obj}); checkClosed(); @@ -1548,9 +1490,7 @@ public final void setObject(int index, } @Override - public final void setObject(int n, - Object obj, - int jdbcType) throws SQLServerException { + public final void setObject(int n, Object obj, int jdbcType) throws SQLServerException { String tvpName = null; if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setObject", new Object[] {n, obj, jdbcType}); @@ -1562,12 +1502,11 @@ public final void setObject(int n, } @Override - public final void setObject(int parameterIndex, - Object x, - int targetSqlType, + public final void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setObject", new Object[] {parameterIndex, x, targetSqlType, scaleOrLength}); + loggerExternal.entering(getClassNameLogging(), "setObject", + new Object[] {parameterIndex, x, targetSqlType, scaleOrLength}); checkClosed(); // scaleOrLength - for java.sql.Types.DECIMAL, java.sql.Types.NUMERIC or temporal types, @@ -1576,22 +1515,21 @@ public final void setObject(int parameterIndex, // For all other types, this value will be ignored. setObject(setterGetParam(parameterIndex), x, JavaType.of(x), JDBCType.of(targetSqlType), - (java.sql.Types.NUMERIC == targetSqlType || java.sql.Types.DECIMAL == targetSqlType || java.sql.Types.TIMESTAMP == targetSqlType - || java.sql.Types.TIME == targetSqlType || microsoft.sql.Types.DATETIMEOFFSET == targetSqlType - || InputStream.class.isInstance(x) || Reader.class.isInstance(x)) ? scaleOrLength : null, + (java.sql.Types.NUMERIC == targetSqlType || java.sql.Types.DECIMAL == targetSqlType + || java.sql.Types.TIMESTAMP == targetSqlType || java.sql.Types.TIME == targetSqlType + || microsoft.sql.Types.DATETIMEOFFSET == targetSqlType || InputStream.class.isInstance(x) + || Reader.class.isInstance(x)) ? scaleOrLength : null, null, false, parameterIndex, null); loggerExternal.exiting(getClassNameLogging(), "setObject"); } @Override - public final void setObject(int parameterIndex, - Object x, - int targetSqlType, - Integer precision, + public final void setObject(int parameterIndex, Object x, int targetSqlType, Integer precision, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setObject", new Object[] {parameterIndex, x, targetSqlType, precision, scale}); + loggerExternal.entering(getClassNameLogging(), "setObject", + new Object[] {parameterIndex, x, targetSqlType, precision, scale}); checkClosed(); // scale - for java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types, @@ -1599,20 +1537,16 @@ public final void setObject(int parameterIndex, // InputStream and Reader, this is the length of the data in the stream or reader. // For all other types, this value will be ignored. - setObject( - setterGetParam(parameterIndex), x, JavaType.of(x), JDBCType.of(targetSqlType), (java.sql.Types.NUMERIC == targetSqlType - || java.sql.Types.DECIMAL == targetSqlType || InputStream.class.isInstance(x) || Reader.class.isInstance(x)) ? scale : null, + setObject(setterGetParam(parameterIndex), x, JavaType.of(x), JDBCType.of(targetSqlType), + (java.sql.Types.NUMERIC == targetSqlType || java.sql.Types.DECIMAL == targetSqlType + || InputStream.class.isInstance(x) || Reader.class.isInstance(x)) ? scale : null, precision, false, parameterIndex, null); loggerExternal.exiting(getClassNameLogging(), "setObject"); } @Override - public final void setObject(int parameterIndex, - Object x, - int targetSqlType, - Integer precision, - int scale, + public final void setObject(int parameterIndex, Object x, int targetSqlType, Integer precision, int scale, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setObject", @@ -1624,23 +1558,16 @@ public final void setObject(int parameterIndex, // InputStream and Reader, this is the length of the data in the stream or reader. // For all other types, this value will be ignored. - setObject( - setterGetParam(parameterIndex), x, JavaType.of(x), JDBCType.of(targetSqlType), (java.sql.Types.NUMERIC == targetSqlType - || java.sql.Types.DECIMAL == targetSqlType || InputStream.class.isInstance(x) || Reader.class.isInstance(x)) ? scale : null, + setObject(setterGetParam(parameterIndex), x, JavaType.of(x), JDBCType.of(targetSqlType), + (java.sql.Types.NUMERIC == targetSqlType || java.sql.Types.DECIMAL == targetSqlType + || InputStream.class.isInstance(x) || Reader.class.isInstance(x)) ? scale : null, precision, forceEncrypt, parameterIndex, null); loggerExternal.exiting(getClassNameLogging(), "setObject"); } - final void setObject(Parameter param, - Object obj, - JavaType javaType, - JDBCType jdbcType, - Integer scale, - Integer precision, - boolean forceEncrypt, - int parameterIndex, - String tvpName) throws SQLServerException { + final void setObject(Parameter param, Object obj, JavaType javaType, JDBCType jdbcType, Integer scale, + Integer precision, boolean forceEncrypt, int parameterIndex, String tvpName) throws SQLServerException { assert JDBCType.UNKNOWN != jdbcType; // For non-null values, infer the object's JDBC type from its Java type @@ -1661,7 +1588,8 @@ final void setObject(Parameter param, break; case INPUTSTREAM: - streamSetterArgs = new StreamSetterArgs(jdbcType.isTextual() ? StreamType.CHARACTER : StreamType.BINARY, + streamSetterArgs = new StreamSetterArgs( + jdbcType.isTextual() ? StreamType.CHARACTER : StreamType.BINARY, DataTypes.UNKNOWN_STREAM_LENGTH); break; @@ -1674,8 +1602,8 @@ final void setObject(Parameter param, } // typeInfo is set as null - param.setValue(jdbcType, obj, javaType, streamSetterArgs, null, precision, scale, connection, forceEncrypt, stmtColumnEncriptionSetting, - parameterIndex, userSQL, tvpName); + param.setValue(jdbcType, obj, javaType, streamSetterArgs, null, precision, scale, connection, forceEncrypt, + stmtColumnEncriptionSetting, parameterIndex, userSQL, tvpName); } // For null values, use the specified JDBC type directly, with the exception @@ -1687,48 +1615,36 @@ final void setObject(Parameter param, jdbcType = JDBCType.BINARY; // typeInfo is set as null - param.setValue(jdbcType, null, JavaType.OBJECT, null, null, precision, scale, connection, false, stmtColumnEncriptionSetting, - parameterIndex, userSQL, tvpName); + param.setValue(jdbcType, null, JavaType.OBJECT, null, null, precision, scale, connection, false, + stmtColumnEncriptionSetting, parameterIndex, userSQL, tvpName); } } @Override - public final void setObject(int index, - Object obj, - SQLType jdbcType) throws SQLServerException { + public final void setObject(int index, Object obj, SQLType jdbcType) throws SQLServerException { setObject(index, obj, jdbcType.getVendorTypeNumber()); } @Override - public final void setObject(int parameterIndex, - Object x, - SQLType targetSqlType, + public final void setObject(int parameterIndex, Object x, SQLType targetSqlType, int scaleOrLength) throws SQLServerException { setObject(parameterIndex, x, targetSqlType.getVendorTypeNumber(), scaleOrLength); } @Override - public final void setObject(int parameterIndex, - Object x, - SQLType targetSqlType, - Integer precision, + public final void setObject(int parameterIndex, Object x, SQLType targetSqlType, Integer precision, Integer scale) throws SQLServerException { setObject(parameterIndex, x, targetSqlType.getVendorTypeNumber(), precision, scale); } @Override - public final void setObject(int parameterIndex, - Object x, - SQLType targetSqlType, - Integer precision, - Integer scale, + public final void setObject(int parameterIndex, Object x, SQLType targetSqlType, Integer precision, Integer scale, boolean forceEncrypt) throws SQLServerException { setObject(parameterIndex, x, targetSqlType.getVendorTypeNumber(), precision, scale, forceEncrypt); } @Override - public final void setShort(int index, - short x) throws SQLServerException { + public final void setShort(int index, short x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setShort", new Object[] {index, x}); checkClosed(); @@ -1737,9 +1653,7 @@ public final void setShort(int index, } @Override - public final void setShort(int index, - short x, - boolean forceEncrypt) throws SQLServerException { + public final void setShort(int index, short x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setShort", new Object[] {index, x, forceEncrypt}); checkClosed(); @@ -1748,8 +1662,7 @@ public final void setShort(int index, } @Override - public final void setString(int index, - String str) throws SQLServerException { + public final void setString(int index, String str) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setString", new Object[] {index, str}); checkClosed(); @@ -1758,9 +1671,7 @@ public final void setString(int index, } @Override - public final void setString(int index, - String str, - boolean forceEncrypt) throws SQLServerException { + public final void setString(int index, String str, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setString", new Object[] {index, str, forceEncrypt}); checkClosed(); @@ -1769,8 +1680,7 @@ public final void setString(int index, } @Override - public final void setNString(int parameterIndex, - String value) throws SQLException { + public final void setNString(int parameterIndex, String value) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setNString", new Object[] {parameterIndex, value}); checkClosed(); @@ -1779,19 +1689,17 @@ public final void setNString(int parameterIndex, } @Override - public final void setNString(int parameterIndex, - String value, - boolean forceEncrypt) throws SQLServerException { + public final void setNString(int parameterIndex, String value, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setNString", new Object[] {parameterIndex, value, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "setNString", + new Object[] {parameterIndex, value, forceEncrypt}); checkClosed(); setValue(parameterIndex, JDBCType.NVARCHAR, value, JavaType.STRING, forceEncrypt); loggerExternal.exiting(getClassNameLogging(), "setNString"); } @Override - public final void setTime(int n, - java.sql.Time x) throws SQLServerException { + public final void setTime(int n, java.sql.Time x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setTime", new Object[] {n, x}); checkClosed(); @@ -1800,9 +1708,7 @@ public final void setTime(int n, } @Override - public final void setTime(int n, - java.sql.Time x, - int scale) throws SQLServerException { + public final void setTime(int n, java.sql.Time x, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setTime", new Object[] {n, x, scale}); checkClosed(); @@ -1811,10 +1717,7 @@ public final void setTime(int n, } @Override - public final void setTime(int n, - java.sql.Time x, - int scale, - boolean forceEncrypt) throws SQLServerException { + public final void setTime(int n, java.sql.Time x, int scale, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setTime", new Object[] {n, x, scale, forceEncrypt}); checkClosed(); @@ -1823,8 +1726,7 @@ public final void setTime(int n, } @Override - public final void setTimestamp(int n, - java.sql.Timestamp x) throws SQLServerException { + public final void setTimestamp(int n, java.sql.Timestamp x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setTimestamp", new Object[] {n, x}); checkClosed(); @@ -1833,9 +1735,7 @@ public final void setTimestamp(int n, } @Override - public final void setTimestamp(int n, - java.sql.Timestamp x, - int scale) throws SQLServerException { + public final void setTimestamp(int n, java.sql.Timestamp x, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setTimestamp", new Object[] {n, x, scale}); checkClosed(); @@ -1844,9 +1744,7 @@ public final void setTimestamp(int n, } @Override - public final void setTimestamp(int n, - java.sql.Timestamp x, - int scale, + public final void setTimestamp(int n, java.sql.Timestamp x, int scale, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setTimestamp", new Object[] {n, x, scale, forceEncrypt}); @@ -1856,8 +1754,7 @@ public final void setTimestamp(int n, } @Override - public final void setDateTimeOffset(int n, - microsoft.sql.DateTimeOffset x) throws SQLServerException { + public final void setDateTimeOffset(int n, microsoft.sql.DateTimeOffset x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setDateTimeOffset", new Object[] {n, x}); checkClosed(); @@ -1866,9 +1763,7 @@ public final void setDateTimeOffset(int n, } @Override - public final void setDateTimeOffset(int n, - microsoft.sql.DateTimeOffset x, - int scale) throws SQLServerException { + public final void setDateTimeOffset(int n, microsoft.sql.DateTimeOffset x, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setDateTimeOffset", new Object[] {n, x, scale}); checkClosed(); @@ -1877,20 +1772,18 @@ public final void setDateTimeOffset(int n, } @Override - public final void setDateTimeOffset(int n, - microsoft.sql.DateTimeOffset x, - int scale, + public final void setDateTimeOffset(int n, microsoft.sql.DateTimeOffset x, int scale, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setDateTimeOffset", new Object[] {n, x, scale, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "setDateTimeOffset", + new Object[] {n, x, scale, forceEncrypt}); checkClosed(); setValue(n, JDBCType.DATETIMEOFFSET, x, JavaType.DATETIMEOFFSET, null, scale, forceEncrypt); loggerExternal.exiting(getClassNameLogging(), "setDateTimeOffset"); } @Override - public final void setDate(int n, - java.sql.Date x) throws SQLServerException { + public final void setDate(int n, java.sql.Date x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setDate", new Object[] {n, x}); checkClosed(); @@ -1899,8 +1792,7 @@ public final void setDate(int n, } @Override - public final void setDateTime(int n, - java.sql.Timestamp x) throws SQLServerException { + public final void setDateTime(int n, java.sql.Timestamp x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setDateTime", new Object[] {n, x}); checkClosed(); @@ -1909,9 +1801,7 @@ public final void setDateTime(int n, } @Override - public final void setDateTime(int n, - java.sql.Timestamp x, - boolean forceEncrypt) throws SQLServerException { + public final void setDateTime(int n, java.sql.Timestamp x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setDateTime", new Object[] {n, x, forceEncrypt}); checkClosed(); @@ -1920,8 +1810,7 @@ public final void setDateTime(int n, } @Override - public final void setSmallDateTime(int n, - java.sql.Timestamp x) throws SQLServerException { + public final void setSmallDateTime(int n, java.sql.Timestamp x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setSmallDateTime", new Object[] {n, x}); checkClosed(); @@ -1930,9 +1819,7 @@ public final void setSmallDateTime(int n, } @Override - public final void setSmallDateTime(int n, - java.sql.Timestamp x, - boolean forceEncrypt) throws SQLServerException { + public final void setSmallDateTime(int n, java.sql.Timestamp x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setSmallDateTime", new Object[] {n, x, forceEncrypt}); checkClosed(); @@ -1941,9 +1828,7 @@ public final void setSmallDateTime(int n, } @Override - public final void setStructured(int n, - String tvpName, - SQLServerDataTable tvpDataTable) throws SQLServerException { + public final void setStructured(int n, String tvpName, SQLServerDataTable tvpDataTable) throws SQLServerException { tvpName = getTVPNameIfNull(n, tvpName); if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setStructured", new Object[] {n, tvpName, tvpDataTable}); @@ -1953,9 +1838,7 @@ public final void setStructured(int n, } @Override - public final void setStructured(int n, - String tvpName, - ResultSet tvpResultSet) throws SQLServerException { + public final void setStructured(int n, String tvpName, ResultSet tvpResultSet) throws SQLServerException { tvpName = getTVPNameIfNull(n, tvpName); if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setStructured", new Object[] {n, tvpName, tvpResultSet}); @@ -1965,8 +1848,7 @@ public final void setStructured(int n, } @Override - public final void setStructured(int n, - String tvpName, + public final void setStructured(int n, String tvpName, ISQLServerDataRecord tvpBulkRecord) throws SQLServerException { tvpName = getTVPNameIfNull(n, tvpName); if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) @@ -1976,8 +1858,7 @@ public final void setStructured(int n, loggerExternal.exiting(getClassNameLogging(), "setStructured"); } - String getTVPNameIfNull(int n, - String tvpName) throws SQLServerException { + String getTVPNameIfNull(int n, String tvpName) throws SQLServerException { if ((null == tvpName) || (0 == tvpName.length())) { // Check if the CallableStatement/PreparedStatement is a stored procedure call if (null != this.procedureName) { @@ -1985,7 +1866,8 @@ String getTVPNameIfNull(int n, pmd.isTVP = true; if (!pmd.procedureIsFound) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_StoredProcedureNotFound")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_StoredProcedureNotFound")); Object[] msgArgs = {this.procedureName}; SQLServerException.makeFromDriverError(connection, pmd, form.format(msgArgs), null, false); } @@ -1996,13 +1878,12 @@ String getTVPNameIfNull(int n, if (null != tvpSchema) { tvpName = "[" + tvpSchema + "].[" + tvpNameWithoutSchema + "]"; - } - else { + } else { tvpName = tvpNameWithoutSchema; } - } - catch (SQLException e) { - throw new SQLServerException(SQLServerException.getErrString("R_metaDataErrorForParameter"), null, 0, e); + } catch (SQLException e) { + throw new SQLServerException(SQLServerException.getErrString("R_metaDataErrorForParameter"), null, + 0, e); } } } @@ -2011,9 +1892,7 @@ String getTVPNameIfNull(int n, @Deprecated @Override - public final void setUnicodeStream(int n, - java.io.InputStream x, - int length) throws SQLException { + public final void setUnicodeStream(int n, java.io.InputStream x, int length) throws SQLException { SQLServerException.throwNotSupportedException(connection, this); } @@ -2050,13 +1929,13 @@ public int[] executeBatch() throws SQLServerException, BatchUpdateException, SQL } checkClosed(); discardLastExecutionResults(); - + int updateCounts[]; - + localUserSQL = userSQL; - + try { - if (isInsert(localUserSQL) && connection.isAzureDW() && (this.useBulkCopyForBatchInsert)) { + if (this.useBulkCopyForBatchInsert && connection.isAzureDW() && isInsert(localUserSQL)) { // From the JDBC spec, section 9.1.4 - Making Batch Updates: // The CallableStatement.executeBatch method (inherited from PreparedStatement) will // throw a BatchUpdateException if the stored procedure returns anything other than an @@ -2070,11 +1949,12 @@ public int[] executeBatch() throws SQLServerException, BatchUpdateException, SQL for (Parameter[] paramValues : batchParamValues) { for (Parameter paramValue : paramValues) { if (paramValue.isOutput()) { - throw new BatchUpdateException(SQLServerException.getErrString("R_outParamsNotPermittedinBatch"), null, 0, null); + throw new BatchUpdateException( + SQLServerException.getErrString("R_outParamsNotPermittedinBatch"), null, 0, null); } } } - + if (batchParamValues == null) { updateCounts = new int[0]; loggerExternal.exiting(getClassNameLogging(), "executeBatch", updateCounts); @@ -2085,25 +1965,37 @@ public int[] executeBatch() throws SQLServerException, BatchUpdateException, SQL ArrayList columnList = parseUserSQLForColumnListDW(); ArrayList valueList = parseUserSQLForValueListDW(false); - String destinationTableName = tableName; - SQLServerStatement stmt = (SQLServerStatement) connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, - connection.getHoldability(), stmtColumnEncriptionSetting); - - // Get destination metadata - try (SQLServerResultSet rs = stmt - .executeQueryInternal("sp_executesql N'SET FMTONLY ON SELECT * FROM " + destinationTableName + " '");) { + checkAdditionalQuery(); + + try (SQLServerStatement stmt = (SQLServerStatement) connection.createStatement( + ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, connection.getHoldability(), + stmtColumnEncriptionSetting); + SQLServerResultSet rs = stmt.executeQueryInternal( + "sp_executesql N'SET FMTONLY ON SELECT * FROM " + tableName + " '");) { + if (null != columnList && columnList.size() > 0) { + if (columnList.size() != valueList.size()) { + throw new IllegalArgumentException( + "Number of provided columns does not match the table definition."); + } + } else { + if (rs.getColumnCount() != valueList.size()) { + throw new IllegalArgumentException( + "Number of provided columns does not match the table definition."); + } + } - SQLServerBulkBatchInsertRecord batchRecord = new SQLServerBulkBatchInsertRecord(batchParamValues, columnList, valueList, null); + SQLServerBulkBatchInsertRecord batchRecord = new SQLServerBulkBatchInsertRecord(batchParamValues, + columnList, valueList, null); for (int i = 1; i <= rs.getColumnCount(); i++) { Column c = rs.getColumn(i); CryptoMetadata cryptoMetadata = c.getCryptoMetadata(); int jdbctype; TypeInfo ti = c.getTypeInfo(); + checkValidColumns(ti); if (null != cryptoMetadata) { jdbctype = cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType().getIntValue(); - } - else { + } else { jdbctype = ti.getSSType().getJDBCType().getIntValue(); } batchRecord.addColumnMetadata(i, c.getColumnName(), jdbctype, ti.getPrecision(), ti.getScale()); @@ -2124,20 +2016,14 @@ public int[] executeBatch() throws SQLServerException, BatchUpdateException, SQL loggerExternal.exiting(getClassNameLogging(), "executeBatch", updateCounts); return updateCounts; } - finally { - if (null != stmt) - stmt.close(); - } } - } - catch (SQLException e) { + } catch (SQLException e) { // throw a BatchUpdateException with the given error message, and return null for the updateCounts. throw new BatchUpdateException(e.getMessage(), null, 0, null); - } - catch (IllegalArgumentException e) { + } catch (IllegalArgumentException e) { // If we fail with IllegalArgumentException, fall back to the original batch insert logic. if (getStatementLogger().isLoggable(java.util.logging.Level.FINE)) { - getStatementLogger().fine("Parsing user's Batch Insert SQL Query failed: " + e.toString()); + getStatementLogger().fine("Parsing user's Batch Insert SQL Query failed: " + e.getMessage()); getStatementLogger().fine("Falling back to the original implementation for Batch Insert."); } } @@ -2159,7 +2045,8 @@ public int[] executeBatch() throws SQLServerException, BatchUpdateException, SQL for (Parameter[] paramValues : batchParamValues) { for (Parameter paramValue : paramValues) { if (paramValue.isOutput()) { - throw new BatchUpdateException(SQLServerException.getErrString("R_outParamsNotPermittedinBatch"), null, 0, null); + throw new BatchUpdateException( + SQLServerException.getErrString("R_outParamsNotPermittedinBatch"), null, 0, null); } } } @@ -2174,12 +2061,12 @@ public int[] executeBatch() throws SQLServerException, BatchUpdateException, SQL // Transform the SQLException into a BatchUpdateException with the update counts. if (null != batchCommand.batchException) { - throw new BatchUpdateException(batchCommand.batchException.getMessage(), batchCommand.batchException.getSQLState(), - batchCommand.batchException.getErrorCode(), updateCounts); + throw new BatchUpdateException(batchCommand.batchException.getMessage(), + batchCommand.batchException.getSQLState(), batchCommand.batchException.getErrorCode(), + updateCounts); } - } - finally { + } finally { batchParamValues = null; } @@ -2197,11 +2084,11 @@ public long[] executeLargeBatch() throws SQLServerException, BatchUpdateExceptio discardLastExecutionResults(); long updateCounts[]; - + localUserSQL = userSQL; - + try { - if (isInsert(localUserSQL) && connection.isAzureDW() && (this.useBulkCopyForBatchInsert)) { + if (this.useBulkCopyForBatchInsert && connection.isAzureDW() && isInsert(localUserSQL)) { // From the JDBC spec, section 9.1.4 - Making Batch Updates: // The CallableStatement.executeBatch method (inherited from PreparedStatement) will // throw a BatchUpdateException if the stored procedure returns anything other than an @@ -2215,11 +2102,12 @@ public long[] executeLargeBatch() throws SQLServerException, BatchUpdateExceptio for (Parameter[] paramValues : batchParamValues) { for (Parameter paramValue : paramValues) { if (paramValue.isOutput()) { - throw new BatchUpdateException(SQLServerException.getErrString("R_outParamsNotPermittedinBatch"), null, 0, null); + throw new BatchUpdateException( + SQLServerException.getErrString("R_outParamsNotPermittedinBatch"), null, 0, null); } } } - + if (batchParamValues == null) { updateCounts = new long[0]; loggerExternal.exiting(getClassNameLogging(), "executeLargeBatch", updateCounts); @@ -2230,25 +2118,37 @@ public long[] executeLargeBatch() throws SQLServerException, BatchUpdateExceptio ArrayList columnList = parseUserSQLForColumnListDW(); ArrayList valueList = parseUserSQLForValueListDW(false); - String destinationTableName = tableName; - SQLServerStatement stmt = (SQLServerStatement) connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, - connection.getHoldability(), stmtColumnEncriptionSetting); - - // Get destination metadata - try (SQLServerResultSet rs = stmt - .executeQueryInternal("sp_executesql N'SET FMTONLY ON SELECT * FROM " + destinationTableName + " '");) { + checkAdditionalQuery(); + + try (SQLServerStatement stmt = (SQLServerStatement) connection.createStatement( + ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, connection.getHoldability(), + stmtColumnEncriptionSetting); + SQLServerResultSet rs = stmt.executeQueryInternal( + "sp_executesql N'SET FMTONLY ON SELECT * FROM " + tableName + " '");) { + if (null != columnList && columnList.size() > 0) { + if (columnList.size() != valueList.size()) { + throw new IllegalArgumentException( + "Number of provided columns does not match the table definition."); + } + } else { + if (rs.getColumnCount() != valueList.size()) { + throw new IllegalArgumentException( + "Number of provided columns does not match the table definition."); + } + } - SQLServerBulkBatchInsertRecord batchRecord = new SQLServerBulkBatchInsertRecord(batchParamValues, columnList, valueList, null); + SQLServerBulkBatchInsertRecord batchRecord = new SQLServerBulkBatchInsertRecord(batchParamValues, + columnList, valueList, null); for (int i = 1; i <= rs.getColumnCount(); i++) { Column c = rs.getColumn(i); CryptoMetadata cryptoMetadata = c.getCryptoMetadata(); int jdbctype; TypeInfo ti = c.getTypeInfo(); + checkValidColumns(ti); if (null != cryptoMetadata) { jdbctype = cryptoMetadata.getBaseTypeInfo().getSSType().getJDBCType().getIntValue(); - } - else { + } else { jdbctype = ti.getSSType().getJDBCType().getIntValue(); } batchRecord.addColumnMetadata(i, c.getColumnName(), jdbctype, ti.getPrecision(), ti.getScale()); @@ -2269,20 +2169,14 @@ public long[] executeLargeBatch() throws SQLServerException, BatchUpdateExceptio loggerExternal.exiting(getClassNameLogging(), "executeLargeBatch", updateCounts); return updateCounts; } - finally { - if (null != stmt) - stmt.close(); - } } - } - catch (SQLException e) { + } catch (SQLException e) { // throw a BatchUpdateException with the given error message, and return null for the updateCounts. throw new BatchUpdateException(e.getMessage(), null, 0, null); - } - catch (IllegalArgumentException e) { + } catch (IllegalArgumentException e) { // If we fail with IllegalArgumentException, fall back to the original batch insert logic. if (getStatementLogger().isLoggable(java.util.logging.Level.FINE)) { - getStatementLogger().fine("Parsing user's Batch Insert SQL Query failed: " + e.toString()); + getStatementLogger().fine("Parsing user's Batch Insert SQL Query failed: " + e.getMessage()); getStatementLogger().fine("Falling back to the original implementation for Batch Insert."); } } @@ -2304,7 +2198,8 @@ public long[] executeLargeBatch() throws SQLServerException, BatchUpdateExceptio for (Parameter[] paramValues : batchParamValues) { for (Parameter paramValue : paramValues) { if (paramValue.isOutput()) { - throw new BatchUpdateException(SQLServerException.getErrString("R_outParamsNotPermittedinBatch"), null, 0, null); + throw new BatchUpdateException( + SQLServerException.getErrString("R_outParamsNotPermittedinBatch"), null, 0, null); } } } @@ -2322,33 +2217,87 @@ public long[] executeLargeBatch() throws SQLServerException, BatchUpdateExceptio DriverJDBCVersion.throwBatchUpdateException(batchCommand.batchException, updateCounts); } - } - finally { + } finally { batchParamValues = null; } loggerExternal.exiting(getClassNameLogging(), "executeLargeBatch", updateCounts); return updateCounts; } - - - private String parseUserSQLForTableNameDW(boolean hasInsertBeenFound, boolean hasIntoBeenFound, boolean hasTableBeenFound, - boolean isExpectingTableName) { + + private void checkValidColumns(TypeInfo ti) throws SQLServerException { + int jdbctype = ti.getSSType().getJDBCType().getIntValue(); + // currently, we do not support: geometry, geography, datetime and smalldatetime + switch (jdbctype) { + case java.sql.Types.INTEGER: + case java.sql.Types.SMALLINT: + case java.sql.Types.BIGINT: + case java.sql.Types.BIT: + case java.sql.Types.TINYINT: + case java.sql.Types.DOUBLE: + case java.sql.Types.REAL: + case microsoft.sql.Types.MONEY: + case microsoft.sql.Types.SMALLMONEY: + case java.sql.Types.DECIMAL: + case java.sql.Types.NUMERIC: + case microsoft.sql.Types.GUID: + case java.sql.Types.CHAR: + case java.sql.Types.NCHAR: + case java.sql.Types.LONGVARCHAR: + case java.sql.Types.VARCHAR: + case java.sql.Types.LONGNVARCHAR: + case java.sql.Types.NVARCHAR: + case java.sql.Types.BINARY: + case java.sql.Types.LONGVARBINARY: + case java.sql.Types.VARBINARY: + // Spatial datatypes fall under Varbinary, check if the UDT is geometry/geography. + String typeName = ti.getSSTypeName(); + if (typeName.equalsIgnoreCase("geometry") || typeName.equalsIgnoreCase("geography")) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_BulkTypeNotSupported")); + throw new IllegalArgumentException(form.format(new Object[] {typeName})); + } + case java.sql.Types.TIMESTAMP: + case java.sql.Types.DATE: + case java.sql.Types.TIME: + case 2013: // java.sql.Types.TIME_WITH_TIMEZONE + case 2014: // java.sql.Types.TIMESTAMP_WITH_TIMEZONE + case microsoft.sql.Types.DATETIMEOFFSET: + case microsoft.sql.Types.SQL_VARIANT: + return; + default: { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_BulkTypeNotSupported")); + String unsupportedDataType = JDBCType.of(jdbctype).toString(); + throw new IllegalArgumentException(form.format(new Object[] {unsupportedDataType})); + } + } + } + + private void checkAdditionalQuery() { + while (checkAndRemoveCommentsAndSpace(true)) {} + + // At this point, if localUserSQL is not empty (after removing all whitespaces, semicolons and comments), we + // have a + // new query. reject this. + if (localUserSQL.length() > 0) { + throw new IllegalArgumentException("Multiple queries are not allowed."); + } + } + + private String parseUserSQLForTableNameDW(boolean hasInsertBeenFound, boolean hasIntoBeenFound, + boolean hasTableBeenFound, boolean isExpectingTableName) { // As far as finding the table name goes, There are two cases: // Insert into and Insert // And there could be in-line comments (with /* and */) in between. // This method assumes the localUserSQL string starts with "insert". - localUserSQL = localUserSQL.trim(); - if (checkAndRemoveComments()) { - return parseUserSQLForTableNameDW(hasInsertBeenFound, hasIntoBeenFound, hasTableBeenFound, isExpectingTableName); - } - + while (checkAndRemoveCommentsAndSpace(false)) {} + StringBuilder sb = new StringBuilder(); - - // If table has been found and the next character is not a . at this point, we've finished parsing the table name. + + // If table has been found and the next character is not a . at this point, we've finished parsing the table + // name. // This if statement is needed to handle the case where the user has something like: - // [dbo] . /* random comment */ [tableName] + // [dbo] . /* random comment */ [tableName] if (hasTableBeenFound && !isExpectingTableName) { - if (localUserSQL.substring(0, 1).equalsIgnoreCase(".")) { + if (checkSQLLength(1) && localUserSQL.substring(0, 1).equalsIgnoreCase(".")) { sb.append("."); localUserSQL = localUserSQL.substring(1); return sb.toString() + parseUserSQLForTableNameDW(true, true, true, true); @@ -2356,87 +2305,98 @@ private String parseUserSQLForTableNameDW(boolean hasInsertBeenFound, boolean ha return ""; } } - - if (localUserSQL.substring(0, 6).equalsIgnoreCase("insert") && !hasInsertBeenFound) { + + if (!hasInsertBeenFound && checkSQLLength(6) && localUserSQL.substring(0, 6).equalsIgnoreCase("insert")) { localUserSQL = localUserSQL.substring(6); return parseUserSQLForTableNameDW(true, hasIntoBeenFound, hasTableBeenFound, isExpectingTableName); } - - if (localUserSQL.substring(0, 4).equalsIgnoreCase("into") && !hasIntoBeenFound) { + + if (!hasIntoBeenFound && checkSQLLength(6) && localUserSQL.substring(0, 4).equalsIgnoreCase("into")) { // is it really "into"? // if the "into" is followed by a blank space or /*, then yes. - if (Character.isWhitespace(localUserSQL.charAt(4)) || - (localUserSQL.charAt(4) == '/' && localUserSQL.charAt(5) == '*')) { + if (Character.isWhitespace(localUserSQL.charAt(4)) + || (localUserSQL.charAt(4) == '/' && localUserSQL.charAt(5) == '*')) { localUserSQL = localUserSQL.substring(4); return parseUserSQLForTableNameDW(hasInsertBeenFound, true, hasTableBeenFound, isExpectingTableName); } - + // otherwise, we found the token that either contains the databasename.tablename or tablename. - // Recursively handle this, but into has been found. (or rather, it's absent in the query - the "into" keyword is optional) + // Recursively handle this, but into has been found. (or rather, it's absent in the query - the "into" + // keyword is optional) return parseUserSQLForTableNameDW(hasInsertBeenFound, true, hasTableBeenFound, isExpectingTableName); } - + // At this point, the next token has to be the table name. // It could be encapsulated in [], "", or have a database name preceding the table name. // If it's encapsulated in [] or "", we need be more careful with parsing as anything could go into []/"". // For ] or ", they can be escaped by ]] or "", watch out for this too. - if (localUserSQL.substring(0, 1).equalsIgnoreCase("[")) { + if (checkSQLLength(1) && localUserSQL.substring(0, 1).equalsIgnoreCase("[")) { int tempint = localUserSQL.indexOf("]", 1); - + + // ] has not been found, this is wrong. + if (tempint < 0) { + throw new IllegalArgumentException("Invalid SQL Query."); + } + // keep checking if it's escaped - while (localUserSQL.charAt(tempint + 1) == ']') { + while (tempint >= 0 && checkSQLLength(tempint + 2) && localUserSQL.charAt(tempint + 1) == ']') { tempint = localUserSQL.indexOf("]", tempint + 2); } - + // we've found a ] that is actually trying to close the square bracket. // return tablename + potentially more that's part of the table name sb.append(localUserSQL.substring(0, tempint + 1)); localUserSQL = localUserSQL.substring(tempint + 1); return sb.toString() + parseUserSQLForTableNameDW(true, true, true, false); } - + // do the same for "" - if (localUserSQL.substring(0, 1).equalsIgnoreCase("\"")) { + if (checkSQLLength(1) && localUserSQL.substring(0, 1).equalsIgnoreCase("\"")) { int tempint = localUserSQL.indexOf("\"", 1); - + + // \" has not been found, this is wrong. + if (tempint < 0) { + throw new IllegalArgumentException("Invalid SQL Query."); + } + // keep checking if it's escaped - while (localUserSQL.charAt(tempint + 1) == '\"') { + while (tempint >= 0 && checkSQLLength(tempint + 2) && localUserSQL.charAt(tempint + 1) == '\"') { tempint = localUserSQL.indexOf("\"", tempint + 2); } - + // we've found a " that is actually trying to close the quote. // return tablename + potentially more that's part of the table name sb.append(localUserSQL.substring(0, tempint + 1)); localUserSQL = localUserSQL.substring(tempint + 1); return sb.toString() + parseUserSQLForTableNameDW(true, true, true, false); } - + // At this point, the next chunk of string is the table name, without starting with [ or ". while (localUserSQL.length() > 0) { - // Keep going until the end of the table name is signalled - either a ., whitespace, or comment is encountered - if (localUserSQL.charAt(0) == '.' || Character.isWhitespace(localUserSQL.charAt(0)) || checkAndRemoveComments()) { + // Keep going until the end of the table name is signalled - either a ., whitespace, ; or comment is + // encountered. + if (localUserSQL.charAt(0) == '.' || Character.isWhitespace(localUserSQL.charAt(0)) + || checkAndRemoveCommentsAndSpace(false)) { return sb.toString() + parseUserSQLForTableNameDW(true, true, true, false); + } else if (localUserSQL.charAt(0) == ';') { + throw new IllegalArgumentException("End of query detected before VALUES have been found."); } else { sb.append(localUserSQL.charAt(0)); localUserSQL = localUserSQL.substring(1); } } - + // It shouldn't come here. If we did, something is wrong. - throw new IllegalArgumentException("localUserSQL"); + throw new IllegalArgumentException("Invalid SQL Query."); } - + private ArrayList parseUserSQLForColumnListDW() { - localUserSQL = localUserSQL.trim(); - // ignore all comments - if (checkAndRemoveComments()) { - return parseUserSQLForColumnListDW(); - } - - //check if optional column list was provided + while (checkAndRemoveCommentsAndSpace(false)) {} + + // check if optional column list was provided // Columns can have the form of c1, [c1] or "c1". It can escape ] or " by ]] or "". - if (localUserSQL.substring(0, 1).equalsIgnoreCase("(")) { + if (checkSQLLength(1) && localUserSQL.substring(0, 1).equalsIgnoreCase("(")) { localUserSQL = localUserSQL.substring(1); return parseUserSQLForColumnListDWHelper(new ArrayList()); } @@ -2444,201 +2404,229 @@ private ArrayList parseUserSQLForColumnListDW() { } private ArrayList parseUserSQLForColumnListDWHelper(ArrayList listOfColumns) { - localUserSQL = localUserSQL.trim(); - // ignore all comments - if (checkAndRemoveComments()) { - return parseUserSQLForColumnListDWHelper(listOfColumns); - } - - if (localUserSQL.charAt(0) == ')') { - localUserSQL = localUserSQL.substring(1); - return listOfColumns; - } - - if (localUserSQL.charAt(0) == ',') { - localUserSQL = localUserSQL.substring(1); - return parseUserSQLForColumnListDWHelper(listOfColumns); - } - - if (localUserSQL.charAt(0) == '[') { - int tempint = localUserSQL.indexOf("]", 1); - - // keep checking if it's escaped - while (localUserSQL.charAt(tempint + 1) == ']') { - localUserSQL = localUserSQL.substring(0, tempint) + localUserSQL.substring(tempint + 1); - tempint = localUserSQL.indexOf("]", tempint + 1); - } - - // we've found a ] that is actually trying to close the square bracket. - String tempstr = localUserSQL.substring(1, tempint); - localUserSQL = localUserSQL.substring(tempint + 1); - listOfColumns.add(tempstr); - return parseUserSQLForColumnListDWHelper(listOfColumns); - } - - if (localUserSQL.charAt(0) == '\"') { - int tempint = localUserSQL.indexOf("\"", 1); - - // keep checking if it's escaped - while (localUserSQL.charAt(tempint + 1) == '\"') { - localUserSQL = localUserSQL.substring(0, tempint) + localUserSQL.substring(tempint + 1); - tempint = localUserSQL.indexOf("\"", tempint + 1); - } - - // we've found a " that is actually trying to close the quote. - String tempstr = localUserSQL.substring(1, tempint); - localUserSQL = localUserSQL.substring(tempint + 1); - listOfColumns.add(tempstr); - return parseUserSQLForColumnListDWHelper(listOfColumns); - } + while (checkAndRemoveCommentsAndSpace(false)) {} - // At this point, the next chunk of string is the column name, without starting with [ or ". StringBuilder sb = new StringBuilder(); while (localUserSQL.length() > 0) { - if (localUserSQL.charAt(0) == ',') { - localUserSQL = localUserSQL.substring(1); - listOfColumns.add(sb.toString()); - return parseUserSQLForColumnListDWHelper(listOfColumns); - } else if (localUserSQL.charAt(0) == ')'){ + while (checkAndRemoveCommentsAndSpace(false)) {} + + // exit condition + if (checkSQLLength(1) && localUserSQL.charAt(0) == ')') { localUserSQL = localUserSQL.substring(1); - listOfColumns.add(sb.toString()); return listOfColumns; - } else if (checkAndRemoveComments()) { - localUserSQL = localUserSQL.trim(); - } else { - sb.append(localUserSQL.charAt(0)); + } + + // ignore , + // we've confirmed length is more than 0. + if (localUserSQL.charAt(0) == ',') { localUserSQL = localUserSQL.substring(1); - localUserSQL = localUserSQL.trim(); + while (checkAndRemoveCommentsAndSpace(false)) {} + } + + // handle [] case + if (localUserSQL.charAt(0) == '[') { + int tempint = localUserSQL.indexOf("]", 1); + + // ] has not been found, this is wrong. + if (tempint < 0) { + throw new IllegalArgumentException("Invalid SQL Query."); + } + + // keep checking if it's escaped + while (tempint >= 0 && checkSQLLength(tempint + 2) && localUserSQL.charAt(tempint + 1) == ']') { + localUserSQL = localUserSQL.substring(0, tempint) + localUserSQL.substring(tempint + 1); + tempint = localUserSQL.indexOf("]", tempint + 1); + } + + // we've found a ] that is actually trying to close the square bracket. + String tempstr = localUserSQL.substring(1, tempint); + localUserSQL = localUserSQL.substring(tempint + 1); + listOfColumns.add(tempstr); + continue; // proceed with the rest of the string + } + + // handle "" case + if (localUserSQL.charAt(0) == '\"') { + int tempint = localUserSQL.indexOf("\"", 1); + + // \" has not been found, this is wrong. + if (tempint < 0) { + throw new IllegalArgumentException("Invalid SQL Query."); + } + + // keep checking if it's escaped + while (tempint >= 0 && checkSQLLength(tempint + 2) && localUserSQL.charAt(tempint + 1) == '\"') { + localUserSQL = localUserSQL.substring(0, tempint) + localUserSQL.substring(tempint + 1); + tempint = localUserSQL.indexOf("\"", tempint + 1); + } + + // we've found a " that is actually trying to close the quote. + String tempstr = localUserSQL.substring(1, tempint); + localUserSQL = localUserSQL.substring(tempint + 1); + listOfColumns.add(tempstr); + continue; // proceed with the rest of the string + } + + // At this point, the next chunk of string is the column name, without starting with [ or ". + while (localUserSQL.length() > 0) { + if (checkAndRemoveCommentsAndSpace(false)) { + continue; + } + if (localUserSQL.charAt(0) == ',') { + localUserSQL = localUserSQL.substring(1); + listOfColumns.add(sb.toString()); + sb.setLength(0); + break; // exit this while loop, but continue parsing. + } else if (localUserSQL.charAt(0) == ')') { + localUserSQL = localUserSQL.substring(1); + listOfColumns.add(sb.toString()); + return listOfColumns; // reached exit condition. + } else { + sb.append(localUserSQL.charAt(0)); + localUserSQL = localUserSQL.substring(1); + localUserSQL = localUserSQL.trim(); // add an entry. + } } } - + // It shouldn't come here. If we did, something is wrong. - throw new IllegalArgumentException("localUserSQL"); + // most likely we couldn't hit the exit condition and just parsed until the end of the string. + throw new IllegalArgumentException("Invalid SQL Query."); } - private ArrayList parseUserSQLForValueListDW(boolean hasValuesBeenFound) { - localUserSQL = localUserSQL.trim(); - // ignore all comments - if (checkAndRemoveComments()) { - return parseUserSQLForValueListDW(hasValuesBeenFound); - } - + if (checkAndRemoveCommentsAndSpace(false)) {} + if (!hasValuesBeenFound) { // look for keyword "VALUES" - if (localUserSQL.substring(0, 6).equalsIgnoreCase("VALUES")) { + if (checkSQLLength(6) && localUserSQL.substring(0, 6).equalsIgnoreCase("VALUES")) { localUserSQL = localUserSQL.substring(6); - - localUserSQL = localUserSQL.trim(); - + // ignore all comments - if (checkAndRemoveComments()) { - return parseUserSQLForValueListDW(true); - } - - if (localUserSQL.substring(0, 1).equalsIgnoreCase("(")) { + while (checkAndRemoveCommentsAndSpace(false)) {} + + if (checkSQLLength(1) && localUserSQL.substring(0, 1).equalsIgnoreCase("(")) { localUserSQL = localUserSQL.substring(1); return parseUserSQLForValueListDWHelper(new ArrayList()); } } } else { // ignore all comments - if (checkAndRemoveComments()) { - return parseUserSQLForValueListDW(hasValuesBeenFound); - } - - if (localUserSQL.substring(0, 1).equalsIgnoreCase("(")) { + while (checkAndRemoveCommentsAndSpace(false)) {} + + if (checkSQLLength(1) && localUserSQL.substring(0, 1).equalsIgnoreCase("(")) { localUserSQL = localUserSQL.substring(1); return parseUserSQLForValueListDWHelper(new ArrayList()); } } - + // shouldn't come here, as the list of values is mandatory. - throw new IllegalArgumentException("localUserSQL"); + throw new IllegalArgumentException("Invalid SQL Query."); } private ArrayList parseUserSQLForValueListDWHelper(ArrayList listOfValues) { - localUserSQL = localUserSQL.trim(); - // ignore all comments - if (checkAndRemoveComments()) { - return parseUserSQLForValueListDWHelper(listOfValues); - } + while (checkAndRemoveCommentsAndSpace(false)) {} - if (localUserSQL.charAt(0) == ')') { - localUserSQL = localUserSQL.substring(1); - return listOfValues; - } - - if (localUserSQL.charAt(0) == ',') { - localUserSQL = localUserSQL.substring(1); - return parseUserSQLForValueListDWHelper(listOfValues); - } - - if (localUserSQL.charAt(0) == '\'') { - int tempint = localUserSQL.indexOf("\'", 1); - - // keep checking if it's escaped - while (localUserSQL.charAt(tempint + 1) == '\'') { - localUserSQL = localUserSQL.substring(0, tempint) + localUserSQL.substring(tempint + 1); - tempint = localUserSQL.indexOf("\'", tempint + 1); - } - - // we've found a ' that is actually trying to close the quote. - // Include 's around the string as well, so we can distinguish '?' and ? later on. - String tempstr = localUserSQL.substring(0, tempint + 1); - localUserSQL = localUserSQL.substring(tempint + 1); - listOfValues.add(tempstr); - return parseUserSQLForValueListDWHelper(listOfValues); - } - // At this point, the next chunk of string is the value, without starting with ' (most likely a ?). StringBuilder sb = new StringBuilder(); while (localUserSQL.length() > 0) { + if (checkAndRemoveCommentsAndSpace(false)) { + continue; + } if (localUserSQL.charAt(0) == ',' || localUserSQL.charAt(0) == ')') { if (localUserSQL.charAt(0) == ',') { localUserSQL = localUserSQL.substring(1); + if (!sb.toString().equals("?")) { + // throw IllegalArgumentException and fallback to original logic for batch insert + throw new IllegalArgumentException( + "Only fully parameterized queries are allowed for using Bulk Copy API for batch insert at the moment."); + } listOfValues.add(sb.toString()); - return parseUserSQLForValueListDWHelper(listOfValues); + sb.setLength(0); } else { localUserSQL = localUserSQL.substring(1); listOfValues.add(sb.toString()); - return listOfValues; + return listOfValues; // reached exit condition. } - } else if (checkAndRemoveComments()) { - localUserSQL = localUserSQL.trim(); } else { sb.append(localUserSQL.charAt(0)); localUserSQL = localUserSQL.substring(1); - localUserSQL = localUserSQL.trim(); + localUserSQL = localUserSQL.trim(); // add entry. } } - + + // Don't need this anymore since we removed support for non-parameterized query. + // if (localUserSQL.charAt(0) == '\'') { + // int tempint = localUserSQL.indexOf("\'", 1); + // + // // \' has not been found, this is wrong. + // if (tempint < 0) { + // throw new IllegalArgumentException("Invalid SQL Query."); + // } + // + // // keep checking if it's escaped + // while (tempint >= 0 && checkSQLLength(tempint + 2) && localUserSQL.charAt(tempint + 1) == '\'') { + // localUserSQL = localUserSQL.substring(0, tempint) + localUserSQL.substring(tempint + 1); + // tempint = localUserSQL.indexOf("\'", tempint + 1); + // } + // + // // we've found a ' that is actually trying to close the quote. + // // Include 's around the string as well, so we can distinguish '?' and ? later on. + // String tempstr = localUserSQL.substring(0, tempint + 1); + // localUserSQL = localUserSQL.substring(tempint + 1); + // listOfValues.add(tempstr); + // return parseUserSQLForValueListDWHelper(listOfValues); + // } + // It shouldn't come here. If we did, something is wrong. - throw new IllegalArgumentException("localUserSQL"); + throw new IllegalArgumentException("Invalid SQL Query."); } - - private boolean checkAndRemoveComments() { + + private boolean checkAndRemoveCommentsAndSpace(boolean checkForSemicolon) { + localUserSQL = localUserSQL.trim(); + + while (checkForSemicolon && null != localUserSQL && localUserSQL.length() > 0 + && localUserSQL.charAt(0) == ';') { + localUserSQL = localUserSQL.substring(1); + } + if (null == localUserSQL || localUserSQL.length() < 2) { return false; } - + if (localUserSQL.substring(0, 2).equalsIgnoreCase("/*")) { int temp = localUserSQL.indexOf("*/") + 2; + if (temp <= 0) { + localUserSQL = ""; + return false; + } localUserSQL = localUserSQL.substring(temp); return true; } - + if (localUserSQL.substring(0, 2).equalsIgnoreCase("--")) { - int temp = localUserSQL.indexOf("\n") + 2; + int temp = localUserSQL.indexOf("\n") + 1; + if (temp <= 0) { + localUserSQL = ""; + return false; + } localUserSQL = localUserSQL.substring(temp); return true; } + return false; } + private boolean checkSQLLength(int length) { + if (null == localUserSQL || localUserSQL.length() < length) { + throw new IllegalArgumentException("Invalid SQL Query."); + } + return true; + } + private final class PrepStmtBatchExecCmd extends TDSCommand { private final SQLServerPreparedStatement stmt; SQLServerException batchException; @@ -2674,7 +2662,8 @@ final void doExecutePreparedStatementBatch(PrepStmtBatchExecCmd batchCommand) th Vector cryptoMetaBatch = new Vector<>(); if (isSelect(userSQL)) { - SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_selectNotPermittedinBatch"), null, true); + SQLServerException.makeFromDriverError(connection, this, + SQLServerException.getErrString("R_selectNotPermittedinBatch"), null, true); } // Make sure any previous maxRows limitation on the connection is removed. @@ -2687,16 +2676,14 @@ final void doExecutePreparedStatementBatch(PrepStmtBatchExecCmd batchCommand) th Parameter[] batchParam = new Parameter[inOutParam.length]; /* - * TDSWriter tdsWriter = null; while (numBatchesExecuted < numBatches) { // Fill in the parameter values for this batch Parameter - * paramValues[] = batchParamValues.get(numBatchesPrepared); assert paramValues.length == batchParam.length; System.arraycopy(paramValues, 0, - * batchParam, 0, paramValues.length); - * - * boolean hasExistingTypeDefinitions = preparedTypeDefinitions != null; boolean hasNewTypeDefinitions = buildPreparedStrings(batchParam, - * false); - * - * // Get the encryption metadata for the first batch only. if ((0 == numBatchesExecuted) && - * (Util.shouldHonorAEForParameters(stmtColumnEncriptionSetting, connection)) && (0 < batchParam.length) && !isInternalEncryptionQuery && - * !encryptionMetadataIsRetrieved) { getParameterEncryptionMetadata(batchParam); + * TDSWriter tdsWriter = null; while (numBatchesExecuted < numBatches) { // Fill in the parameter values for + * this batch Parameter paramValues[] = batchParamValues.get(numBatchesPrepared); assert paramValues.length == + * batchParam.length; System.arraycopy(paramValues, 0, batchParam, 0, paramValues.length); boolean + * hasExistingTypeDefinitions = preparedTypeDefinitions != null; boolean hasNewTypeDefinitions = + * buildPreparedStrings(batchParam, false); // Get the encryption metadata for the first batch only. if ((0 == + * numBatchesExecuted) && (Util.shouldHonorAEForParameters(stmtColumnEncriptionSetting, connection)) && (0 < + * batchParam.length) && !isInternalEncryptionQuery && !encryptionMetadataIsRetrieved) { + * getParameterEncryptionMetadata(batchParam); */ TDSWriter tdsWriter = null; @@ -2710,14 +2697,16 @@ final void doExecutePreparedStatementBatch(PrepStmtBatchExecCmd batchCommand) th boolean hasNewTypeDefinitions = buildPreparedStrings(batchParam, false); // Get the encryption metadata for the first batch only. - if ((0 == numBatchesExecuted) && (Util.shouldHonorAEForParameters(stmtColumnEncriptionSetting, connection)) && (0 < batchParam.length) - && !isInternalEncryptionQuery && !encryptionMetadataIsRetrieved) { + if ((0 == numBatchesExecuted) && (Util.shouldHonorAEForParameters(stmtColumnEncriptionSetting, connection)) + && (0 < batchParam.length) && !isInternalEncryptionQuery && !encryptionMetadataIsRetrieved) { getParameterEncryptionMetadata(batchParam); - // fix an issue when inserting unicode into non-encrypted nchar column using setString() and AE is on on Connection + // fix an issue when inserting unicode into non-encrypted nchar column using setString() and AE is on on + // Connection buildPreparedStrings(batchParam, true); - // Save the crypto metadata retrieved for the first batch. We will re-use these for the rest of the batches. + // Save the crypto metadata retrieved for the first batch. We will re-use these for the rest of the + // batches. for (Parameter aBatchParam : batchParam) { cryptoMetaBatch.add(aBatchParam.cryptoMeta); } @@ -2744,8 +2733,7 @@ final void doExecutePreparedStatementBatch(PrepStmtBatchExecCmd batchCommand) th if (numBatchesExecuted < numBatchesPrepared) { // assert null != tdsWriter; tdsWriter.writeByte((byte) nBatchStatementDelimiter); - } - else { + } else { resetForReexecute(); tdsWriter = batchCommand.startRequest(TDS.PKT_RPC); } @@ -2783,10 +2771,10 @@ final void doExecutePreparedStatementBatch(PrepStmtBatchExecCmd batchCommand) th // translated into (or added to) a BatchUpdateException. if (null != resultSet) { SQLServerException.makeFromDriverError(connection, this, - SQLServerException.getErrString("R_resultsetGeneratedForUpdate"), null, false); + SQLServerException.getErrString("R_resultsetGeneratedForUpdate"), null, + false); } - } - catch (SQLServerException e) { + } catch (SQLServerException e) { // If the failure was severe enough to close the connection or roll back a // manual transaction, then propagate the error up as a SQLServerException // now, rather than continue with the batch. @@ -2811,7 +2799,8 @@ final void doExecutePreparedStatementBatch(PrepStmtBatchExecCmd batchCommand) th // In batch execution, we have a special update count // to indicate that no information was returned - batchCommand.updateCounts[numBatchesExecuted] = (-1 == updateCount) ? Statement.SUCCESS_NO_INFO : updateCount; + batchCommand.updateCounts[numBatchesExecuted] = (-1 == updateCount) ? Statement.SUCCESS_NO_INFO + : updateCount; processBatch(); numBatchesExecuted++; @@ -2823,20 +2812,18 @@ final void doExecutePreparedStatementBatch(PrepStmtBatchExecCmd batchCommand) th // we successfully executed the previously prepared set. assert numBatchesExecuted == numBatchesPrepared; } - } - catch (SQLException e) { - if (retryBasedOnFailedReuseOfCachedHandle(e, attempt, needsPrepare, true) && connection.isStatementPoolingEnabled()) { + } catch (SQLException e) { + if (retryBasedOnFailedReuseOfCachedHandle(e, attempt, needsPrepare, true) + && connection.isStatementPoolingEnabled()) { // Reset number of batches prepared. numBatchesPrepared = numBatchesExecuted; continue; - } - else if (null != batchCommand.batchException) { + } else if (null != batchCommand.batchException) { // if batch exception occurred, loop out to throw the initial batchException numBatchesExecuted = numBatchesPrepared; attempt++; continue; - } - else { + } else { throw e; } } @@ -2846,8 +2833,7 @@ else if (null != batchCommand.batchException) { } @Override - public final void setCharacterStream(int parameterIndex, - Reader reader) throws SQLException { + public final void setCharacterStream(int parameterIndex, Reader reader) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setCharacterStream", new Object[] {parameterIndex, reader}); checkClosed(); @@ -2856,9 +2842,7 @@ public final void setCharacterStream(int parameterIndex, } @Override - public final void setCharacterStream(int n, - java.io.Reader reader, - int length) throws SQLServerException { + public final void setCharacterStream(int n, java.io.Reader reader, int length) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setCharacterStream", new Object[] {n, reader, length}); checkClosed(); @@ -2867,19 +2851,17 @@ public final void setCharacterStream(int n, } @Override - public final void setCharacterStream(int parameterIndex, - Reader reader, - long length) throws SQLException { + public final void setCharacterStream(int parameterIndex, Reader reader, long length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setCharacterStream", new Object[] {parameterIndex, reader, length}); + loggerExternal.entering(getClassNameLogging(), "setCharacterStream", + new Object[] {parameterIndex, reader, length}); checkClosed(); setStream(parameterIndex, StreamType.CHARACTER, reader, JavaType.READER, length); loggerExternal.exiting(getClassNameLogging(), "setCharacterStream"); } @Override - public final void setNCharacterStream(int parameterIndex, - Reader value) throws SQLException { + public final void setNCharacterStream(int parameterIndex, Reader value) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setNCharacterStream", new Object[] {parameterIndex, value}); checkClosed(); @@ -2888,25 +2870,22 @@ public final void setNCharacterStream(int parameterIndex, } @Override - public final void setNCharacterStream(int parameterIndex, - Reader value, - long length) throws SQLException { + public final void setNCharacterStream(int parameterIndex, Reader value, long length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setNCharacterStream", new Object[] {parameterIndex, value, length}); + loggerExternal.entering(getClassNameLogging(), "setNCharacterStream", + new Object[] {parameterIndex, value, length}); checkClosed(); setStream(parameterIndex, StreamType.NCHARACTER, value, JavaType.READER, length); loggerExternal.exiting(getClassNameLogging(), "setNCharacterStream"); } @Override - public final void setRef(int i, - java.sql.Ref x) throws SQLException { + public final void setRef(int i, java.sql.Ref x) throws SQLException { SQLServerException.throwNotSupportedException(connection, this); } @Override - public final void setBlob(int i, - java.sql.Blob x) throws SQLException { + public final void setBlob(int i, java.sql.Blob x) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setBlob", new Object[] {i, x}); checkClosed(); @@ -2915,29 +2894,27 @@ public final void setBlob(int i, } @Override - public final void setBlob(int parameterIndex, - InputStream inputStream) throws SQLException { + public final void setBlob(int parameterIndex, InputStream inputStream) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setBlob", new Object[] {parameterIndex, inputStream}); checkClosed(); - setStream(parameterIndex, StreamType.BINARY, inputStream, JavaType.INPUTSTREAM, DataTypes.UNKNOWN_STREAM_LENGTH); + setStream(parameterIndex, StreamType.BINARY, inputStream, JavaType.INPUTSTREAM, + DataTypes.UNKNOWN_STREAM_LENGTH); loggerExternal.exiting(getClassNameLogging(), "setBlob"); } @Override - public final void setBlob(int parameterIndex, - InputStream inputStream, - long length) throws SQLException { + public final void setBlob(int parameterIndex, InputStream inputStream, long length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "setBlob", new Object[] {parameterIndex, inputStream, length}); + loggerExternal.entering(getClassNameLogging(), "setBlob", + new Object[] {parameterIndex, inputStream, length}); checkClosed(); setStream(parameterIndex, StreamType.BINARY, inputStream, JavaType.INPUTSTREAM, length); loggerExternal.exiting(getClassNameLogging(), "setBlob"); } @Override - public final void setClob(int parameterIndex, - java.sql.Clob clobValue) throws SQLException { + public final void setClob(int parameterIndex, java.sql.Clob clobValue) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setClob", new Object[] {parameterIndex, clobValue}); checkClosed(); @@ -2946,8 +2923,7 @@ public final void setClob(int parameterIndex, } @Override - public final void setClob(int parameterIndex, - Reader reader) throws SQLException { + public final void setClob(int parameterIndex, Reader reader) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setClob", new Object[] {parameterIndex, reader}); checkClosed(); @@ -2956,9 +2932,7 @@ public final void setClob(int parameterIndex, } @Override - public final void setClob(int parameterIndex, - Reader reader, - long length) throws SQLException { + public final void setClob(int parameterIndex, Reader reader, long length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setClob", new Object[] {parameterIndex, reader, length}); checkClosed(); @@ -2967,8 +2941,7 @@ public final void setClob(int parameterIndex, } @Override - public final void setNClob(int parameterIndex, - NClob value) throws SQLException { + public final void setNClob(int parameterIndex, NClob value) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setNClob", new Object[] {parameterIndex, value}); checkClosed(); @@ -2977,8 +2950,7 @@ public final void setNClob(int parameterIndex, } @Override - public final void setNClob(int parameterIndex, - Reader reader) throws SQLException { + public final void setNClob(int parameterIndex, Reader reader) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setNClob", new Object[] {parameterIndex, reader}); checkClosed(); @@ -2987,9 +2959,7 @@ public final void setNClob(int parameterIndex, } @Override - public final void setNClob(int parameterIndex, - Reader reader, - long length) throws SQLException { + public final void setNClob(int parameterIndex, Reader reader, long length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setNClob", new Object[] {parameterIndex, reader, length}); checkClosed(); @@ -2998,15 +2968,12 @@ public final void setNClob(int parameterIndex, } @Override - public final void setArray(int i, - java.sql.Array x) throws SQLException { + public final void setArray(int i, java.sql.Array x) throws SQLException { SQLServerException.throwNotSupportedException(connection, this); } @Override - public final void setDate(int n, - java.sql.Date x, - java.util.Calendar cal) throws SQLServerException { + public final void setDate(int n, java.sql.Date x, java.util.Calendar cal) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setDate", new Object[] {n, x, cal}); checkClosed(); @@ -3015,9 +2982,7 @@ public final void setDate(int n, } @Override - public final void setDate(int n, - java.sql.Date x, - java.util.Calendar cal, + public final void setDate(int n, java.sql.Date x, java.util.Calendar cal, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setDate", new Object[] {n, x, cal, forceEncrypt}); @@ -3027,9 +2992,7 @@ public final void setDate(int n, } @Override - public final void setTime(int n, - java.sql.Time x, - java.util.Calendar cal) throws SQLServerException { + public final void setTime(int n, java.sql.Time x, java.util.Calendar cal) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setTime", new Object[] {n, x, cal}); checkClosed(); @@ -3038,9 +3001,7 @@ public final void setTime(int n, } @Override - public final void setTime(int n, - java.sql.Time x, - java.util.Calendar cal, + public final void setTime(int n, java.sql.Time x, java.util.Calendar cal, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setTime", new Object[] {n, x, cal, forceEncrypt}); @@ -3050,9 +3011,7 @@ public final void setTime(int n, } @Override - public final void setTimestamp(int n, - java.sql.Timestamp x, - java.util.Calendar cal) throws SQLServerException { + public final void setTimestamp(int n, java.sql.Timestamp x, java.util.Calendar cal) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setTimestamp", new Object[] {n, x, cal}); checkClosed(); @@ -3061,9 +3020,7 @@ public final void setTimestamp(int n, } @Override - public final void setTimestamp(int n, - java.sql.Timestamp x, - java.util.Calendar cal, + public final void setTimestamp(int n, java.sql.Timestamp x, java.util.Calendar cal, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setTimestamp", new Object[] {n, x, cal, forceEncrypt}); @@ -3073,17 +3030,16 @@ public final void setTimestamp(int n, } @Override - public final void setNull(int paramIndex, - int sqlType, - String typeName) throws SQLServerException { + public final void setNull(int paramIndex, int sqlType, String typeName) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setNull", new Object[] {paramIndex, sqlType, typeName}); checkClosed(); if (microsoft.sql.Types.STRUCTURED == sqlType) { - setObject(setterGetParam(paramIndex), null, JavaType.TVP, JDBCType.of(sqlType), null, null, false, paramIndex, typeName); - } - else { - setObject(setterGetParam(paramIndex), null, JavaType.OBJECT, JDBCType.of(sqlType), null, null, false, paramIndex, typeName); + setObject(setterGetParam(paramIndex), null, JavaType.TVP, JDBCType.of(sqlType), null, null, false, + paramIndex, typeName); + } else { + setObject(setterGetParam(paramIndex), null, JavaType.OBJECT, JDBCType.of(sqlType), null, null, false, + paramIndex, typeName); } loggerExternal.exiting(getClassNameLogging(), "setNull"); } @@ -3095,8 +3051,7 @@ public final ParameterMetaData getParameterMetaData(boolean forceRefresh) throws if (!forceRefresh && null != pmd) { return pmd; - } - else { + } else { loggerExternal.entering(getClassNameLogging(), "getParameterMetaData"); checkClosed(); pmd = new SQLServerParameterMetaData(this, userSQL); @@ -3114,20 +3069,17 @@ public final ParameterMetaData getParameterMetaData() throws SQLServerException } @Override - public final void setURL(int parameterIndex, - java.net.URL x) throws SQLException { + public final void setURL(int parameterIndex, java.net.URL x) throws SQLException { SQLServerException.throwNotSupportedException(connection, this); } @Override - public final void setRowId(int parameterIndex, - RowId x) throws SQLException { + public final void setRowId(int parameterIndex, RowId x) throws SQLException { SQLServerException.throwNotSupportedException(connection, this); } @Override - public final void setSQLXML(int parameterIndex, - SQLXML xmlObject) throws SQLException { + public final void setSQLXML(int parameterIndex, SQLXML xmlObject) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "setSQLXML", new Object[] {parameterIndex, xmlObject}); checkClosed(); @@ -3135,11 +3087,11 @@ public final void setSQLXML(int parameterIndex, loggerExternal.exiting(getClassNameLogging(), "setSQLXML"); } - /* make sure we throw here */ @Override public final int executeUpdate(String sql) throws SQLServerException { loggerExternal.entering(getClassNameLogging(), "executeUpdate", sql); - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_cannotTakeArgumentsPreparedOrCallable")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_cannotTakeArgumentsPreparedOrCallable")); Object[] msgArgs = {"executeUpdate()"}; throw new SQLServerException(this, form.format(msgArgs), null, 0, false); } @@ -3147,7 +3099,8 @@ public final int executeUpdate(String sql) throws SQLServerException { @Override public final boolean execute(String sql) throws SQLServerException { loggerExternal.entering(getClassNameLogging(), "execute", sql); - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_cannotTakeArgumentsPreparedOrCallable")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_cannotTakeArgumentsPreparedOrCallable")); Object[] msgArgs = {"execute()"}; throw new SQLServerException(this, form.format(msgArgs), null, 0, false); } @@ -3155,7 +3108,8 @@ public final boolean execute(String sql) throws SQLServerException { @Override public final java.sql.ResultSet executeQuery(String sql) throws SQLServerException { loggerExternal.entering(getClassNameLogging(), "executeQuery", sql); - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_cannotTakeArgumentsPreparedOrCallable")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_cannotTakeArgumentsPreparedOrCallable")); Object[] msgArgs = {"executeQuery()"}; throw new SQLServerException(this, form.format(msgArgs), null, 0, false); } @@ -3163,7 +3117,8 @@ public final java.sql.ResultSet executeQuery(String sql) throws SQLServerExcepti @Override public void addBatch(String sql) throws SQLServerException { loggerExternal.entering(getClassNameLogging(), "addBatch", sql); - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_cannotTakeArgumentsPreparedOrCallable")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_cannotTakeArgumentsPreparedOrCallable")); Object[] msgArgs = {"addBatch()"}; throw new SQLServerException(this, form.format(msgArgs), null, 0, false); } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java index afe0799bb..609dc7e13 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java @@ -1,17 +1,15 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; import java.util.ListResourceBundle; + /** - * A simple resource bundle containing the strings for localizing. + * Represents a simple resource bundle containing the strings for localizing. * */ public final class SQLServerResource extends ListResourceBundle { @@ -23,381 +21,517 @@ protected Object[][] getContents() { return contents; } - // the keys must be prefixed with R_ to denote they are resource strings and their names should follow the camelCasing + // the keys must be prefixed with R_ to denote they are resource strings and their names should follow the + // camelCasing // convention and be descriptive static final Object[][] contents = { - // LOCALIZE THIS - {"R_timedOutBeforeRouting", "The timeout expired before connecting to the routing destination."}, - {"R_invalidRoutingInfo", "Unexpected routing information received. Please check your connection properties and SQL Server configuration."}, - {"R_multipleRedirections", "Two or more redirections have occurred. Only one redirection per login attempt is allowed."}, - {"R_dbMirroringWithMultiSubnetFailover", "Connecting to a mirrored SQL Server instance using the multiSubnetFailover connection property is not supported."}, - {"R_dbMirroringWithReadOnlyIntent", "Connecting to a mirrored SQL Server instance using the ApplicationIntent ReadOnly connection property is not supported."}, - {"R_ipAddressLimitWithMultiSubnetFailover", "Connecting with the multiSubnetFailover connection property to a SQL Server instance configured with more than {0} IP addresses is not supported."}, - {"R_connectionTimedOut", "Connection timed out: no further information."}, - {"R_invalidPositionIndex", "The position index {0} is not valid."}, - {"R_invalidLength", "The length {0} is not valid."}, - {"R_unknownSSType", "Invalid SQL Server data type {0}."}, - {"R_unknownJDBCType", "Invalid JDBC data type {0}."}, - {"R_notSQLServer", "The driver received an unexpected pre-login response. Verify the connection properties and check that an instance of SQL Server is running on the host and accepting TCP/IP connections at the port. This driver can be used only with SQL Server 2005 or later."}, - {"R_tcpOpenFailed", "{0}. Verify the connection properties. Make sure that an instance of SQL Server is running on the host and accepting TCP/IP connections at the port. Make sure that TCP connections to the port are not blocked by a firewall."}, - {"R_unsupportedServerVersion", "SQL Server version {0} is not supported by this driver."}, - {"R_noServerResponse", "SQL Server did not return a response. The connection has been closed."}, - {"R_truncatedServerResponse", "SQL Server returned an incomplete response. The connection has been closed."}, - {"R_queryTimedOut", "The query has timed out."}, - {"R_queryCancelled", "The query was canceled."}, - {"R_errorReadingStream", "An error occurred while reading the value from the stream object. Error: \"{0}\""}, - {"R_streamReadReturnedInvalidValue", "The stream read operation returned an invalid value for the amount of data read."}, - {"R_mismatchedStreamLength", "The stream value is not the specified length. The specified length was {0}, the actual length is {1}."}, - {"R_notSupported", "This operation is not supported."}, - {"R_invalidOutputParameter", "The index {0} of the output parameter is not valid."}, - {"R_outputParameterNotRegisteredForOutput", "The output parameter {0} was not registered for output."}, - {"R_parameterNotDefinedForProcedure", "Parameter {0} was not defined for stored procedure {1}."}, - {"R_connectionIsClosed", "The connection is closed."}, - {"R_invalidBooleanValue", "The property {0} does not contain a valid boolean value. Only true or false can be used."}, - {"R_propertyMaximumExceedsChars", "The {0} property exceeds the maximum number of {1} characters."}, - {"R_invalidPortNumber", "The port number {0} is not valid."}, - {"R_invalidTimeOut", "The timeout {0} is not valid."}, - {"R_invalidLockTimeOut", "The lockTimeOut {0} is not valid."}, - {"R_invalidAuthenticationScheme", "The authenticationScheme {0} is not valid."}, - {"R_invalidPacketSize", "The packetSize {0} is not valid."}, - {"R_packetSizeTooBigForSSL", "SSL encryption cannot be used with a network packet size larger than {0} bytes. Please check your connection properties and SQL Server configuration."}, - {"R_tcpipConnectionFailed", "The TCP/IP connection to the host {0}, port {1} has failed. Error: \"{2}\"."}, //{PlaceHolder="TCP/IP"} - {"R_invalidTransactionLevel", "The transaction level {0} is not valid."}, - {"R_cantInvokeRollback", "Cannot invoke a rollback operation when the AutoCommit mode is set to \"true\"."}, - {"R_cantSetSavepoint", "Cannot set a savepoint when the AutoCommit mode is set to \"true\"."}, - {"R_sqlServerHoldability", "SQL Server supports holdability at the connection level only. Use the connection.setHoldability() method."}, //{PlaceHolder="connection.setHoldability()"} - {"R_invalidHoldability", "The holdability value {0} is not valid."}, - {"R_invalidColumnArrayLength", "The column array is not valid. Its length must be 1."}, - {"R_valueNotSetForParameter", "The value is not set for the parameter number {0}."}, - {"R_sqlBrowserFailed", "The connection to the host {0}, named instance {1} failed. Error: \"{2}\". Verify the server and instance names and check that no firewall is blocking UDP traffic to port 1434. For SQL Server 2005 or later, verify that the SQL Server Browser Service is running on the host."}, - {"R_notConfiguredToListentcpip", "The server {0} is not configured to listen with TCP/IP."}, - {"R_cantIdentifyTableMetadata", "Unable to identify the table {0} for the metadata."}, - {"R_metaDataErrorForParameter", "A metadata error for the parameter {0} occurred."}, - {"R_invalidParameterNumber", "The parameter number {0} is not valid."}, - {"R_noMetadata", "There is no metadata."}, - {"R_resultsetClosed", "The result set is closed."}, - {"R_invalidColumnName", "The column name {0} is not valid."}, - {"R_resultsetNotUpdatable", "The result set is not updatable."}, - {"R_indexOutOfRange", "The index {0} is out of range."}, - {"R_savepointNotNamed", "The savepoint is not named."}, - {"R_savepointNamed", "The savepoint {0} is named."}, - {"R_resultsetNoCurrentRow", "The result set has no current row."}, - {"R_mustBeOnInsertRow", "The cursor is not on the insert row."}, - {"R_mustNotBeOnInsertRow", "The requested operation is not valid on the insert row."}, - {"R_cantUpdateDeletedRow", "A deleted row cannot be updated."}, - {"R_noResultset", "The statement did not return a result set."}, - {"R_resultsetGeneratedForUpdate", "A result set was generated for update."}, - {"R_statementIsClosed", "The statement is closed."}, - {"R_invalidRowcount", "The maximum row count {0} for a result set must be non-negative."}, - {"R_invalidQueryTimeOutValue", "The query timeout value {0} is not valid."}, - {"R_invalidFetchDirection", "The fetch direction {0} is not valid."}, - {"R_invalidFetchSize", "The fetch size cannot be negative."}, - {"R_noColumnParameterValue", "No column parameter values were specified to update the row."}, - {"R_statementMustBeExecuted", "The statement must be executed before any results can be obtained."}, - {"R_modeSuppliedNotValid", "The supplied mode is not valid."}, - {"R_errorConnectionString", "The connection string contains a badly formed name or value."}, - {"R_errorProcessingComplexQuery", "An error occurred while processing the complex query."}, - {"R_invalidOffset", "The offset {0} is not valid."}, - {"R_nullConnection", "The connection URL is null."}, - {"R_invalidConnection", "The connection URL is invalid."}, - {"R_cannotTakeArgumentsPreparedOrCallable", "The method {0} cannot take arguments on a PreparedStatement or CallableStatement."}, - {"R_unsupportedConversionFromTo", "The conversion from {0} to {1} is unsupported."}, // Invalid conversion (e.g. MONEY to Timestamp) - {"R_unsupportedConversionTo", "The conversion to {0} is unsupported."}, // Invalid conversion to an unknown type - {"R_errorConvertingValue","An error occurred while converting the {0} value to JDBC data type {1}."}, // Data-dependent conversion failure (e.g. "foo" vs. "123", to Integer) - {"R_streamIsClosed", "The stream is closed."}, - {"R_invalidTDS", "The TDS protocol stream is not valid."}, - {"R_unexpectedToken", " Unexpected token {0}."}, - {"R_selectNotPermittedinBatch", "The SELECT statement is not permitted in a batch."}, - {"R_failedToCreateXAConnection", "Failed to create the XA control connection. Error: \"{0}\""}, - {"R_codePageNotSupported", "Codepage {0} is not supported by the Java environment."}, - {"R_unknownSortId", "SQL Server collation {0} is not supported by this driver."}, - {"R_unknownLCID", "Windows collation {0} is not supported by this driver."}, - {"R_encodingErrorWritingTDS", "An encoding error occurred while writing a string to the TDS buffer. Error: \"{0}\""}, - {"R_processingError", "A processing error \"{0}\" occurred."}, - {"R_requestedOpNotSupportedOnForward", "The requested operation is not supported on forward only result sets."}, - {"R_unsupportedCursor", "The cursor type is not supported."}, - {"R_unsupportedCursorOperation", "The requested operation is not supported with this cursor type."}, - {"R_unsupportedConcurrency", "The concurrency is not supported."}, - {"R_unsupportedCursorAndConcurrency", "The cursor type/concurrency combination is not supported."}, - {"R_stringReadError", "A string read error occurred at offset:{0}."}, - {"R_stringWriteError", "A string write error occurred at offset:{0}."}, - {"R_stringNotInHex", "The string is not in a valid hex format."}, - {"R_unknownType", "The Java type {0} is not a supported type."}, - {"R_physicalConnectionIsClosed", "The physical connection is closed for this pooled connection."}, - {"R_invalidDataSourceReference", "Invalid DataSource reference."}, - {"R_cantGetColumnValueFromDeletedRow", "Cannot get a value from a deleted row."}, - {"R_cantGetUpdatedColumnValue", "Updated columns cannot be accessed until updateRow() or cancelRowUpdates() has been called."}, - {"R_cantUpdateColumn","The column value cannot be updated."}, - {"R_positionedUpdatesNotSupported", "Positioned updates and deletes are not supported."}, - {"R_invalidAutoGeneratedKeys", "The autoGeneratedKeys parameter value {0} is not valid. Only the values Statement.RETURN_GENERATED_KEYS and Statement.NO_GENERATED_KEYS can be used."}, - {"R_notConfiguredForIntegrated", "This driver is not configured for integrated authentication."}, - {"R_failoverPartnerWithoutDB", "databaseName is required when using the failoverPartner connection property."}, - {"R_invalidPartnerConfiguration", "The database {0} on server {1} is not configured for database mirroring."}, - {"R_invaliddisableStatementPooling", "The disableStatementPooling value {0} is not valid."}, - {"R_invalidselectMethod", "The selectMethod {0} is not valid."}, - {"R_invalidpropertyValue", "The data type of connection property {0} is not valid. All the properties for this connection must be of String type."}, - {"R_invalidArgument", "The argument {0} is not valid."}, - {"R_streamWasNotMarkedBefore", "The stream has not been marked."}, - {"R_invalidresponseBuffering", "The responseBuffering connection property {0} is not valid."}, - {"R_invalidapplicationIntent", "The applicationIntent connection property {0} is not valid."}, - {"R_dataAlreadyAccessed", "The data has been accessed and is not available for this column or parameter."}, - {"R_outParamsNotPermittedinBatch", "The OUT and INOUT parameters are not permitted in a batch."}, - {"R_sslRequiredNoServerSupport", "The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer (SSL) encryption. The application requested encryption but the server is not configured to support SSL."}, - {"R_sslRequiredByServer", "SQL Server login requires an encrypted connection that uses Secure Sockets Layer (SSL)."}, - {"R_sslFailed", "The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer (SSL) encryption. Error: \"{0}\"."}, - {"R_certNameFailed", "Failed to validate the server name in a certificate during Secure Sockets Layer (SSL) initialization."}, - {"R_failedToInitializeXA", "Failed to initialize the stored procedure xp_sqljdbc_xa_init. The status is: {0}. Error: \"{1}\""}, - {"R_failedFunctionXA", "The function {0} failed. The status is: {1}. Error: \"{2}\""}, - {"R_noTransactionCookie", "The function {0} failed. No transaction cookie was returned."}, - {"R_failedToEnlist", "Failed to enlist. Error: \"{0}\""}, - {"R_failedToUnEnlist", "Failed to unenlist. Error: \"{0}\""}, - {"R_failedToReadRecoveryXIDs", "Failed to read recovery XA branch transaction IDs (XIDs). Error: \"{0}\""}, - {"R_userPropertyDescription", "The database user."}, - {"R_passwordPropertyDescription", "The database password."}, - {"R_databaseNamePropertyDescription", "The name of the database to connect to."}, - {"R_serverNamePropertyDescription", "The computer running SQL Server."}, - {"R_portNumberPropertyDescription", "The TCP port where an instance of SQL Server is listening."}, - {"R_serverSpnPropertyDescription", "SQL Server SPN."}, - {"R_columnEncryptionSettingPropertyDescription", "The column encryption setting."}, - {"R_serverNameAsACEPropertyDescription", "Translates the serverName from Unicode to ASCII Compatible Encoding (ACE), as defined by the ToASCII operation of RFC 3490."}, - {"R_sendStringParametersAsUnicodePropertyDescription", "Determines if the string parameters are sent to the server as Unicode or the database's character set."}, - {"R_multiSubnetFailoverPropertyDescription", "Indicates that the application is connecting to the Availability Group Listener of an Availability Group or Failover Cluster Instance."}, - {"R_applicationNamePropertyDescription", "The application name for SQL Server profiling and logging tools."}, - {"R_lastUpdateCountPropertyDescription", "Ensures that only the last update count is returned from an SQL statement passed to the server."}, - {"R_disableStatementPoolingPropertyDescription", "Disables the statement pooling feature."}, - {"R_integratedSecurityPropertyDescription", "Indicates whether Windows authentication will be used to connect to SQL Server."}, - {"R_authenticationSchemePropertyDescription", "The authentication scheme to be used for integrated authentication."}, - {"R_lockTimeoutPropertyDescription", "The number of milliseconds to wait before the database reports a lock time-out."}, - {"R_loginTimeoutPropertyDescription", "The number of seconds the driver should wait before timing out a failed connection."}, - {"R_instanceNamePropertyDescription", "The name of the SQL Server instance to connect to."}, - {"R_xopenStatesPropertyDescription", "Determines if the driver returns XOPEN-compliant SQL state codes in exceptions."}, - {"R_selectMethodPropertyDescription", "Enables the application to use server cursors to process forward only, read only result sets."}, - {"R_responseBufferingPropertyDescription", "Controls the adaptive buffering behavior to allow the application to process large result sets without requiring server cursors."}, - {"R_applicationIntentPropertyDescription", "Declares the application workload type when connecting to a server. Possible values are ReadOnly and ReadWrite."}, - {"R_workstationIDPropertyDescription", "The host name of the workstation."}, - {"R_failoverPartnerPropertyDescription", "The name of the failover server used in a database mirroring configuration."}, - {"R_packetSizePropertyDescription", "The network packet size used to communicate with SQL Server."}, - {"R_encryptPropertyDescription", "Determines if Secure Sockets Layer (SSL) encryption should be used between the client and the server."}, - {"R_trustServerCertificatePropertyDescription", "Determines if the driver should validate the SQL Server Secure Sockets Layer (SSL) certificate."}, - {"R_trustStoreTypePropertyDescription", "KeyStore type."}, - {"R_trustStorePropertyDescription", "The path to the certificate TrustStore file."}, - {"R_trustStorePasswordPropertyDescription", "The password used to check the integrity of the trust store data."}, - {"R_trustManagerClassPropertyDescription", "The class to instantiate as the TrustManager for SSL connections."}, - {"R_trustManagerConstructorArgPropertyDescription", "The optional argument to pass to the constructor specified by trustManagerClass."}, - {"R_hostNameInCertificatePropertyDescription", "The host name to be used when validating the SQL Server Secure Sockets Layer (SSL) certificate."}, - {"R_sendTimeAsDatetimePropertyDescription", "Determines whether to use the SQL Server datetime data type to send java.sql.Time values to the database."}, - {"R_TransparentNetworkIPResolutionPropertyDescription", "Determines whether to use the Transparent Network IP Resolution feature."}, - {"R_queryTimeoutPropertyDescription", "The number of seconds to wait before the database reports a query time-out."}, - {"R_socketTimeoutPropertyDescription", "The number of milliseconds to wait before the java.net.SocketTimeoutException is raised."}, - {"R_serverPreparedStatementDiscardThresholdPropertyDescription", "The threshold for when to close discarded prepare statements on the server (calling a batch of sp_unprepares). A value of 1 or less will cause sp_unprepare to be called immediately on PreparedStatment close."}, - {"R_enablePrepareOnFirstPreparedStatementCallPropertyDescription", "This setting specifies whether a prepared statement is prepared (sp_prepexec) on first use (property=true) or on second after first calling sp_executesql (property=false)."}, - {"R_statementPoolingCacheSizePropertyDescription", "This setting specifies the size of the prepared statement cache for a connection. A value less than 1 means no cache."}, - {"R_gsscredentialPropertyDescription", "Impersonated GSS Credential to access SQL Server."}, - {"R_noParserSupport", "An error occurred while instantiating the required parser. Error: \"{0}\""}, - {"R_writeOnlyXML", "Cannot read from this SQLXML instance. This instance is for writing data only."}, - {"R_dataHasBeenReadXML", "Cannot read from this SQLXML instance. The data has already been read."}, - {"R_readOnlyXML", "Cannot write to this SQLXML instance. This instance is for reading data only."}, - {"R_dataHasBeenSetXML", "Cannot write to this SQLXML instance. The data has already been set."}, - {"R_noDataXML", "No data has been set in this SQLXML instance."}, - {"R_cantSetNull", "Cannot set a null value."}, - {"R_failedToParseXML", "Failed to parse the XML. Error: \"{0}\""}, - {"R_isFreed", "This {0} object has been freed. It can no longer be accessed."}, - {"R_invalidProperty", "This property is not supported: {0}." }, - {"R_referencingFailedTSP", "The DataSource trustStore password needs to be set." }, - {"R_valueOutOfRange", "One or more values is out of range of values for the {0} SQL Server data type." }, - {"R_integratedAuthenticationFailed", "Integrated authentication failed."}, - {"R_permissionDenied", "Security violation. Permission to target \"{0}\" denied."}, - {"R_getSchemaError", "Error getting default schema name."}, - {"R_setSchemaWarning", "Warning: setSchema is a no-op in this driver version."}, - {"R_updateCountOutofRange", "The update count value is out of range."}, - {"R_limitOffsetNotSupported", "OFFSET clause in limit escape sequence is not supported."}, - {"R_limitEscapeSyntaxError", "Error in limit escape syntax. Failed to parse query."}, - {"R_featureNotSupported", "{0} is not supported."}, - {"R_zoneOffsetError", "Error in retrieving zone offset."}, - {"R_invalidMaxRows", "The supported maximum row count for a result set is Integer.MAX_VALUE or less."}, - {"R_schemaMismatch", "Source and destination schemas do not match."}, - {"R_invalidColumn", "Column {0} is invalid. Please check your column mappings."}, - {"R_invalidDestinationTable", "Destination table name is missing or invalid."}, - {"R_unableRetrieveColMeta", "Unable to retrieve column metadata."}, - {"R_invalidDestConnection", "Destination connection must be a connection from the Microsoft JDBC Driver for SQL Server."}, - {"R_unableRetrieveSourceData", "Unable to retrieve data from the source."}, - {"R_ParsingError", "Failed to parse data for the {0} type."}, - {"R_BulkTypeNotSupported", "Data type {0} is not supported in bulk copy."}, - {"R_invalidTransactionOption", "UseInternalTransaction option cannot be set to TRUE when used with a Connection object."}, - {"R_invalidNegativeArg", "The {0} argument cannot be negative."}, - {"R_BulkColumnMappingsIsEmpty", "Cannot perform bulk copy operation if the only mapping is an identity column and KeepIdentity is set to false."}, - {"R_DataSchemaMismatch", "Source data does not match source schema."}, - {"R_BulkDataDuplicateColumn", "Duplicate column names are not allowed."}, - {"R_invalidColumnOrdinal", "Column {0} is invalid. Column number should be greater than zero."}, - {"R_unsupportedEncoding", "The encoding {0} is not supported."}, - {"R_UnexpectedDescribeParamFormat", "Internal error. The format of the resultset returned by sp_describe_parameter_encryption is invalid. One of the resultsets is missing."}, - {"R_InvalidEncryptionKeyOridnal", "Internal error. The referenced column encryption key ordinal \"{0}\" is missing in the encryption metadata returned by sp_describe_parameter_encryption. Max ordinal is \"{1}\"."}, - {"R_MissingParamEncryptionMetadata", "Internal error. Metadata for some parameters in statement or procedure \"{0}\" is missing in the resultset returned by sp_describe_parameter_encryption."}, - {"R_UnableRetrieveParameterMetadata", "Unable to retrieve parameter encryption metadata."}, - {"R_InvalidCipherTextSize", "Specified ciphertext has an invalid size of {0} bytes, which is below the minimum {1} bytes required for decryption."}, - {"R_InvalidAlgorithmVersion","The specified ciphertext''s encryption algorithm version {0} does not match the expected encryption algorithm version {1} ."}, - {"R_InvalidAuthenticationTag", "Specified ciphertext has an invalid authentication tag. "}, - {"R_EncryptionFailed", "Internal error while encryption: {0} " }, - {"R_DecryptionFailed", "Internal error while decryption: {0} " }, - {"R_InvalidKeySize", "The column encryption key has been successfully decrypted but it''s length: {0} does not match the length: {1} for algorithm \"{2}\". Verify the encrypted value of the column encryption key in the database." }, - {"R_InvalidEncryptionType", "Encryption type {0} specified for the column in the database is either invalid or corrupted. Valid encryption types for algorithm {1} are: {2}." }, - {"R_UnknownColumnEncryptionAlgorithm", "The Algorithm {0} does not exist. Algorithms registered in the factory are {1}." }, - {"R_KeyExtractionFailed", "Key extraction failed : {0} ."}, - {"R_UntrustedKeyPath", "The column master key path {0} received from server {1} is not a trusted key path. The column master key path may be corrupt or you should set {0} as a trusted key path using SQLServerConnection.setColumnEncryptionTrustedMasterKeyPaths()."}, - {"R_UnrecognizedKeyStoreProviderName", "Failed to decrypt a column encryption key. Invalid key store provider name: {0}. A key store provider name must denote either a system key store provider or a registered custom key store provider. Valid system key provider names are: {1}. Valid (currently registered) custom key store provider names are: {2}. Please verify key store provider information in column master key definitions in the database, and verify all custom key store providers used in your application are registered properly."}, - {"R_UnsupportedDataTypeAE", "Encryption and decryption of data type {0} is not supported."}, - {"R_NormalizationErrorAE", "Decryption of the data type {0} failed. Normalization error."}, - {"R_UnsupportedNormalizationVersionAE", "Normalization version \"{0}\" received from SQL Server is either invalid or corrupted. Valid normalization versions are: {1}."}, - {"R_NullCipherTextAE", "Internal error. Ciphertext value cannot be null."}, - {"R_NullColumnEncryptionAlgorithmAE", "Internal error. Encryption algorithm cannot be null. Valid algorithms are: {1}."}, - {"R_CustomCipherAlgorithmNotSupportedAE", "Custom cipher algorithm not supported."}, - {"R_PlainTextNullAE", "Internal error. Plaintext value cannot be null."}, - {"R_StreamingDataTypeAE", "Data of length greater than {0} is not supported in encrypted {1} column."}, - {"R_AE_NotSupportedByServer","SQL Server instance in use does not support column encryption."}, - {"R_InvalidAEVersionNumber","Received invalid version number \"{0}\" for Always Encrypted."}, // From Server - {"R_NullEncryptedColumnEncryptionKey", "Internal error. Encrypted column encryption key cannot be null."}, - {"R_EmptyEncryptedColumnEncryptionKey", "Internal error. Empty encrypted column encryption key specified."}, - {"R_InvalidMasterKeyDetails", "Invalid master key details specified."}, - {"R_CertificateError", "Error occurred while retrieving certificate \"{0}\" from keystore \"{1}\"."}, - {"R_ByteToShortConversion", "Error occurred while decrypting column encryption key."}, - {"R_InvalidCertificateSignature", "The specified encrypted column encryption key signature does not match the signature computed with the column master key (certificate) in \"{0}\". The encrypted column encryption key may be corrupt, or the specified path may be incorrect."}, - {"R_CEKDecryptionFailed", "Exception while decryption of encrypted column encryption key: {0} "}, - {"R_NullKeyEncryptionAlgorithm", "Key encryption algorithm cannot be null."}, - {"R_NullKeyEncryptionAlgorithmInternal", "Internal error. Key encryption algorithm cannot be null."}, - {"R_InvalidKeyEncryptionAlgorithm", "Invalid key encryption algorithm specified: {0}. Expected value: {1}."}, - {"R_InvalidKeyEncryptionAlgorithmInternal", "Internal error. Invalid key encryption algorithm specified: {0}. Expected value: {1}."}, - {"R_NullColumnEncryptionKey", "Column encryption key cannot be null."}, - {"R_EmptyColumnEncryptionKey", "Empty column encryption key specified."}, - {"R_CertificateNotFoundForAlias", "Certificate with alias {0} not found in the store provided by {1}. Verify the certificate has been imported correctly into the certificate location/store."}, - {"R_UnrecoverableKeyAE", "Cannot recover private key from keystore with certificate details {0}. Verify that imported certificate for Always Encrypted contains private key and password provided for certificate is correct."}, - {"R_KeyStoreNotFound", "System cannot find the key store file at the specified path. Verify that the path is correct and you have proper permissions to access it."}, - {"R_CustomKeyStoreProviderMapNull", "Column encryption key store provider map cannot be null. Expecting a non-null value."}, - {"R_EmptyCustomKeyStoreProviderName", "Invalid key store provider name specified. Key store provider names cannot be null or empty."}, - {"R_InvalidCustomKeyStoreProviderName", "Invalid key store provider name {0}. {1} prefix is reserved for system key store providers."}, - {"R_CustomKeyStoreProviderValueNull", "Null reference specified for key store provider {0}. Expecting a non-null value."}, - {"R_CustomKeyStoreProviderSetOnce", "Key store providers cannot be set more than once."}, - {"R_unknownColumnEncryptionType", "Invalid column encryption type {0}."}, - {"R_unsupportedStmtColEncSetting", "SQLServerStatementColumnEncryptionSetting cannot be null."}, - {"R_unsupportedConversionAE", "The conversion from {0} to {1} is unsupported for encrypted column."}, - {"R_InvalidDataForAE", "The given value of type {0} from the data source cannot be converted to type {1} of the specified target column."}, - {"R_authenticationPropertyDescription", "The authentication to use."}, - {"R_accessTokenPropertyDescription", "The access token to use for Azure Active Directory."}, - {"R_FedAuthRequiredPreLoginResponseInvalidValue", "Server sent an unexpected value for FedAuthRequired PreLogin Option. Value was {0}."}, - {"R_FedAuthInfoLengthTooShortForCountOfInfoIds", "The FedAuthInfo token must at least contain 4 bytes indicating the number of info IDs."}, - {"R_FedAuthInfoInvalidOffset", "FedAuthInfoDataOffset points to an invalid location. Current dataOffset is {0}."}, - {"R_FedAuthInfoFailedToReadData", "Failed to read FedAuthInfoData."}, - {"R_FedAuthInfoLengthTooShortForData", "FEDAUTHINFO token stream is not long enough ({0}) to contain the data it claims to."}, - {"R_FedAuthInfoDoesNotContainStsurlAndSpn", "FEDAUTHINFO token stream does not contain both STSURL and SPN."}, - {"R_ADALExecution", "Failed to authenticate the user {0} in Active Directory (Authentication={1})."}, - {"R_UnrequestedFeatureAckReceived", "Unrequested feature acknowledge is received. Feature ID: {0}."}, - {"R_FedAuthFeatureAckContainsExtraData", "Federated authentication feature extension ack for ADAL and Security Token includes extra data."}, - {"R_FedAuthFeatureAckUnknownLibraryType", "Attempting to use unknown federated authentication library. Library ID: {0}."}, - {"R_UnknownFeatureAck", "Unknown feature acknowledge is received."}, - {"R_SetAuthenticationWhenIntegratedSecurityTrue", "Cannot set \"Authentication\" with \"IntegratedSecurity\" set to \"true\"."}, - {"R_SetAccesstokenWhenIntegratedSecurityTrue","Cannot set the AccessToken property if the \"IntegratedSecurity\" connection string keyword has been set to \"true\"."}, - {"R_IntegratedAuthenticationWithUserPassword", "Cannot use \"Authentication=ActiveDirectoryIntegrated\" with \"User\", \"UserName\" or \"Password\" connection string keywords."}, - {"R_AccessTokenWithUserPassword","Cannot set the AccessToken property if \"User\", \"UserName\" or \"Password\" has been specified in the connection string."}, - {"R_AccessTokenCannotBeEmpty","AccesToken cannot be empty."}, - {"R_SetBothAuthenticationAndAccessToken","Cannot set the AccessToken property if \"Authentication\" has been specified in the connection string."}, - {"R_NoUserPasswordForActivePassword","Both \"User\" (or \"UserName\") and \"Password\" connection string keywords must be specified, if \"Authentication=ActiveDirectoryPassword\"."}, - {"R_NoUserPasswordForSqlPassword","Both \"User\" (or \"UserName\") and \"Password\" connection string keywords must be specified, if \"Authentication=SqlPassword\"."}, - {"R_ForceEncryptionTrue_HonorAEFalse", "Cannot set Force Encryption to true for parameter {0} because enryption is not enabled for the statement or procedure {1}."}, - {"R_ForceEncryptionTrue_HonorAETrue_UnencryptedColumn", "Cannot execute statement or procedure {0} because Force Encryption was set as true for parameter {1} and the database expects this parameter to be sent as plaintext. This may be due to a configuration error."}, - {"R_ForceEncryptionTrue_HonorAEFalseRS", "Cannot set Force Encryption to true for parameter {0} because encryption is not enabled for the statement or procedure."}, - {"R_ForceEncryptionTrue_HonorAETrue_UnencryptedColumnRS", "Cannot execute update because Force Encryption was set as true for parameter {0} and the database expects this parameter to be sent as plaintext. This may be due to a configuration error."}, - {"R_NullValue","{0} cannot be null."}, - {"R_AKVPathNull", "Azure Key Vault key path cannot be null." }, - {"R_AKVURLInvalid", "Invalid URL specified: {0}." }, - {"R_AKVMasterKeyPathInvalid", "Invalid Azure Key Vault key path specified: {0}."}, - {"R_EmptyCEK","Empty column encryption key specified."}, - {"R_EncryptedCEKNull","Encrypted column encryption key cannot be null."}, - {"R_EmptyEncryptedCEK","Encrypted Column Encryption Key length should not be zero."}, - {"R_NonRSAKey","Cannot use a non-RSA key: {0}."}, - {"R_GetAKVKeySize","Unable to get the Azure Key Vault public key size in bytes."}, - {"R_InvalidEcryptionAlgorithmVersion","Specified encrypted column encryption key contains an invalid encryption algorithm version {0}. Expected version is {1}."}, - {"R_AKVKeyLengthError","The specified encrypted column encryption key''s ciphertext length: {0} does not match the ciphertext length: {1} when using column master key (Azure Key Vault key) in {2}. The encrypted column encryption key may be corrupt, or the specified Azure Key Vault key path may be incorrect."}, - {"R_AKVSignatureLengthError","The specified encrypted column encryption key''s signature length: {0} does not match the signature length: {1} when using column master key (Azure Key Vault key) in {2}. The encrypted column encryption key may be corrupt, or the specified Azure Key Vault key path may be incorrect."}, - {"R_HashNull","Hash should not be null while decrypting encrypted column encryption key."}, - {"R_NoSHA256Algorithm","SHA-256 Algorithm is not supported."}, - {"R_VerifySignature","Unable to verify signature of the column encryption key."}, - {"R_CEKSignatureNotMatchCMK","The specified encrypted column encryption key signature does not match the signature computed with the column master key (Asymmetric key in Azure Key Vault) in {0}. The encrypted column encryption key may be corrupt, or the specified path may be incorrect."}, - {"R_DecryptCEKError","Unable to decrypt column encryption key using specified Azure Key Vault key."}, - {"R_EncryptCEKError","Unable to encrypt column encryption key using specified Azure Key Vault key."}, - {"R_CipherTextLengthNotMatchRSASize","CipherText length does not match the RSA key size."}, - {"R_GenerateSignature","Unable to generate signature using a specified Azure Key Vault Key URL."}, - {"R_SignedHashLengthError","Signed hash length does not match the RSA key size."}, - {"R_InvalidSignatureComputed","Invalid signature of the encrypted column encryption key computed."}, - {"R_UnableLoadADALSqlDll","Unable to load adalsql.dll. Error code: 0x{0}. For details, see: http://go.microsoft.com/fwlink/?LinkID=513072"}, - {"R_ADALAuthenticationMiddleErrorMessage","Error code 0x{0}; state {1}."}, - {"R_unsupportedDataTypeTVP", "Data type {0} not supported in Table-Valued Parameter."}, - {"R_moreDataInRowThanColumnInTVP", "Input array is longer than the number of columns in this table."}, - {"R_invalidTVPName"," The Table-Valued Parameter must have a valid type name."}, - {"R_invalidThreePartName","Invalid 3 part name format for TypeName."}, - {"R_unsupportedConversionTVP", "The conversion from {0} to {1} is unsupported for Table-Valued Parameter."}, - {"R_TVPMixedSource", "Cannot add column metadata. This Table-Valued Parameter has a ResultSet from which metadata will be derived."}, - {"R_TVPEmptyMetadata", "There are not enough fields in the Structured type. Structured types must have at least one field."}, - {"R_TVPInvalidValue", "The value provided for Table-Valued Parameter {0} is not valid. Only SQLServerDataTable, ResultSet and ISQLServerDataRecord objects are supported."}, - {"R_TVPInvalidColumnValue", "Input data is not in correct format."}, - {"R_TVPSortOrdinalGreaterThanFieldCount", "The sort ordinal {0} on field {1} exceeds the total number of fields."}, - {"R_TVPMissingSortOrderOrOrdinal", "The sort order and ordinal must either both be specified, or neither should be specified (SortOrder.Unspecified and -1). The values given were: order = {0}, ordinal = {1}."}, - {"R_TVPDuplicateSortOrdinal", "The sort ordinal {0} was specified twice."}, - {"R_TVPMissingSortOrdinal", "The sort ordinal {0} was not specified."}, - {"R_TVPDuplicateColumnName","A column name {0} already belongs to this SQLServerDataTable."}, - {"R_InvalidConnectionSetting", "The {0} value \"{1}\" is not valid."}, // This is used for connection settings. {0}-> property name as is, {1}-> value - {"R_InvalidWindowsCertificateStoreEncryption", "Cannot encrypt a column encryption key with the Windows Certificate Store."}, - {"R_AEKeypathEmpty", "Internal error. Certificate path cannot be null. Use the following format: \"certificate location/certificate store/certificate thumbprint\", where \"certificate location\" is either LocalMachine or CurrentUser."}, - {"R_AEWinApiErr", "Windows Api native error."}, - {"R_AECertpathBad", "Internal error. Invalid certificate path: {0}. Use the following format: \"certificate location/certificate store/certificate thumbprint\", where \"certificate location\" is either LocalMachine or CurrentUser."}, - {"R_AECertLocBad", "Internal error. Invalid certificate location {0} in certificate path {1}. Use the following format: \"certificate location/certificate store/certificate thumbprint\", where \"certificate location\" is either LocalMachine or CurrentUser."}, - {"R_AECertStoreBad", "Internal error. Invalid certificate store {0} specified in certificate path {1}. Expected value: My."}, - {"R_AECertHashEmpty", "Internal error. Empty certificate thumbprint specified in certificate path {0}."}, - {"R_AECertNotFound", "Certificate with thumbprint {2} not found in certificate store {1} in certificate location {0}. Verify the certificate path in the column master key definition in the database is correct, and the certificate has been imported correctly into the certificate location/store."}, - {"R_AEMaloc", "Memory allocation failure."}, - {"R_AEKeypathLong", "Internal error. Specified certificate path has {0} bytes, which exceeds maximum length of {1} bytes."}, - {"R_AEECEKLenBad", "The specified encrypted column encryption key''s ciphertext length: {0} does not match the ciphertext length: {1} when using column master key (certificate) in \"{2}\". The encrypted column encryption key may be corrupt, or the specified certificate path may be incorrect."}, - {"R_AEECEKSigLenBad", "The specified encrypted column encryption key''s signature length {0} does not match the length {1} when using the column master key (certificate) in \"{2}\". The encrypted column encryption key may be corrupt, or the specified certificate path may be incorrect."}, - {"R_AEKeyPathEmptyOrReserved","The certificate path \"{0}\" is invalid; it is empty or contains reserved directory names."}, - {"R_AEKeyPathCurUser","CurrentUser was specified in key path but an error occurred obtaining the current user''s initial working directory."}, - {"R_AEKeyFileOpenError","Error opening certificate file {0}."}, - {"R_AEKeyFileReadError","Error reading certificate file {0}."}, - {"R_keyStoreAuthenticationPropertyDescription", "The name that identifies a key store."}, - {"R_keyStoreSecretPropertyDescription", "The authentication secret or information needed to locate the secret."}, - {"R_keyStoreLocationPropertyDescription", "The key store location."}, - {"R_keyStoreAuthenticationNotSet", "\"keyStoreAuthentication\" connection string keyword must be specified, if \"{0}\" is specified."}, - {"R_keyStoreSecretOrLocationNotSet", "Both \"keyStoreSecret\" and \"keyStoreLocation\" must be set, if \"keyStoreAuthentication=JavaKeyStorePassword\" has been specified in the connection string."}, - {"R_certificateStoreInvalidKeyword", "Cannot set \"keyStoreSecret\", if \"keyStoreAuthentication=CertificateStore\" has been specified in the connection string."}, - {"R_certificateStoreLocationNotSet", "\"keyStoreLocation\" must be specified, if \"keyStoreAuthentication=CertificateStore\" has been specified in the connection string."}, - {"R_certificateStorePlatformInvalid", "Cannot set \"keyStoreAuthentication=CertificateStore\" on a Windows operating system."}, - {"R_invalidKeyStoreFile", "Cannot parse \"{0}\". Either the file format is not valid or the password is not correct."}, // for JKS/PKCS - {"R_invalidCEKCacheTtl", "Invalid column encryption key cache time-to-live specified. The columnEncryptionKeyCacheTtl value cannot be negative and timeUnit can only be DAYS, HOURS, MINUTES or SECONDS."}, - {"R_sendTimeAsDateTimeForAE", "Use sendTimeAsDateTime=false with Always Encrypted."}, - {"R_TVPnotWorkWithSetObjectResultSet", "setObject() with ResultSet is not supported for Table-Valued Parameter. Please use setStructured()."}, - {"R_invalidQueryTimeout", "The queryTimeout {0} is not valid."}, - {"R_invalidSocketTimeout", "The socketTimeout {0} is not valid."}, - {"R_fipsPropertyDescription", "Determines if FIPS mode is enabled."}, - {"R_invalidFipsConfig", "Unable to verify FIPS mode settings."}, - {"R_serverPreparedStatementDiscardThreshold", "The serverPreparedStatementDiscardThreshold {0} is not valid."}, - {"R_statementPoolingCacheSize", "The statementPoolingCacheSize {0} is not valid."}, - {"R_kerberosLoginFailedForUsername", "Cannot login with Kerberos principal {0}, check your credentials. {1}"}, - {"R_kerberosLoginFailed", "Kerberos Login failed: {0} due to {1} ({2})"}, - {"R_StoredProcedureNotFound", "Could not find stored procedure ''{0}''."}, - {"R_jaasConfigurationNamePropertyDescription", "Login configuration file for Kerberos authentication."}, - {"R_AKVKeyNotFound", "Key not found: {0}"}, - {"R_SQLVariantSupport", "SQL_VARIANT is not supported in versions of SQL Server before 2008."}, - {"R_invalidProbbytes", "SQL_VARIANT: invalid probBytes for {0} type."}, - {"R_invalidStringValue", "SQL_VARIANT does not support string values of length greater than 8000."}, - {"R_invalidValueForTVPWithSQLVariant", "Use of TVPs containing null sql_variant columns is not supported."}, - {"R_invalidDataTypeSupportForSQLVariant", "Unexpected TDS type ' '{0}' ' in SQL_VARIANT."}, - {"R_sslProtocolPropertyDescription", "SSL protocol label from TLS, TLSv1, TLSv1.1, and TLSv1.2. The default is TLS."}, - {"R_invalidSSLProtocol", "SSL Protocol {0} label is not valid. Only TLS, TLSv1, TLSv1.1, and TLSv1.2 are supported."}, - {"R_cancelQueryTimeoutPropertyDescription", "The number of seconds to wait to cancel sending a query timeout."}, - {"R_invalidCancelQueryTimeout", "The cancel timeout value {0} is not valid."}, - {"R_useBulkCopyForBatchInsertPropertyDescription", "Whether the driver will use bulk copy API for batch insert operations"}, - {"R_UnknownDataClsTokenNumber", "Unknown token for Data Classification."}, // From Server - {"R_InvalidDataClsVersionNumber", "Invalid version number {0} for Data Classification."}, // From Server - {"R_unknownUTF8SupportValue", "Unknown value for UTF8 support."}, - {"R_illegalWKT", "Illegal Well-Known text. Please make sure Well-Known text is valid."}, - {"R_illegalTypeForGeometry", "{0} is not supported for Geometry."}, - {"R_illegalWKTposition", "Illegal character in Well-Known text at position {0}."}, - }; + // LOCALIZE THIS + {"R_timedOutBeforeRouting", "The timeout expired before connecting to the routing destination."}, + {"R_invalidRoutingInfo", + "Unexpected routing information received. Please check your connection properties and SQL Server configuration."}, + {"R_multipleRedirections", + "Two or more redirections have occurred. Only one redirection per login attempt is allowed."}, + {"R_dbMirroringWithMultiSubnetFailover", + "Connecting to a mirrored SQL Server instance using the multiSubnetFailover connection property is not supported."}, + {"R_dbMirroringWithReadOnlyIntent", + "Connecting to a mirrored SQL Server instance using the ApplicationIntent ReadOnly connection property is not supported."}, + {"R_ipAddressLimitWithMultiSubnetFailover", + "Connecting with the multiSubnetFailover connection property to a SQL Server instance configured with more than {0} IP addresses is not supported."}, + {"R_connectionTimedOut", "Connection timed out: no further information."}, + {"R_invalidPositionIndex", "The position index {0} is not valid."}, + {"R_invalidLength", "The length {0} is not valid."}, + {"R_unknownSSType", "Invalid SQL Server data type {0}."}, + {"R_unknownJDBCType", "Invalid JDBC data type {0}."}, + {"R_notSQLServer", + "The driver received an unexpected pre-login response. Verify the connection properties and check that an instance of SQL Server is running on the host and accepting TCP/IP connections at the port. This driver can be used only with SQL Server 2005 or later."}, + {"R_tcpOpenFailed", + "{0}. Verify the connection properties. Make sure that an instance of SQL Server is running on the host and accepting TCP/IP connections at the port. Make sure that TCP connections to the port are not blocked by a firewall."}, + {"R_unsupportedServerVersion", "SQL Server version {0} is not supported by this driver."}, + {"R_noServerResponse", "SQL Server did not return a response. The connection has been closed."}, + {"R_truncatedServerResponse", + "SQL Server returned an incomplete response. The connection has been closed."}, + {"R_queryTimedOut", "The query has timed out."}, {"R_queryCancelled", "The query was canceled."}, + {"R_errorReadingStream", + "An error occurred while reading the value from the stream object. Error: \"{0}\""}, + {"R_streamReadReturnedInvalidValue", + "The stream read operation returned an invalid value for the amount of data read."}, + {"R_mismatchedStreamLength", + "The stream value is not the specified length. The specified length was {0}, the actual length is {1}."}, + {"R_notSupported", "This operation is not supported."}, + {"R_invalidOutputParameter", "The index {0} of the output parameter is not valid."}, + {"R_outputParameterNotRegisteredForOutput", "The output parameter {0} was not registered for output."}, + {"R_parameterNotDefinedForProcedure", "Parameter {0} was not defined for stored procedure {1}."}, + {"R_connectionIsClosed", "The connection is closed."}, + {"R_invalidBooleanValue", + "The property {0} does not contain a valid boolean value. Only true or false can be used."}, + {"R_propertyMaximumExceedsChars", "The {0} property exceeds the maximum number of {1} characters."}, + {"R_invalidPortNumber", "The port number {0} is not valid."}, + {"R_invalidTimeOut", "The timeout {0} is not valid."}, + {"R_invalidLockTimeOut", "The lockTimeOut {0} is not valid."}, + {"R_invalidAuthenticationScheme", "The authenticationScheme {0} is not valid."}, + {"R_invalidPacketSize", "The packetSize {0} is not valid."}, + {"R_packetSizeTooBigForSSL", + "SSL encryption cannot be used with a network packet size larger than {0} bytes. Please check your connection properties and SQL Server configuration."}, + {"R_tcpipConnectionFailed", "The TCP/IP connection to the host {0}, port {1} has failed. Error: \"{2}\"."}, // {PlaceHolder="TCP/IP"} + {"R_invalidTransactionLevel", "The transaction level {0} is not valid."}, + {"R_cantInvokeRollback", "Cannot invoke a rollback operation when the AutoCommit mode is set to \"true\"."}, + {"R_cantSetSavepoint", "Cannot set a savepoint when the AutoCommit mode is set to \"true\"."}, + {"R_sqlServerHoldability", + "SQL Server supports holdability at the connection level only. Use the connection.setHoldability() method."}, // {PlaceHolder="connection.setHoldability()"} + {"R_invalidHoldability", "The holdability value {0} is not valid."}, + {"R_invalidColumnArrayLength", "The column array is not valid. Its length must be 1."}, + {"R_valueNotSetForParameter", "The value is not set for the parameter number {0}."}, + {"R_sqlBrowserFailed", + "The connection to the host {0}, named instance {1} failed. Error: \"{2}\". Verify the server and instance names and check that no firewall is blocking UDP traffic to port 1434. For SQL Server 2005 or later, verify that the SQL Server Browser Service is running on the host."}, + {"R_notConfiguredToListentcpip", "The server {0} is not configured to listen with TCP/IP."}, + {"R_cantIdentifyTableMetadata", "Unable to identify the table {0} for the metadata."}, + {"R_metaDataErrorForParameter", "A metadata error for the parameter {0} occurred."}, + {"R_invalidParameterNumber", "The parameter number {0} is not valid."}, + {"R_noMetadata", "There is no metadata."}, {"R_resultsetClosed", "The result set is closed."}, + {"R_invalidColumnName", "The column name {0} is not valid."}, + {"R_resultsetNotUpdatable", "The result set is not updatable."}, + {"R_indexOutOfRange", "The index {0} is out of range."}, + {"R_savepointNotNamed", "The savepoint is not named."}, {"R_savepointNamed", "The savepoint {0} is named."}, + {"R_resultsetNoCurrentRow", "The result set has no current row."}, + {"R_mustBeOnInsertRow", "The cursor is not on the insert row."}, + {"R_mustNotBeOnInsertRow", "The requested operation is not valid on the insert row."}, + {"R_cantUpdateDeletedRow", "A deleted row cannot be updated."}, + {"R_noResultset", "The statement did not return a result set."}, + {"R_resultsetGeneratedForUpdate", "A result set was generated for update."}, + {"R_statementIsClosed", "The statement is closed."}, + {"R_invalidRowcount", "The maximum row count {0} for a result set must be non-negative."}, + {"R_invalidQueryTimeOutValue", "The query timeout value {0} is not valid."}, + {"R_invalidFetchDirection", "The fetch direction {0} is not valid."}, + {"R_invalidFetchSize", "The fetch size cannot be negative."}, + {"R_noColumnParameterValue", "No column parameter values were specified to update the row."}, + {"R_statementMustBeExecuted", "The statement must be executed before any results can be obtained."}, + {"R_modeSuppliedNotValid", "The supplied mode is not valid."}, + {"R_errorConnectionString", "The connection string contains a badly formed name or value."}, + {"R_errorProcessingComplexQuery", "An error occurred while processing the complex query."}, + {"R_invalidOffset", "The offset {0} is not valid."}, {"R_nullConnection", "The connection URL is null."}, + {"R_invalidConnection", "The connection URL is invalid."}, + {"R_cannotTakeArgumentsPreparedOrCallable", + "The method {0} cannot take arguments on a PreparedStatement or CallableStatement."}, + // Invalid conversion (e.g. MONEY to Timestamp) + {"R_unsupportedConversionFromTo", "The conversion from {0} to {1} is unsupported."}, + // Invalid conversion to an unknown type + {"R_unsupportedConversionTo", "The conversion to {0} is unsupported."}, + // Data-dependent conversion failure (e.g. "foo" vs. "123", to Integer) + {"R_errorConvertingValue", "An error occurred while converting the {0} value to JDBC data type {1}."}, + {"R_streamIsClosed", "The stream is closed."}, {"R_invalidTDS", "The TDS protocol stream is not valid."}, + {"R_unexpectedToken", " Unexpected token {0}."}, + {"R_selectNotPermittedinBatch", "The SELECT statement is not permitted in a batch."}, + {"R_failedToCreateXAConnection", "Failed to create the XA control connection. Error: \"{0}\""}, + {"R_codePageNotSupported", "Codepage {0} is not supported by the Java environment."}, + {"R_unknownSortId", "SQL Server collation {0} is not supported by this driver."}, + {"R_unknownLCID", "Windows collation {0} is not supported by this driver."}, + {"R_encodingErrorWritingTDS", + "An encoding error occurred while writing a string to the TDS buffer. Error: \"{0}\""}, + {"R_processingError", "A processing error \"{0}\" occurred."}, + {"R_requestedOpNotSupportedOnForward", + "The requested operation is not supported on forward only result sets."}, + {"R_unsupportedCursor", "The cursor type is not supported."}, + {"R_unsupportedCursorOperation", "The requested operation is not supported with this cursor type."}, + {"R_unsupportedConcurrency", "The concurrency is not supported."}, + {"R_unsupportedCursorAndConcurrency", "The cursor type/concurrency combination is not supported."}, + {"R_stringReadError", "A string read error occurred at offset:{0}."}, + {"R_stringWriteError", "A string write error occurred at offset:{0}."}, + {"R_stringNotInHex", "The string is not in a valid hex format."}, + {"R_unknownType", "The Java type {0} is not a supported type."}, + {"R_physicalConnectionIsClosed", "The physical connection is closed for this pooled connection."}, + {"R_invalidDataSourceReference", "Invalid DataSource reference."}, + {"R_cantGetColumnValueFromDeletedRow", "Cannot get a value from a deleted row."}, + {"R_cantGetUpdatedColumnValue", + "Updated columns cannot be accessed until updateRow() or cancelRowUpdates() has been called."}, + {"R_cantUpdateColumn", "The column value cannot be updated."}, + {"R_positionedUpdatesNotSupported", "Positioned updates and deletes are not supported."}, + {"R_invalidAutoGeneratedKeys", + "The autoGeneratedKeys parameter value {0} is not valid. Only the values Statement.RETURN_GENERATED_KEYS and Statement.NO_GENERATED_KEYS can be used."}, + {"R_notConfiguredForIntegrated", "This driver is not configured for integrated authentication."}, + {"R_failoverPartnerWithoutDB", + "databaseName is required when using the failoverPartner connection property."}, + {"R_invalidPartnerConfiguration", + "The database {0} on server {1} is not configured for database mirroring."}, + {"R_invaliddisableStatementPooling", "The disableStatementPooling value {0} is not valid."}, + {"R_invalidselectMethod", "The selectMethod {0} is not valid."}, + {"R_invalidpropertyValue", + "The data type of connection property {0} is not valid. All the properties for this connection must be of String type."}, + {"R_invalidArgument", "The argument {0} is not valid."}, + {"R_streamWasNotMarkedBefore", "The stream has not been marked."}, + {"R_invalidresponseBuffering", "The responseBuffering connection property {0} is not valid."}, + {"R_invalidapplicationIntent", "The applicationIntent connection property {0} is not valid."}, + {"R_dataAlreadyAccessed", "The data has been accessed and is not available for this column or parameter."}, + {"R_outParamsNotPermittedinBatch", "The OUT and INOUT parameters are not permitted in a batch."}, + {"R_sslRequiredNoServerSupport", + "The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer (SSL) encryption. The application requested encryption but the server is not configured to support SSL."}, + {"R_sslRequiredByServer", + "SQL Server login requires an encrypted connection that uses Secure Sockets Layer (SSL)."}, + {"R_sslFailed", + "The driver could not establish a secure connection to SQL Server by using Secure Sockets Layer (SSL) encryption. Error: \"{0}\"."}, + {"R_certNameFailed", + "Failed to validate the server name in a certificate during Secure Sockets Layer (SSL) initialization."}, + {"R_failedToInitializeXA", + "Failed to initialize the stored procedure xp_sqljdbc_xa_init. The status is: {0}. Error: \"{1}\""}, + {"R_failedFunctionXA", "The function {0} failed. The status is: {1}. Error: \"{2}\""}, + {"R_noTransactionCookie", "The function {0} failed. No transaction cookie was returned."}, + {"R_failedToEnlist", "Failed to enlist. Error: \"{0}\""}, + {"R_failedToUnEnlist", "Failed to unenlist. Error: \"{0}\""}, + {"R_failedToReadRecoveryXIDs", "Failed to read recovery XA branch transaction IDs (XIDs). Error: \"{0}\""}, + {"R_userPropertyDescription", "The database user."}, + {"R_passwordPropertyDescription", "The database password."}, + {"R_databaseNamePropertyDescription", "The name of the database to connect to."}, + {"R_serverNamePropertyDescription", "The computer running SQL Server."}, + {"R_portNumberPropertyDescription", "The TCP port where an instance of SQL Server is listening."}, + {"R_serverSpnPropertyDescription", "SQL Server SPN."}, + {"R_columnEncryptionSettingPropertyDescription", "The column encryption setting."}, + {"R_serverNameAsACEPropertyDescription", + "Translates the serverName from Unicode to ASCII Compatible Encoding (ACE), as defined by the ToASCII operation of RFC 3490."}, + {"R_sendStringParametersAsUnicodePropertyDescription", + "Determines if the string parameters are sent to the server as Unicode or the database's character set."}, + {"R_multiSubnetFailoverPropertyDescription", + "Indicates that the application is connecting to the Availability Group Listener of an Availability Group or Failover Cluster Instance."}, + {"R_applicationNamePropertyDescription", + "The application name for SQL Server profiling and logging tools."}, + {"R_lastUpdateCountPropertyDescription", + "Ensures that only the last update count is returned from an SQL statement passed to the server."}, + {"R_disableStatementPoolingPropertyDescription", "Disables the statement pooling feature."}, + {"R_integratedSecurityPropertyDescription", + "Indicates whether Windows authentication will be used to connect to SQL Server."}, + {"R_authenticationSchemePropertyDescription", + "The authentication scheme to be used for integrated authentication."}, + {"R_lockTimeoutPropertyDescription", + "The number of milliseconds to wait before the database reports a lock time-out."}, + {"R_loginTimeoutPropertyDescription", + "The number of seconds the driver should wait before timing out a failed connection."}, + {"R_instanceNamePropertyDescription", "The name of the SQL Server instance to connect to."}, + {"R_xopenStatesPropertyDescription", + "Determines if the driver returns XOPEN-compliant SQL state codes in exceptions."}, + {"R_selectMethodPropertyDescription", + "Enables the application to use server cursors to process forward only, read only result sets."}, + {"R_responseBufferingPropertyDescription", + "Controls the adaptive buffering behavior to allow the application to process large result sets without requiring server cursors."}, + {"R_applicationIntentPropertyDescription", + "Declares the application workload type when connecting to a server. Possible values are ReadOnly and ReadWrite."}, + {"R_workstationIDPropertyDescription", "The host name of the workstation."}, + {"R_failoverPartnerPropertyDescription", + "The name of the failover server used in a database mirroring configuration."}, + {"R_packetSizePropertyDescription", "The network packet size used to communicate with SQL Server."}, + {"R_encryptPropertyDescription", + "Determines if Secure Sockets Layer (SSL) encryption should be used between the client and the server."}, + {"R_trustServerCertificatePropertyDescription", + "Determines if the driver should validate the SQL Server Secure Sockets Layer (SSL) certificate."}, + {"R_trustStoreTypePropertyDescription", "KeyStore type."}, + {"R_trustStorePropertyDescription", "The path to the certificate TrustStore file."}, + {"R_trustStorePasswordPropertyDescription", + "The password used to check the integrity of the trust store data."}, + {"R_trustManagerClassPropertyDescription", + "The class to instantiate as the TrustManager for SSL connections."}, + {"R_trustManagerConstructorArgPropertyDescription", + "The optional argument to pass to the constructor specified by trustManagerClass."}, + {"R_hostNameInCertificatePropertyDescription", + "The host name to be used when validating the SQL Server Secure Sockets Layer (SSL) certificate."}, + {"R_sendTimeAsDatetimePropertyDescription", + "Determines whether to use the SQL Server datetime data type to send java.sql.Time values to the database."}, + {"R_TransparentNetworkIPResolutionPropertyDescription", + "Determines whether to use the Transparent Network IP Resolution feature."}, + {"R_queryTimeoutPropertyDescription", + "The number of seconds to wait before the database reports a query time-out."}, + {"R_socketTimeoutPropertyDescription", + "The number of milliseconds to wait before the java.net.SocketTimeoutException is raised."}, + {"R_serverPreparedStatementDiscardThresholdPropertyDescription", + "The threshold for when to close discarded prepare statements on the server (calling a batch of sp_unprepares). A value of 1 or less will cause sp_unprepare to be called immediately on PreparedStatment close."}, + {"R_enablePrepareOnFirstPreparedStatementCallPropertyDescription", + "This setting specifies whether a prepared statement is prepared (sp_prepexec) on first use (property=true) or on second after first calling sp_executesql (property=false)."}, + {"R_statementPoolingCacheSizePropertyDescription", + "This setting specifies the size of the prepared statement cache for a connection. A value less than 1 means no cache."}, + {"R_gsscredentialPropertyDescription", "Impersonated GSS Credential to access SQL Server."}, + {"R_noParserSupport", "An error occurred while instantiating the required parser. Error: \"{0}\""}, + {"R_writeOnlyXML", "Cannot read from this SQLXML instance. This instance is for writing data only."}, + {"R_dataHasBeenReadXML", "Cannot read from this SQLXML instance. The data has already been read."}, + {"R_readOnlyXML", "Cannot write to this SQLXML instance. This instance is for reading data only."}, + {"R_dataHasBeenSetXML", "Cannot write to this SQLXML instance. The data has already been set."}, + {"R_noDataXML", "No data has been set in this SQLXML instance."}, + {"R_cantSetNull", "Cannot set a null value."}, + {"R_failedToParseXML", "Failed to parse the XML. Error: \"{0}\""}, + {"R_isFreed", "This {0} object has been freed. It can no longer be accessed."}, + {"R_invalidProperty", "This property is not supported: {0}."}, + {"R_referencingFailedTSP", "The DataSource trustStore password needs to be set."}, + {"R_valueOutOfRange", "One or more values is out of range of values for the {0} SQL Server data type."}, + {"R_integratedAuthenticationFailed", "Integrated authentication failed."}, + {"R_permissionDenied", "Security violation. Permission to target \"{0}\" denied."}, + {"R_getSchemaError", "Error getting default schema name."}, + {"R_setSchemaWarning", "Warning: setSchema is a no-op in this driver version."}, + {"R_updateCountOutofRange", "The update count value is out of range."}, + {"R_limitOffsetNotSupported", "OFFSET clause in limit escape sequence is not supported."}, + {"R_limitEscapeSyntaxError", "Error in limit escape syntax. Failed to parse query."}, + {"R_featureNotSupported", "{0} is not supported."}, + {"R_zoneOffsetError", "Error in retrieving zone offset."}, + {"R_invalidMaxRows", "The supported maximum row count for a result set is Integer.MAX_VALUE or less."}, + {"R_schemaMismatch", "Source and destination schemas do not match."}, + {"R_invalidColumn", "Column {0} is invalid. Please check your column mappings."}, + {"R_invalidDestinationTable", "Destination table name is missing or invalid."}, + {"R_unableRetrieveColMeta", "Unable to retrieve column metadata."}, + {"R_invalidDestConnection", + "Destination connection must be a connection from the Microsoft JDBC Driver for SQL Server."}, + {"R_unableRetrieveSourceData", "Unable to retrieve data from the source."}, + {"R_ParsingError", "Failed to parse data for the {0} type."}, + {"R_BulkTypeNotSupported", "Data type {0} is not supported in bulk copy."}, + {"R_invalidTransactionOption", + "UseInternalTransaction option cannot be set to TRUE when used with a Connection object."}, + {"R_invalidNegativeArg", "The {0} argument cannot be negative."}, + {"R_BulkColumnMappingsIsEmpty", + "Cannot perform bulk copy operation if the only mapping is an identity column and KeepIdentity is set to false."}, + {"R_DataSchemaMismatch", "Source data does not match source schema."}, + {"R_BulkDataDuplicateColumn", "Duplicate column names are not allowed."}, + {"R_invalidColumnOrdinal", "Column {0} is invalid. Column number should be greater than zero."}, + {"R_unsupportedEncoding", "The encoding {0} is not supported."}, + {"R_UnexpectedDescribeParamFormat", + "Internal error. The format of the resultset returned by sp_describe_parameter_encryption is invalid. One of the resultsets is missing."}, + {"R_InvalidEncryptionKeyOridnal", + "Internal error. The referenced column encryption key ordinal \"{0}\" is missing in the encryption metadata returned by sp_describe_parameter_encryption. Max ordinal is \"{1}\"."}, + {"R_MissingParamEncryptionMetadata", + "Internal error. Metadata for some parameters in statement or procedure \"{0}\" is missing in the resultset returned by sp_describe_parameter_encryption."}, + {"R_UnableRetrieveParameterMetadata", "Unable to retrieve parameter encryption metadata."}, + {"R_InvalidCipherTextSize", + "Specified ciphertext has an invalid size of {0} bytes, which is below the minimum {1} bytes required for decryption."}, + {"R_InvalidAlgorithmVersion", + "The specified ciphertext''s encryption algorithm version {0} does not match the expected encryption algorithm version {1} ."}, + {"R_InvalidAuthenticationTag", "Specified ciphertext has an invalid authentication tag. "}, + {"R_EncryptionFailed", "Internal error while encryption: {0} "}, + {"R_DecryptionFailed", "Internal error while decryption: {0} "}, + {"R_InvalidKeySize", + "The column encryption key has been successfully decrypted but it''s length: {0} does not match the length: {1} for algorithm \"{2}\". Verify the encrypted value of the column encryption key in the database."}, + {"R_InvalidEncryptionType", + "Encryption type {0} specified for the column in the database is either invalid or corrupted. Valid encryption types for algorithm {1} are: {2}."}, + {"R_UnknownColumnEncryptionAlgorithm", + "The Algorithm {0} does not exist. Algorithms registered in the factory are {1}."}, + {"R_KeyExtractionFailed", "Key extraction failed : {0} ."}, + {"R_UntrustedKeyPath", + "The column master key path {0} received from server {1} is not a trusted key path. The column master key path may be corrupt or you should set {0} as a trusted key path using SQLServerConnection.setColumnEncryptionTrustedMasterKeyPaths()."}, + {"R_UnrecognizedKeyStoreProviderName", + "Failed to decrypt a column encryption key. Invalid key store provider name: {0}. A key store provider name must denote either a system key store provider or a registered custom key store provider. Valid system key provider names are: {1}. Valid (currently registered) custom key store provider names are: {2}. Please verify key store provider information in column master key definitions in the database, and verify all custom key store providers used in your application are registered properly."}, + {"R_UnsupportedDataTypeAE", "Encryption and decryption of data type {0} is not supported."}, + {"R_NormalizationErrorAE", "Decryption of the data type {0} failed. Normalization error."}, + {"R_UnsupportedNormalizationVersionAE", + "Normalization version \"{0}\" received from SQL Server is either invalid or corrupted. Valid normalization versions are: {1}."}, + {"R_NullCipherTextAE", "Internal error. Ciphertext value cannot be null."}, + {"R_NullColumnEncryptionAlgorithmAE", + "Internal error. Encryption algorithm cannot be null. Valid algorithms are: {1}."}, + {"R_CustomCipherAlgorithmNotSupportedAE", "Custom cipher algorithm not supported."}, + {"R_PlainTextNullAE", "Internal error. Plaintext value cannot be null."}, + {"R_StreamingDataTypeAE", "Data of length greater than {0} is not supported in encrypted {1} column."}, + {"R_AE_NotSupportedByServer", "SQL Server instance in use does not support column encryption."}, + {"R_InvalidAEVersionNumber", "Received invalid version number \"{0}\" for Always Encrypted."}, // From + // Server + {"R_NullEncryptedColumnEncryptionKey", "Internal error. Encrypted column encryption key cannot be null."}, + {"R_EmptyEncryptedColumnEncryptionKey", "Internal error. Empty encrypted column encryption key specified."}, + {"R_InvalidMasterKeyDetails", "Invalid master key details specified."}, + {"R_CertificateError", "Error occurred while retrieving certificate \"{0}\" from keystore \"{1}\"."}, + {"R_ByteToShortConversion", "Error occurred while decrypting column encryption key."}, + {"R_InvalidCertificateSignature", + "The specified encrypted column encryption key signature does not match the signature computed with the column master key (certificate) in \"{0}\". The encrypted column encryption key may be corrupt, or the specified path may be incorrect."}, + {"R_CEKDecryptionFailed", "Exception while decryption of encrypted column encryption key: {0} "}, + {"R_NullKeyEncryptionAlgorithm", "Key encryption algorithm cannot be null."}, + {"R_NullKeyEncryptionAlgorithmInternal", "Internal error. Key encryption algorithm cannot be null."}, + {"R_InvalidKeyEncryptionAlgorithm", + "Invalid key encryption algorithm specified: {0}. Expected value: {1}."}, + {"R_InvalidKeyEncryptionAlgorithmInternal", + "Internal error. Invalid key encryption algorithm specified: {0}. Expected value: {1}."}, + {"R_NullColumnEncryptionKey", "Column encryption key cannot be null."}, + {"R_EmptyColumnEncryptionKey", "Empty column encryption key specified."}, + {"R_CertificateNotFoundForAlias", + "Certificate with alias {0} not found in the store provided by {1}. Verify the certificate has been imported correctly into the certificate location/store."}, + {"R_UnrecoverableKeyAE", + "Cannot recover private key from keystore with certificate details {0}. Verify that imported certificate for Always Encrypted contains private key and password provided for certificate is correct."}, + {"R_KeyStoreNotFound", + "System cannot find the key store file at the specified path. Verify that the path is correct and you have proper permissions to access it."}, + {"R_CustomKeyStoreProviderMapNull", + "Column encryption key store provider map cannot be null. Expecting a non-null value."}, + {"R_EmptyCustomKeyStoreProviderName", + "Invalid key store provider name specified. Key store provider names cannot be null or empty."}, + {"R_InvalidCustomKeyStoreProviderName", + "Invalid key store provider name {0}. {1} prefix is reserved for system key store providers."}, + {"R_CustomKeyStoreProviderValueNull", + "Null reference specified for key store provider {0}. Expecting a non-null value."}, + {"R_CustomKeyStoreProviderSetOnce", "Key store providers cannot be set more than once."}, + {"R_unknownColumnEncryptionType", "Invalid column encryption type {0}."}, + {"R_unsupportedStmtColEncSetting", "SQLServerStatementColumnEncryptionSetting cannot be null."}, + {"R_unsupportedConversionAE", "The conversion from {0} to {1} is unsupported for encrypted column."}, + {"R_InvalidDataForAE", + "The given value of type {0} from the data source cannot be converted to type {1} of the specified target column."}, + {"R_authenticationPropertyDescription", "The authentication to use."}, + {"R_accessTokenPropertyDescription", "The access token to use for Azure Active Directory."}, + {"R_FedAuthRequiredPreLoginResponseInvalidValue", + "Server sent an unexpected value for FedAuthRequired PreLogin Option. Value was {0}."}, + {"R_FedAuthInfoLengthTooShortForCountOfInfoIds", + "The FedAuthInfo token must at least contain 4 bytes indicating the number of info IDs."}, + {"R_FedAuthInfoInvalidOffset", + "FedAuthInfoDataOffset points to an invalid location. Current dataOffset is {0}."}, + {"R_FedAuthInfoFailedToReadData", "Failed to read FedAuthInfoData."}, + {"R_FedAuthInfoLengthTooShortForData", + "FEDAUTHINFO token stream is not long enough ({0}) to contain the data it claims to."}, + {"R_FedAuthInfoDoesNotContainStsurlAndSpn", + "FEDAUTHINFO token stream does not contain both STSURL and SPN."}, + {"R_ADALExecution", "Failed to authenticate the user {0} in Active Directory (Authentication={1})."}, + {"R_UnrequestedFeatureAckReceived", "Unrequested feature acknowledge is received. Feature ID: {0}."}, + {"R_FedAuthFeatureAckContainsExtraData", + "Federated authentication feature extension ack for ADAL and Security Token includes extra data."}, + {"R_FedAuthFeatureAckUnknownLibraryType", + "Attempting to use unknown federated authentication library. Library ID: {0}."}, + {"R_UnknownFeatureAck", "Unknown feature acknowledge is received."}, + {"R_SetAuthenticationWhenIntegratedSecurityTrue", + "Cannot set \"Authentication\" with \"IntegratedSecurity\" set to \"true\"."}, + {"R_SetAccesstokenWhenIntegratedSecurityTrue", + "Cannot set the AccessToken property if the \"IntegratedSecurity\" connection string keyword has been set to \"true\"."}, + {"R_IntegratedAuthenticationWithUserPassword", + "Cannot use \"Authentication=ActiveDirectoryIntegrated\" with \"User\", \"UserName\" or \"Password\" connection string keywords."}, + {"R_AccessTokenWithUserPassword", + "Cannot set the AccessToken property if \"User\", \"UserName\" or \"Password\" has been specified in the connection string."}, + {"R_AccessTokenCannotBeEmpty", "AccesToken cannot be empty."}, + {"R_SetBothAuthenticationAndAccessToken", + "Cannot set the AccessToken property if \"Authentication\" has been specified in the connection string."}, + {"R_NoUserPasswordForActivePassword", + "Both \"User\" (or \"UserName\") and \"Password\" connection string keywords must be specified, if \"Authentication=ActiveDirectoryPassword\"."}, + {"R_NoUserPasswordForSqlPassword", + "Both \"User\" (or \"UserName\") and \"Password\" connection string keywords must be specified, if \"Authentication=SqlPassword\"."}, + {"R_ForceEncryptionTrue_HonorAEFalse", + "Cannot set Force Encryption to true for parameter {0} because enryption is not enabled for the statement or procedure {1}."}, + {"R_ForceEncryptionTrue_HonorAETrue_UnencryptedColumn", + "Cannot execute statement or procedure {0} because Force Encryption was set as true for parameter {1} and the database expects this parameter to be sent as plaintext. This may be due to a configuration error."}, + {"R_ForceEncryptionTrue_HonorAEFalseRS", + "Cannot set Force Encryption to true for parameter {0} because encryption is not enabled for the statement or procedure."}, + {"R_ForceEncryptionTrue_HonorAETrue_UnencryptedColumnRS", + "Cannot execute update because Force Encryption was set as true for parameter {0} and the database expects this parameter to be sent as plaintext. This may be due to a configuration error."}, + {"R_NullValue", "{0} cannot be null."}, {"R_AKVPathNull", "Azure Key Vault key path cannot be null."}, + {"R_AKVURLInvalid", "Invalid URL specified: {0}."}, + {"R_AKVMasterKeyPathInvalid", "Invalid Azure Key Vault key path specified: {0}."}, + {"R_EmptyCEK", "Empty column encryption key specified."}, + {"R_EncryptedCEKNull", "Encrypted column encryption key cannot be null."}, + {"R_EmptyEncryptedCEK", "Encrypted Column Encryption Key length should not be zero."}, + {"R_NonRSAKey", "Cannot use a non-RSA key: {0}."}, + {"R_GetAKVKeySize", "Unable to get the Azure Key Vault public key size in bytes."}, + {"R_InvalidEcryptionAlgorithmVersion", + "Specified encrypted column encryption key contains an invalid encryption algorithm version {0}. Expected version is {1}."}, + {"R_AKVKeyLengthError", + "The specified encrypted column encryption key''s ciphertext length: {0} does not match the ciphertext length: {1} when using column master key (Azure Key Vault key) in {2}. The encrypted column encryption key may be corrupt, or the specified Azure Key Vault key path may be incorrect."}, + {"R_AKVSignatureLengthError", + "The specified encrypted column encryption key''s signature length: {0} does not match the signature length: {1} when using column master key (Azure Key Vault key) in {2}. The encrypted column encryption key may be corrupt, or the specified Azure Key Vault key path may be incorrect."}, + {"R_HashNull", "Hash should not be null while decrypting encrypted column encryption key."}, + {"R_NoSHA256Algorithm", "SHA-256 Algorithm is not supported."}, + {"R_VerifySignature", "Unable to verify signature of the column encryption key."}, + {"R_CEKSignatureNotMatchCMK", + "The specified encrypted column encryption key signature does not match the signature computed with the column master key (Asymmetric key in Azure Key Vault) in {0}. The encrypted column encryption key may be corrupt, or the specified path may be incorrect."}, + {"R_DecryptCEKError", "Unable to decrypt column encryption key using specified Azure Key Vault key."}, + {"R_EncryptCEKError", "Unable to encrypt column encryption key using specified Azure Key Vault key."}, + {"R_CipherTextLengthNotMatchRSASize", "CipherText length does not match the RSA key size."}, + {"R_GenerateSignature", "Unable to generate signature using a specified Azure Key Vault Key URL."}, + {"R_SignedHashLengthError", "Signed hash length does not match the RSA key size."}, + {"R_InvalidSignatureComputed", "Invalid signature of the encrypted column encryption key computed."}, + {"R_UnableLoadADALSqlDll", + "Unable to load adalsql.dll. Error code: 0x{0}. For details, see: http://go.microsoft.com/fwlink/?LinkID=513072"}, + {"R_ADALAuthenticationMiddleErrorMessage", "Error code 0x{0}; state {1}."}, + {"R_unsupportedDataTypeTVP", "Data type {0} not supported in Table-Valued Parameter."}, + {"R_moreDataInRowThanColumnInTVP", "Input array is longer than the number of columns in this table."}, + {"R_invalidTVPName", " The Table-Valued Parameter must have a valid type name."}, + {"R_invalidThreePartName", "Invalid 3 part name format for TypeName."}, + {"R_unsupportedConversionTVP", "The conversion from {0} to {1} is unsupported for Table-Valued Parameter."}, + {"R_TVPMixedSource", + "Cannot add column metadata. This Table-Valued Parameter has a ResultSet from which metadata will be derived."}, + {"R_TVPEmptyMetadata", + "There are not enough fields in the Structured type. Structured types must have at least one field."}, + {"R_TVPInvalidValue", + "The value provided for Table-Valued Parameter {0} is not valid. Only SQLServerDataTable, ResultSet and ISQLServerDataRecord objects are supported."}, + {"R_TVPInvalidColumnValue", "Input data is not in correct format."}, + {"R_TVPSortOrdinalGreaterThanFieldCount", + "The sort ordinal {0} on field {1} exceeds the total number of fields."}, + {"R_TVPMissingSortOrderOrOrdinal", + "The sort order and ordinal must either both be specified, or neither should be specified (SortOrder.Unspecified and -1). The values given were: order = {0}, ordinal = {1}."}, + {"R_TVPDuplicateSortOrdinal", "The sort ordinal {0} was specified twice."}, + {"R_TVPMissingSortOrdinal", "The sort ordinal {0} was not specified."}, + {"R_TVPDuplicateColumnName", "A column name {0} already belongs to this SQLServerDataTable."}, + {"R_InvalidConnectionSetting", "The {0} value \"{1}\" is not valid."}, // This is used for connection + // settings. {0}-> property name as + // is, {1}-> value + {"R_InvalidWindowsCertificateStoreEncryption", + "Cannot encrypt a column encryption key with the Windows Certificate Store."}, + {"R_AEKeypathEmpty", + "Internal error. Certificate path cannot be null. Use the following format: \"certificate location/certificate store/certificate thumbprint\", where \"certificate location\" is either LocalMachine or CurrentUser."}, + {"R_AEWinApiErr", "Windows Api native error."}, + {"R_AECertpathBad", + "Internal error. Invalid certificate path: {0}. Use the following format: \"certificate location/certificate store/certificate thumbprint\", where \"certificate location\" is either LocalMachine or CurrentUser."}, + {"R_AECertLocBad", + "Internal error. Invalid certificate location {0} in certificate path {1}. Use the following format: \"certificate location/certificate store/certificate thumbprint\", where \"certificate location\" is either LocalMachine or CurrentUser."}, + {"R_AECertStoreBad", + "Internal error. Invalid certificate store {0} specified in certificate path {1}. Expected value: My."}, + {"R_AECertHashEmpty", "Internal error. Empty certificate thumbprint specified in certificate path {0}."}, + {"R_AECertNotFound", + "Certificate with thumbprint {2} not found in certificate store {1} in certificate location {0}. Verify the certificate path in the column master key definition in the database is correct, and the certificate has been imported correctly into the certificate location/store."}, + {"R_AEMaloc", "Memory allocation failure."}, + {"R_AEKeypathLong", + "Internal error. Specified certificate path has {0} bytes, which exceeds maximum length of {1} bytes."}, + {"R_AEECEKLenBad", + "The specified encrypted column encryption key''s ciphertext length: {0} does not match the ciphertext length: {1} when using column master key (certificate) in \"{2}\". The encrypted column encryption key may be corrupt, or the specified certificate path may be incorrect."}, + {"R_AEECEKSigLenBad", + "The specified encrypted column encryption key''s signature length {0} does not match the length {1} when using the column master key (certificate) in \"{2}\". The encrypted column encryption key may be corrupt, or the specified certificate path may be incorrect."}, + {"R_AEKeyPathEmptyOrReserved", + "The certificate path \"{0}\" is invalid; it is empty or contains reserved directory names."}, + {"R_AEKeyPathCurUser", + "CurrentUser was specified in key path but an error occurred obtaining the current user''s initial working directory."}, + {"R_AEKeyFileOpenError", "Error opening certificate file {0}."}, + {"R_AEKeyFileReadError", "Error reading certificate file {0}."}, + {"R_keyStoreAuthenticationPropertyDescription", "The name that identifies a key store."}, + {"R_keyStoreSecretPropertyDescription", + "The authentication secret or information needed to locate the secret."}, + {"R_keyStoreLocationPropertyDescription", "The key store location."}, + {"R_keyStoreAuthenticationNotSet", + "\"keyStoreAuthentication\" connection string keyword must be specified, if \"{0}\" is specified."}, + {"R_keyStoreSecretOrLocationNotSet", + "Both \"keyStoreSecret\" and \"keyStoreLocation\" must be set, if \"keyStoreAuthentication=JavaKeyStorePassword\" has been specified in the connection string."}, + {"R_certificateStoreInvalidKeyword", + "Cannot set \"keyStoreSecret\", if \"keyStoreAuthentication=CertificateStore\" has been specified in the connection string."}, + {"R_certificateStoreLocationNotSet", + "\"keyStoreLocation\" must be specified, if \"keyStoreAuthentication=CertificateStore\" has been specified in the connection string."}, + {"R_certificateStorePlatformInvalid", + "Cannot set \"keyStoreAuthentication=CertificateStore\" on a Windows operating system."}, + {"R_invalidKeyStoreFile", + "Cannot parse \"{0}\". Either the file format is not valid or the password is not correct."}, // for + // JKS/PKCS + {"R_invalidCEKCacheTtl", + "Invalid column encryption key cache time-to-live specified. The columnEncryptionKeyCacheTtl value cannot be negative and timeUnit can only be DAYS, HOURS, MINUTES or SECONDS."}, + {"R_sendTimeAsDateTimeForAE", "Use sendTimeAsDateTime=false with Always Encrypted."}, + {"R_TVPnotWorkWithSetObjectResultSet", + "setObject() with ResultSet is not supported for Table-Valued Parameter. Please use setStructured()."}, + {"R_invalidQueryTimeout", "The queryTimeout {0} is not valid."}, + {"R_invalidSocketTimeout", "The socketTimeout {0} is not valid."}, + {"R_fipsPropertyDescription", "Determines if FIPS mode is enabled."}, + {"R_invalidFipsConfig", "Unable to verify FIPS mode settings."}, + {"R_serverPreparedStatementDiscardThreshold", + "The serverPreparedStatementDiscardThreshold {0} is not valid."}, + {"R_statementPoolingCacheSize", "The statementPoolingCacheSize {0} is not valid."}, + {"R_kerberosLoginFailedForUsername", + "Cannot login with Kerberos principal {0}, check your credentials. {1}"}, + {"R_kerberosLoginFailed", "Kerberos Login failed: {0} due to {1} ({2})"}, + {"R_StoredProcedureNotFound", "Could not find stored procedure ''{0}''."}, + {"R_jaasConfigurationNamePropertyDescription", "Login configuration file for Kerberos authentication."}, + {"R_AKVKeyNotFound", "Key not found: {0}"}, + {"R_SQLVariantSupport", "SQL_VARIANT is not supported in versions of SQL Server before 2008."}, + {"R_invalidProbbytes", "SQL_VARIANT: invalid probBytes for {0} type."}, + {"R_invalidStringValue", "SQL_VARIANT does not support string values of length greater than 8000."}, + {"R_invalidValueForTVPWithSQLVariant", "Use of TVPs containing null sql_variant columns is not supported."}, + {"R_invalidDataTypeSupportForSQLVariant", "Unexpected TDS type ' '{0}' ' in SQL_VARIANT."}, + {"R_sslProtocolPropertyDescription", + "SSL protocol label from TLS, TLSv1, TLSv1.1, and TLSv1.2. The default is TLS."}, + {"R_invalidSSLProtocol", + "SSL Protocol {0} label is not valid. Only TLS, TLSv1, TLSv1.1, and TLSv1.2 are supported."}, + {"R_cancelQueryTimeoutPropertyDescription", + "The number of seconds to wait to cancel sending a query timeout."}, + {"R_invalidCancelQueryTimeout", "The cancel timeout value {0} is not valid."}, + {"R_useBulkCopyForBatchInsertPropertyDescription", + "Whether the driver will use bulk copy API for batch insert operations"}, + {"R_UnknownDataClsTokenNumber", "Unknown token for Data Classification."}, // From Server + {"R_InvalidDataClsVersionNumber", "Invalid version number {0} for Data Classification."}, // From Server + {"R_unknownUTF8SupportValue", "Unknown value for UTF8 support."}, + {"R_illegalWKT", "Illegal Well-Known text. Please make sure Well-Known text is valid."}, + {"R_illegalTypeForGeometry", "{0} is not supported for Geometry."}, + {"R_illegalWKTposition", "Illegal character in Well-Known text at position {0}."},}; } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSet.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSet.java index b7b2370c9..89502cd2a 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSet.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSet.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -22,6 +19,7 @@ import java.sql.ResultSetMetaData; import java.sql.RowId; import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; import java.sql.SQLType; import java.sql.SQLWarning; import java.sql.SQLXML; @@ -33,8 +31,9 @@ import com.microsoft.sqlserver.jdbc.dataclassification.SensitivityClassification; + /** - * Indicates the type of the row received from the server + * Indicates the type of the row received from the server. */ enum RowType { ROW, @@ -42,8 +41,9 @@ enum RowType { UNKNOWN, } + /** - * Top-level JDBC ResultSet implementation + * Defines the Top-level JDBC ResultSet implementation. */ public class SQLServerResultSet implements ISQLServerResultSet, java.io.Serializable { @@ -60,7 +60,8 @@ private static int nextResultSetID() { return lastResultSetID.incrementAndGet(); } - final static java.util.logging.Logger logger = java.util.logging.Logger.getLogger("com.microsoft.sqlserver.jdbc.internals.SQLServerResultSet"); + final static java.util.logging.Logger logger = java.util.logging.Logger + .getLogger("com.microsoft.sqlserver.jdbc.internals.SQLServerResultSet"); @Override public String toString() { @@ -71,7 +72,8 @@ String logCursorState() { return " currentRow:" + currentRow + " numFetchedRows:" + numFetchedRows + " rowCount:" + rowCount; } - protected static final java.util.logging.Logger loggerExternal = java.util.logging.Logger.getLogger("com.microsoft.sqlserver.jdbc.ResultSet"); + protected static final java.util.logging.Logger loggerExternal = java.util.logging.Logger + .getLogger("com.microsoft.sqlserver.jdbc.ResultSet"); final private String loggingClassName; @@ -130,8 +132,8 @@ final void setCurrentRowType(RowType rowType) { } /** - * Currently active Stream Note only one stream can be active at a time, JDBC spec calls for the streams to be closed when a column or row move - * occurs + * Currently active Stream Note only one stream can be active at a time, JDBC spec calls for the streams to be + * closed when a column or row move occurs */ private Closeable activeStream; private SQLServerLob activeLOB; @@ -174,8 +176,8 @@ final void setDeletedCurrentRow(boolean rowDeleted) { /** * Count of rows in this result set. * - * The number of rows in the result set may be known when this ResultSet object is created, after the first full traversal of the result set, or - * possibly never (as is the case with DYNAMIC cursors). + * The number of rows in the result set may be known when this ResultSet object is created, after the first full + * traversal of the result set, or possibly never (as is the case with DYNAMIC cursors). */ static final int UNKNOWN_ROW_COUNT = -3; private int rowCount; @@ -186,21 +188,20 @@ final void setDeletedCurrentRow(boolean rowDeleted) { // The CekTable retrieved from the COLMETADATA token for this resultset. private CekTable cekTable = null; - /* Gets the CekTable */ + /* Returns the CekTable */ CekTable getCekTable() { return cekTable; } - final void setColumnName(int index, - String name) { + final void setColumnName(int index, String name) { columns[index - 1].setColumnName(name); } /** - * Skips columns between the last marked column and the target column, inclusive, optionally discarding their values as they are skipped. + * Skips columns between the last marked column and the target column, inclusive, optionally discarding their values + * as they are skipped. */ - private void skipColumns(int columnsToSkip, - boolean discardValues) throws SQLServerException { + private void skipColumns(int columnsToSkip, boolean discardValues) throws SQLServerException { assert lastColumnIndex >= 1; assert 0 <= columnsToSkip && columnsToSkip <= columns.length; @@ -227,10 +228,10 @@ public SensitivityClassification getSensitivityClassification() { } /** - * Make a new result set + * Constructs a SQLServerResultSet. * * @param stmtIn - * the generating statement + * the generating statement */ SQLServerResultSet(SQLServerStatement stmtIn) throws SQLServerException { int resultSetID = nextResultSetID(); @@ -271,7 +272,8 @@ boolean onTabName(TDSReader tdsReader) throws SQLServerException { } boolean onColMetaData(TDSReader tdsReader) throws SQLServerException { - columnMetaData = new StreamColumns(Util.shouldHonorAEForRead(stmt.stmtColumnEncriptionSetting, stmt.connection)); + columnMetaData = new StreamColumns( + Util.shouldHonorAEForRead(stmt.stmtColumnEncriptionSetting, stmt.connection)); columnMetaData.setFromTDS(tdsReader); cekTable = columnMetaData.getCekTable(); return true; @@ -378,7 +380,8 @@ boolean onDone(TDSReader tdsReader) throws SQLServerException { this.fetchSize = stmtIn.nFetchSize; this.fetchDirection = stmtIn.nFetchDirection; - CursorInitializer initializer = stmtIn.executedSqlDirectly ? (new ClientCursorInitializer()) : (new ServerCursorInitializer(stmtIn)); + CursorInitializer initializer = stmtIn.executedSqlDirectly ? (new ClientCursorInitializer()) + : (new ServerCursorInitializer(stmtIn)); TDSParser.parse(stmtIn.resultsReader(), initializer); this.columns = initializer.buildColumns(); @@ -421,8 +424,7 @@ public T unwrap(Class iface) throws SQLException { T t; try { t = iface.cast(this); - } - catch (ClassCastException e) { + } catch (ClassCastException e) { throw new SQLServerException(e.getMessage(), e); } loggerExternal.exiting(getClassNameLogging(), "unwrap", t); @@ -432,14 +434,15 @@ public T unwrap(Class iface) throws SQLException { private SQLServerException rowErrorException = null; /** - * Check if the result set is closed + * Checks if the result set is closed * * @throws SQLServerException */ void checkClosed() throws SQLServerException { if (isClosed) { - SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_resultsetClosed"), null, false); + SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_resultsetClosed"), + null, false); } stmt.checkClosed(); @@ -463,16 +466,17 @@ public boolean isClosed() throws SQLException { * Called by ResultSet API methods to disallow method use on forward only result sets. * * @throws SQLException - * if the result set is forward only. + * if the result set is forward only. * @throws SQLFeatureNotSupportedException */ private void throwNotScrollable() throws SQLException { - SQLServerException.makeFromDriverError(stmt.connection, this, SQLServerException.getErrString("R_requestedOpNotSupportedOnForward"), null, - true); + SQLServerException.makeFromDriverError(stmt.connection, this, + SQLServerException.getErrString("R_requestedOpNotSupportedOnForward"), null, true); } protected boolean isForwardOnly() { - return TYPE_SS_DIRECT_FORWARD_ONLY == stmt.getSQLResultSetType() || TYPE_SS_SERVER_CURSOR_FORWARD_ONLY == stmt.getSQLResultSetType(); + return TYPE_SS_DIRECT_FORWARD_ONLY == stmt.getSQLResultSetType() + || TYPE_SS_SERVER_CURSOR_FORWARD_ONLY == stmt.getSQLResultSetType(); } private boolean isDynamic() { @@ -488,10 +492,11 @@ private void verifyResultSetIsScrollable() throws SQLException { * Called by ResultSet API methods to disallow method use on read only result sets. * * @throws SQLServerException - * if the result set is read only. + * if the result set is read only. */ private void throwNotUpdatable() throws SQLServerException { - SQLServerException.makeFromDriverError(stmt.connection, this, SQLServerException.getErrString("R_resultsetNotUpdatable"), null, true); + SQLServerException.makeFromDriverError(stmt.connection, this, + SQLServerException.getErrString("R_resultsetNotUpdatable"), null, true); } private void verifyResultSetIsUpdatable() throws SQLServerException { @@ -500,7 +505,7 @@ private void verifyResultSetIsUpdatable() throws SQLServerException { } /** - * Checks whether the result set has a current row. + * Returns whether the result set has a current row. * * @return true if there is a current row * @return false if the result set is positioned before the first row or after the last row. @@ -512,20 +517,22 @@ private boolean hasCurrentRow() { /** * Verifies whether this result set has a current row. * - * This check DOES NOT consider whether the cursor is on the insert row. The result set may or may not have a current row regardless whether the - * cursor is on the insert row. Consider the following scenarios: + * This check DOES NOT consider whether the cursor is on the insert row. The result set may or may not have a + * current row regardless whether the cursor is on the insert row. Consider the following scenarios: * - * beforeFirst(); moveToInsertRow(); relative(1); No current row to move relative to. Throw "no current row" exception. + * beforeFirst(); moveToInsertRow(); relative(1); No current row to move relative to. Throw "no current row" + * exception. * - * first(); moveToInsertRow(); relative(1); Call to relative moves off of the insert row one row past the current row. That is, the cursor ends up - * on the second row of the result set. + * first(); moveToInsertRow(); relative(1); Call to relative moves off of the insert row one row past the current + * row. That is, the cursor ends up on the second row of the result set. * * @throws SQLServerException - * if the result set has no current row + * if the result set has no current row */ private void verifyResultSetHasCurrentRow() throws SQLServerException { if (!hasCurrentRow()) { - SQLServerException.makeFromDriverError(stmt.connection, stmt, SQLServerException.getErrString("R_resultsetNoCurrentRow"), null, true); + SQLServerException.makeFromDriverError(stmt.connection, stmt, + SQLServerException.getErrString("R_resultsetNoCurrentRow"), null, true); } } @@ -533,19 +540,21 @@ private void verifyResultSetHasCurrentRow() throws SQLServerException { * Called by ResultSet API methods to disallow method use when cursor is on a deleted row. * * @throws SQLServerException - * if the cursor is not on an updatable row. + * if the cursor is not on an updatable row. */ private void verifyCurrentRowIsNotDeleted(String errResource) throws SQLServerException { if (currentRowDeleted()) { - SQLServerException.makeFromDriverError(stmt.connection, stmt, SQLServerException.getErrString(errResource), null, true); + SQLServerException.makeFromDriverError(stmt.connection, stmt, SQLServerException.getErrString(errResource), + null, true); } } /** - * Called by ResultSet API methods to disallow method use when the column index is not in the range of columns returned in the results. + * Called by ResultSet API methods to disallow method use when the column index is not in the range of columns + * returned in the results. * * @throws SQLServerException - * if the column index is out of bounds + * if the column index is out of bounds */ private void verifyValidColumnIndex(int index) throws SQLServerException { int nCols = columns.length; @@ -567,25 +576,28 @@ private void verifyValidColumnIndex(int index) throws SQLServerException { * Called by ResultSet API methods to disallow method use when cursor is on the insert row. * * @throws SQLServerException - * if the cursor is on the insert row. + * if the cursor is on the insert row. */ private void verifyResultSetIsNotOnInsertRow() throws SQLServerException { if (isOnInsertRow) { - SQLServerException.makeFromDriverError(stmt.connection, stmt, SQLServerException.getErrString("R_mustNotBeOnInsertRow"), null, true); + SQLServerException.makeFromDriverError(stmt.connection, stmt, + SQLServerException.getErrString("R_mustNotBeOnInsertRow"), null, true); } } private void throwUnsupportedCursorOp() throws SQLServerException { // Absolute positioning of dynamic cursors is unsupported. - SQLServerException.makeFromDriverError(stmt.connection, this, SQLServerException.getErrString("R_unsupportedCursorOperation"), null, true); + SQLServerException.makeFromDriverError(stmt.connection, this, + SQLServerException.getErrString("R_unsupportedCursorOperation"), null, true); } /** - * Close the result set. + * Closes the result set. * - * Note that the public close() method performs all of the cleanup work through this internal method which cannot throw any exceptions. This is - * done deliberately to ensure that ALL of the object's client-side and server-side state is cleaned up as best as possible, even under conditions - * which would normally result in exceptions being thrown. + * Note that the public close() method performs all of the cleanup work through this internal method which cannot + * throw any exceptions. This is done deliberately to ensure that ALL of the object's client-side and server-side + * state is cleaned up as best as possible, even under conditions which would normally result in exceptions being + * thrown. */ private void closeInternal() { // Calling close on a closed ResultSet is a no-op per JDBC spec @@ -619,12 +631,12 @@ public void close() throws SQLServerException { } /** - * Find a column index given a column name + * Finds a column index given a column name. * * @param columnName - * the name of the column + * the name of the column * @throws SQLServerException - * If any errors occur. + * If any errors occur. * @return the column index */ @Override @@ -691,11 +703,9 @@ final Column getColumn(int columnIndex) throws SQLServerException { try { fillLOBs(); activeStream.close(); - } - catch (IOException e) { + } catch (IOException e) { SQLServerException.makeFromDriverError(null, null, e.getMessage(), null, true); - } - finally { + } finally { activeStream = null; } } @@ -704,8 +714,8 @@ final Column getColumn(int columnIndex) throws SQLServerException { } /** - * This function initializes null compressed columns only when the row type is NBCROW and if the areNullCompressedColumnsInitialized is false. In - * all other cases this will be a no-op. + * Initializes null compressed columns only when the row type is NBCROW and if the + * areNullCompressedColumnsInitialized is false. In all other cases this will be a no-op. * * @throws SQLServerException */ @@ -713,7 +723,9 @@ private void initializeNullCompressedColumns() throws SQLServerException { if (resultSetCurrentRowType.equals(RowType.NBCROW) && (!areNullCompressedColumnsInitialized)) { int columnNo = 0; // no of bytes to be read from the stream - int noOfBytes = ((this.columns.length - 1) >> 3) + 1;// equivalent of (int)Math.ceil(this.columns.length/8.0) and gives better perf + int noOfBytes = ((this.columns.length - 1) >> 3) + 1;// equivalent of + // (int)Math.ceil(this.columns.length/8.0) and gives + // better perf for (int byteNo = 0; byteNo < noOfBytes; byteNo++) { int byteValue = tdsReader.readUnsignedByte(); @@ -751,10 +763,10 @@ private Column loadColumn(int index) throws SQLServerException { } /** - * Clear result set warnings + * Clears result set warnings. * * @throws SQLServerException - * when an error occurs + * when an error occurs */ @Override public void clearWarnings() throws SQLServerException { @@ -886,8 +898,7 @@ private void moveBackward(int rowsToMove) throws SQLServerException { // to clientMoveAbsolute is interpreted as relative to the last row, not the first. if (currentRow + rowsToMove < 1) { moveBeforeFirst(); - } - else { + } else { currentRow = clientMoveAbsolute(currentRow + rowsToMove); } @@ -920,13 +931,11 @@ private void moveBackward(int rowsToMove) throws SQLServerException { } // Scroll past the last of the returned rows, and ... - while (scrollWindow.next(this)) - ; + while (scrollWindow.next(this)); // back up one row. scrollWindow.previous(this); - } - else { + } else { doServerFetch(TDS.FETCH_RELATIVE, rowsToMove + scrollWindow.getRow() - 1, fetchSize); // If the new fetch buffer returned no rows, then the cursor has reached the start of the result set. @@ -941,10 +950,10 @@ private void moveBackward(int rowsToMove) throws SQLServerException { } /** - * Update the current row's position if known. + * Updates the current row's position if known. * - * If known, the current row is assumed to be at a valid position somewhere in the ResultSet. That is, the current row is not before the first row - * or after the last row. + * If known, the current row is assumed to be at a valid position somewhere in the ResultSet. That is, the current + * row is not before the first row or after the last row. */ private void updateCurrentRow(int rowsToMove) { if (UNKNOWN_ROW != currentRow) { @@ -955,8 +964,8 @@ private void updateCurrentRow(int rowsToMove) { } /** - * Initially moves the cursor to the first row of this ResultSet object, with subsequent calls moving the cursor to the second row, the third row, - * and so on. + * Moves the cursor to the first row of this ResultSet object initially, then subsequent calls move the cursor to + * the second row, the third row, and so on. * * @return false when there are no more rows to read */ @@ -1063,7 +1072,10 @@ public boolean wasNull() throws SQLServerException { } /** - * @return true if the cursor is before the first row in this result set, returns false otherwise or if the result set contains no rows. + * Returns if the cursor is before the first row in this result set. + * + * @return true if the cursor is before the first row in this result set, returns false otherwise or if the result + * set contains no rows. */ @Override public boolean isBeforeFirst() throws SQLException { @@ -1161,19 +1173,19 @@ public boolean isAfterLast() throws SQLException { } /** - * Retrieves whether the cursor is on the first row of this ResultSet object. + * Returns whether the cursor is on the first row of this ResultSet object. * - * This method should be called only on ResultSet objects that are scrollable: TYPE_SCROLL_SENSITIVE, TYPE_SCROLL_INSENSITIVE, - * TYPE_SS_SCROLL_STATIC, TYPE_SS_SCROLL_KEYSET, TYPE_SS_SCROLL_DYNAMIC. + * This method should be called only on ResultSet objects that are scrollable: TYPE_SCROLL_SENSITIVE, + * TYPE_SCROLL_INSENSITIVE, TYPE_SS_SCROLL_STATIC, TYPE_SS_SCROLL_KEYSET, TYPE_SS_SCROLL_DYNAMIC. * *

- * Note:Support for the isFirst method is optional for ResultSets with a result set type of - * TYPE_FORWARD_ONLY + * Note:Support for the isFirst method is optional for ResultSets with a + * result set type of TYPE_FORWARD_ONLY * * @return true if the cursor is on the first row; false otherwise * * @exception SQLException - * if a database access error occurs or this method is called on a closed result set + * if a database access error occurs or this method is called on a closed result set * * @since 1.2 */ @@ -1208,22 +1220,22 @@ public boolean isFirst() throws SQLException { } /** - * Retrieves whether the cursor is on the last row of this ResultSet object. Note: Calling the method - * isLast may be expensive because the JDBC driver might need to fetch ahead one row in order to determine whether the current row is - * the last row in the result set. + * Returns whether the cursor is on the last row of this ResultSet object. Note: + * Calling the method isLast may be expensive because the JDBC driver might need to fetch ahead one row + * in order to determine whether the current row is the last row in the result set. * *

- * This method should be called only on ResultSet objects that are scrollable: TYPE_SCROLL_SENSITIVE, TYPE_SCROLL_INSENSITIVE, - * TYPE_SS_SCROLL_STATIC, TYPE_SS_SCROLL_KEYSET, TYPE_SS_SCROLL_DYNAMIC. + * This method should be called only on ResultSet objects that are scrollable: TYPE_SCROLL_SENSITIVE, + * TYPE_SCROLL_INSENSITIVE, TYPE_SS_SCROLL_STATIC, TYPE_SS_SCROLL_KEYSET, TYPE_SS_SCROLL_DYNAMIC. *

* - * Note: Support for the isLast method is optional for ResultSets with a result set type of - * TYPE_FORWARD_ONLY + * Note: Support for the isLast method is optional for ResultSets with a + * result set type of TYPE_FORWARD_ONLY * * @return true if the cursor is on the last row; false otherwise * * @exception SQLException - * if a database access error occurs or this method is called on a closed result set + * if a database access error occurs or this method is called on a closed result set * * @since 1.2 */ @@ -1302,8 +1314,7 @@ private void moveBeforeFirst() throws SQLServerException { if (0 == serverCursorId) { fetchBufferBeforeFirst(); scrollWindow.clear(); - } - else { + } else { doServerFetch(TDS.FETCH_FIRST, 0, 0); } @@ -1346,15 +1357,16 @@ private void moveAfterLast() throws SQLServerException { * Moves the cursor to the first row in this ResultSet object. * *

- * This method should be called only on ResultSet objects that are scrollable: TYPE_SCROLL_SENSITIVE, TYPE_SCROLL_INSENSITIVE, - * TYPE_SS_SCROLL_STATIC, TYPE_SS_SCROLL_KEYSET, TYPE_SS_SCROLL_DYNAMIC. + * This method should be called only on ResultSet objects that are scrollable: TYPE_SCROLL_SENSITIVE, + * TYPE_SCROLL_INSENSITIVE, TYPE_SS_SCROLL_STATIC, TYPE_SS_SCROLL_KEYSET, TYPE_SS_SCROLL_DYNAMIC. *

* - * @return true if the cursor is on a valid row; false if there are no rows in the result set + * @return true if the cursor is on a valid row; false if there are no rows in the result + * set * * @exception SQLException - * if a database access error occurs; this method is called on a closed result set or the result set type is - * TYPE_FORWARD_ONLY + * if a database access error occurs; this method is called on a closed result set or the result set type + * is TYPE_FORWARD_ONLY * * @since 1.2 */ @@ -1380,8 +1392,7 @@ public boolean first() throws SQLException { private void moveFirst() throws SQLServerException { if (0 == serverCursorId) { moveBeforeFirst(); - } - else { + } else { // Fetch the first block of up to fetchSize rows doServerFetch(TDS.FETCH_FIRST, 0, fetchSize); } @@ -1404,14 +1415,15 @@ private void moveFirst() throws SQLServerException { /** * Moves the cursor to the last row in this ResultSet object. * - * This method should be called only on ResultSet objects that are scrollable: TYPE_SCROLL_SENSITIVE, TYPE_SCROLL_INSENSITIVE, - * TYPE_SS_SCROLL_STATIC, TYPE_SS_SCROLL_KEYSET, TYPE_SS_SCROLL_DYNAMIC. + * This method should be called only on ResultSet objects that are scrollable: TYPE_SCROLL_SENSITIVE, + * TYPE_SCROLL_INSENSITIVE, TYPE_SS_SCROLL_STATIC, TYPE_SS_SCROLL_KEYSET, TYPE_SS_SCROLL_DYNAMIC. * - * @return true if the cursor is on a valid row; false if there are no rows in the result set + * @return true if the cursor is on a valid row; false if there are no rows in the result + * set * * @exception SQLException - * if a database access error occurs; this method is called on a closed result set or the result set type is - * TYPE_FORWARD_ONLY + * if a database access error occurs; this method is called on a closed result set or the result set type + * is TYPE_FORWARD_ONLY * * @since 1.2 */ @@ -1455,8 +1467,7 @@ private void moveLast() throws SQLServerException { } // Scroll to the last of the returned rows - while (scrollWindow.next(this)) - ; + while (scrollWindow.next(this)); scrollWindow.previous(this); // Adjust the current row appropriately @@ -1496,40 +1507,41 @@ public int getRow() throws SQLException { * Moves the cursor to the given row number in this ResultSet object. * *

- * This method should be called only on ResultSet objects that are scrollable: TYPE_SCROLL_SENSITIVE, TYPE_SCROLL_INSENSITIVE, - * TYPE_SS_SCROLL_STATIC, TYPE_SS_SCROLL_KEYSET, TYPE_SS_SCROLL_DYNAMIC. + * This method should be called only on ResultSet objects that are scrollable: TYPE_SCROLL_SENSITIVE, + * TYPE_SCROLL_INSENSITIVE, TYPE_SS_SCROLL_STATIC, TYPE_SS_SCROLL_KEYSET, TYPE_SS_SCROLL_DYNAMIC. *

* *

- * If the row number is positive, the cursor moves to the given row number with respect to the beginning of the result set. The first row is row - * 1, the second is row 2, and so on. + * If the row number is positive, the cursor moves to the given row number with respect to the beginning of the + * result set. The first row is row 1, the second is row 2, and so on. * *

- * If the given row number is negative, the cursor moves to an absolute row position with respect to the end of the result set. For example, - * calling the method absolute(-1) positions the cursor on the last row; calling the method absolute(-2) moves the - * cursor to the next-to-last row, and so on. + * If the given row number is negative, the cursor moves to an absolute row position with respect to the end of the + * result set. For example, calling the method absolute(-1) positions the cursor on the last row; + * calling the method absolute(-2) moves the cursor to the next-to-last row, and so on. * *

* If the row number specified is zero, the cursor is moved to before the first row. * *

- * An attempt to position the cursor beyond the first/last row in the result set leaves the cursor before the first row or after the last row. + * An attempt to position the cursor beyond the first/last row in the result set leaves the cursor before the first + * row or after the last row. * *

- * Note: Calling absolute(1) is the same as calling first(). Calling absolute(-1) is the same as - * calling last(). + * Note: Calling absolute(1) is the same as calling first(). Calling + * absolute(-1) is the same as calling last(). * * @param row - * the number of the row to which the cursor should move. A value of zero indicates that the cursor will be positioned before the first - * row; a positive number indicates the row number counting from the beginning of the result set; a negative number indicates the row - * number counting from the end of the result set + * the number of the row to which the cursor should move. A value of zero indicates that the cursor will be + * positioned before the first row; a positive number indicates the row number counting from the beginning of + * the result set; a negative number indicates the row number counting from the end of the result set * - * @return true if the cursor is moved to a position in this ResultSet object; false if the cursor is - * before the first row or after the last row + * @return true if the cursor is moved to a position in this ResultSet object; + * false if the cursor is before the first row or after the last row * * @exception SQLException - * if a database access error occurs; this method is called on a closed result set or the result set type is - * TYPE_FORWARD_ONLY + * if a database access error occurs; this method is called on a closed result set or the result set type + * is TYPE_FORWARD_ONLY * * @since 1.2 */ @@ -1637,8 +1649,7 @@ private void moveAbsolute(int row) throws SQLServerException { if (row > 0) { // The current row is just the row to which we moved. currentRow = row; - } - else { + } else { // Absolute fetch with -ve row is relative to the end of the result set. assert row < 0; assert rowCount + row + 1 >= 1; @@ -1664,7 +1675,8 @@ private boolean fetchBufferHasRows() throws SQLServerException { // Return whether the next item in the response appears to be a row or something // that should have been a row. - return (TDS.TDS_ROW == tdsTokenType || TDS.TDS_NBCROW == tdsTokenType || TDS.TDS_MSG == tdsTokenType || TDS.TDS_ERR == tdsTokenType); + return (TDS.TDS_ROW == tdsTokenType || TDS.TDS_NBCROW == tdsTokenType || TDS.TDS_MSG == tdsTokenType + || TDS.TDS_ERR == tdsTokenType); } final void discardCurrentRow() throws SQLServerException { @@ -1742,13 +1754,11 @@ final boolean fetchBufferNext() throws SQLServerException { fetchBufferCurrentRowType = fetchBuffer.nextRow(); if (fetchBufferCurrentRowType.equals(RowType.UNKNOWN)) return false; - } - catch (SQLServerException e) { + } catch (SQLServerException e) { currentRow = AFTER_LAST_ROW; rowErrorException = e; throw e; - } - finally { + } finally { lastColumnIndex = 0; resultSetCurrentRowType = fetchBufferCurrentRowType; } @@ -1844,14 +1854,15 @@ private int clientMoveAbsolute(int row) throws SQLServerException { /** * Moves the cursor to the previous row in this ResultSet object. * - * This method should be called only on ResultSet objects that are scrollable: TYPE_SCROLL_SENSITIVE, TYPE_SCROLL_INSENSITIVE, - * TYPE_SS_SCROLL_STATIC, TYPE_SS_SCROLL_KEYSET, TYPE_SS_SCROLL_DYNAMIC. + * This method should be called only on ResultSet objects that are scrollable: TYPE_SCROLL_SENSITIVE, + * TYPE_SCROLL_INSENSITIVE, TYPE_SS_SCROLL_STATIC, TYPE_SS_SCROLL_KEYSET, TYPE_SS_SCROLL_DYNAMIC. * - * @return true if the cursor is now positioned on a valid row; false if the cursor is positioned before the first row + * @return true if the cursor is now positioned on a valid row; false if the cursor is + * positioned before the first row * * @exception SQLException - * if a database access error occurs; this method is called on a closed result set or the result set type is - * TYPE_FORWARD_ONLY + * if a database access error occurs; this method is called on a closed result set or the result set type + * is TYPE_FORWARD_ONLY * * @since 1.2 */ @@ -1911,10 +1922,12 @@ public void setFetchDirection(int direction) throws SQLException { // Throws SQLException if the type of this ResultSet object is TYPE_FORWARD_ONLY. verifyResultSetIsScrollable(); - if ((ResultSet.FETCH_FORWARD != direction && ResultSet.FETCH_REVERSE != direction && ResultSet.FETCH_UNKNOWN != direction) || + if ((ResultSet.FETCH_FORWARD != direction && ResultSet.FETCH_REVERSE != direction + && ResultSet.FETCH_UNKNOWN != direction) || - (ResultSet.FETCH_FORWARD != direction && (SQLServerResultSet.TYPE_SS_DIRECT_FORWARD_ONLY == stmt.resultSetType - || SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY == stmt.resultSetType))) { + (ResultSet.FETCH_FORWARD != direction + && (SQLServerResultSet.TYPE_SS_DIRECT_FORWARD_ONLY == stmt.resultSetType + || SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY == stmt.resultSetType))) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidFetchDirection")); Object[] msgArgs = {direction}; SQLServerException.makeFromDriverError(stmt.connection, stmt, form.format(msgArgs), null, false); @@ -1937,7 +1950,8 @@ public void setFetchSize(int rows) throws SQLServerException { loggerExternal.entering(getClassNameLogging(), "setFetchSize", rows); checkClosed(); if (rows < 0) - SQLServerException.makeFromDriverError(stmt.connection, stmt, SQLServerException.getErrString("R_invalidFetchSize"), null, false); + SQLServerException.makeFromDriverError(stmt.connection, stmt, + SQLServerException.getErrString("R_invalidFetchSize"), null, false); fetchSize = (0 == rows) ? stmt.defaultFetchSize : rows; loggerExternal.exiting(getClassNameLogging(), "setFetchSize"); @@ -1977,7 +1991,7 @@ public int getConcurrency() throws SQLServerException { * Does all the common stuff necessary when calling a getter for the column at index. * * @param index - * the index of the column to get + * the index of the column to get */ Column getterGetColumn(int index) throws SQLServerException { // Note that we don't verify here that we're not on the insert row. According to @@ -2005,34 +2019,27 @@ Column getterGetColumn(int index) throws SQLServerException { return loadColumn(index); } - private Object getValue(int columnIndex, - JDBCType jdbcType) throws SQLServerException { + private Object getValue(int columnIndex, JDBCType jdbcType) throws SQLServerException { return getValue(columnIndex, jdbcType, null, null); } - private Object getValue(int columnIndex, - JDBCType jdbcType, - Calendar cal) throws SQLServerException { + private Object getValue(int columnIndex, JDBCType jdbcType, Calendar cal) throws SQLServerException { return getValue(columnIndex, jdbcType, null, cal); } - private Object getValue(int columnIndex, - JDBCType jdbcType, + private Object getValue(int columnIndex, JDBCType jdbcType, InputStreamGetterArgs getterArgs) throws SQLServerException { return getValue(columnIndex, jdbcType, getterArgs, null); } - private Object getValue(int columnIndex, - JDBCType jdbcType, - InputStreamGetterArgs getterArgs, + private Object getValue(int columnIndex, JDBCType jdbcType, InputStreamGetterArgs getterArgs, Calendar cal) throws SQLServerException { Object o = getterGetColumn(columnIndex).getValue(jdbcType, getterArgs, cal, tdsReader); lastValueWasNull = (null == o); return o; } - void setInternalVariantType(int columnIndex, - SqlVariant type) throws SQLServerException { + void setInternalVariantType(int columnIndex, SqlVariant type) throws SQLServerException { getterGetColumn(columnIndex).setInternalVariant(type); } @@ -2040,18 +2047,17 @@ SqlVariant getVariantInternalType(int columnIndex) throws SQLServerException { return getterGetColumn(columnIndex).getInternalVariant(); } - private Object getStream(int columnIndex, - StreamType streamType) throws SQLServerException { - Object value = getValue(columnIndex, streamType.getJDBCType(), - new InputStreamGetterArgs(streamType, stmt.getExecProps().isResponseBufferingAdaptive(), isForwardOnly(), toString())); + private Object getStream(int columnIndex, StreamType streamType) throws SQLServerException { + Object value = getValue(columnIndex, streamType.getJDBCType(), new InputStreamGetterArgs(streamType, + stmt.getExecProps().isResponseBufferingAdaptive(), isForwardOnly(), toString())); activeStream = (Closeable) value; return value; } private SQLXML getSQLXMLInternal(int columnIndex) throws SQLServerException { - SQLServerSQLXML value = (SQLServerSQLXML) getValue(columnIndex, JDBCType.SQLXML, - new InputStreamGetterArgs(StreamType.SQLXML, stmt.getExecProps().isResponseBufferingAdaptive(), isForwardOnly(), toString())); + SQLServerSQLXML value = (SQLServerSQLXML) getValue(columnIndex, JDBCType.SQLXML, new InputStreamGetterArgs( + StreamType.SQLXML, stmt.getExecProps().isResponseBufferingAdaptive(), isForwardOnly(), toString())); if (null != value) activeStream = value.getStream(); @@ -2078,8 +2084,7 @@ public java.io.InputStream getAsciiStream(String columnName) throws SQLServerExc @Deprecated @Override - public BigDecimal getBigDecimal(int columnIndex, - int scale) throws SQLServerException { + public BigDecimal getBigDecimal(int columnIndex, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "getBigDecimal", new Object[] {columnIndex, scale}); checkClosed(); @@ -2092,8 +2097,7 @@ public BigDecimal getBigDecimal(int columnIndex, @Deprecated @Override - public BigDecimal getBigDecimal(String columnName, - int scale) throws SQLServerException { + public BigDecimal getBigDecimal(String columnName, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "columnName", new Object[] {columnName, scale}); checkClosed(); @@ -2195,8 +2199,7 @@ public java.sql.Date getDate(String columnName) throws SQLServerException { } @Override - public java.sql.Date getDate(int columnIndex, - Calendar cal) throws SQLServerException { + public java.sql.Date getDate(int columnIndex, Calendar cal) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "getDate", new Object[] {columnIndex, cal}); checkClosed(); @@ -2206,8 +2209,7 @@ public java.sql.Date getDate(int columnIndex, } @Override - public java.sql.Date getDate(String colName, - Calendar cal) throws SQLServerException { + public java.sql.Date getDate(String colName, Calendar cal) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "getDate", new Object[] {colName, cal}); checkClosed(); @@ -2344,83 +2346,64 @@ public Object getObject(int columnIndex) throws SQLServerException { } @Override - public T getObject(int columnIndex, - Class type) throws SQLException { + public T getObject(int columnIndex, Class type) throws SQLException { loggerExternal.entering(getClassNameLogging(), "getObject", columnIndex); checkClosed(); Object returnValue; if (type == String.class) { returnValue = getString(columnIndex); - } - else if (type == Byte.class) { + } else if (type == Byte.class) { byte byteValue = getByte(columnIndex); returnValue = wasNull() ? null : byteValue; - } - else if (type == Short.class) { + } else if (type == Short.class) { short shortValue = getShort(columnIndex); returnValue = wasNull() ? null : shortValue; - } - else if (type == Integer.class) { + } else if (type == Integer.class) { int intValue = getInt(columnIndex); returnValue = wasNull() ? null : intValue; - } - else if (type == Long.class) { + } else if (type == Long.class) { long longValue = getLong(columnIndex); returnValue = wasNull() ? null : longValue; - } - else if (type == BigDecimal.class) { + } else if (type == BigDecimal.class) { returnValue = getBigDecimal(columnIndex); - } - else if (type == Boolean.class) { + } else if (type == Boolean.class) { boolean booleanValue = getBoolean(columnIndex); returnValue = wasNull() ? null : booleanValue; - } - else if (type == java.sql.Date.class) { + } else if (type == java.sql.Date.class) { returnValue = getDate(columnIndex); - } - else if (type == java.sql.Time.class) { + } else if (type == java.sql.Time.class) { returnValue = getTime(columnIndex); - } - else if (type == java.sql.Timestamp.class) { + } else if (type == java.sql.Timestamp.class) { returnValue = getTimestamp(columnIndex); - } - else if (type == microsoft.sql.DateTimeOffset.class) { + } else if (type == microsoft.sql.DateTimeOffset.class) { returnValue = getDateTimeOffset(columnIndex); - } - else if (type == UUID.class) { + } else if (type == UUID.class) { // read binary, avoid string allocation and parsing byte[] guid = getBytes(columnIndex); returnValue = guid != null ? Util.readGUIDtoUUID(guid) : null; - } - else if (type == SQLXML.class) { + } else if (type == SQLXML.class) { returnValue = getSQLXML(columnIndex); - } - else if (type == Blob.class) { + } else if (type == Blob.class) { returnValue = getBlob(columnIndex); - } - else if (type == Clob.class) { + } else if (type == Clob.class) { returnValue = getClob(columnIndex); - } - else if (type == NClob.class) { + } else if (type == NClob.class) { returnValue = getNClob(columnIndex); - } - else if (type == byte[].class) { + } else if (type == byte[].class) { returnValue = getBytes(columnIndex); - } - else if (type == Float.class) { + } else if (type == Float.class) { float floatValue = getFloat(columnIndex); returnValue = wasNull() ? null : floatValue; - } - else if (type == Double.class) { + } else if (type == Double.class) { double doubleValue = getDouble(columnIndex); returnValue = wasNull() ? null : doubleValue; - } - else { + } else { // if the type is not supported the specification says the should // a SQLException instead of SQLFeatureNotSupportedException MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_unsupportedConversionTo")); Object[] msgArgs = {type}; - throw new SQLServerException(form.format(msgArgs), SQLState.DATA_EXCEPTION_NOT_SPECIFIC, DriverError.NOT_SET, null); + throw new SQLServerException(form.format(msgArgs), SQLState.DATA_EXCEPTION_NOT_SPECIFIC, + DriverError.NOT_SET, null); } loggerExternal.exiting(getClassNameLogging(), "getObject", columnIndex); return type.cast(returnValue); @@ -2436,8 +2419,7 @@ public Object getObject(String columnName) throws SQLServerException { } @Override - public T getObject(String columnName, - Class type) throws SQLException { + public T getObject(String columnName, Class type) throws SQLException { loggerExternal.entering(getClassNameLogging(), "getObject", columnName); checkClosed(); T value = getObject(findColumn(columnName), type); @@ -2546,8 +2528,7 @@ public java.sql.Time getTime(String columnName) throws SQLServerException { } @Override - public java.sql.Time getTime(int columnIndex, - Calendar cal) throws SQLServerException { + public java.sql.Time getTime(int columnIndex, Calendar cal) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "getTime", new Object[] {columnIndex, cal}); checkClosed(); @@ -2557,8 +2538,7 @@ public java.sql.Time getTime(int columnIndex, } @Override - public java.sql.Time getTime(String colName, - Calendar cal) throws SQLServerException { + public java.sql.Time getTime(String colName, Calendar cal) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "getTime", new Object[] {colName, cal}); checkClosed(); @@ -2586,8 +2566,7 @@ public java.sql.Timestamp getTimestamp(String columnName) throws SQLServerExcept } @Override - public java.sql.Timestamp getTimestamp(int columnIndex, - Calendar cal) throws SQLServerException { + public java.sql.Timestamp getTimestamp(int columnIndex, Calendar cal) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "getTimestamp", new Object[] {columnIndex, cal}); checkClosed(); @@ -2597,8 +2576,7 @@ public java.sql.Timestamp getTimestamp(int columnIndex, } @Override - public java.sql.Timestamp getTimestamp(String colName, - Calendar cal) throws SQLServerException { + public java.sql.Timestamp getTimestamp(String colName, Calendar cal) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "getTimestamp", new Object[] {colName, cal}); checkClosed(); @@ -2626,8 +2604,7 @@ public java.sql.Timestamp getDateTime(String columnName) throws SQLServerExcepti } @Override - public java.sql.Timestamp getDateTime(int columnIndex, - Calendar cal) throws SQLServerException { + public java.sql.Timestamp getDateTime(int columnIndex, Calendar cal) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "getDateTime", new Object[] {columnIndex, cal}); checkClosed(); @@ -2637,8 +2614,7 @@ public java.sql.Timestamp getDateTime(int columnIndex, } @Override - public java.sql.Timestamp getDateTime(String colName, - Calendar cal) throws SQLServerException { + public java.sql.Timestamp getDateTime(String colName, Calendar cal) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "getDateTime", new Object[] {colName, cal}); checkClosed(); @@ -2666,8 +2642,7 @@ public java.sql.Timestamp getSmallDateTime(String columnName) throws SQLServerEx } @Override - public java.sql.Timestamp getSmallDateTime(int columnIndex, - Calendar cal) throws SQLServerException { + public java.sql.Timestamp getSmallDateTime(int columnIndex, Calendar cal) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "getSmallDateTime", new Object[] {columnIndex, cal}); checkClosed(); @@ -2677,8 +2652,7 @@ public java.sql.Timestamp getSmallDateTime(int columnIndex, } @Override - public java.sql.Timestamp getSmallDateTime(String colName, - Calendar cal) throws SQLServerException { + public java.sql.Timestamp getSmallDateTime(String colName, Calendar cal) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "getSmallDateTime", new Object[] {colName, cal}); checkClosed(); @@ -2694,10 +2668,11 @@ public microsoft.sql.DateTimeOffset getDateTimeOffset(int columnIndex) throws SQ // DateTimeOffset is not supported with SQL Server versions earlier than Katmai if (!stmt.connection.isKatmaiOrLater()) - throw new SQLServerException(SQLServerException.getErrString("R_notSupported"), SQLState.DATA_EXCEPTION_NOT_SPECIFIC, DriverError.NOT_SET, - null); + throw new SQLServerException(SQLServerException.getErrString("R_notSupported"), + SQLState.DATA_EXCEPTION_NOT_SPECIFIC, DriverError.NOT_SET, null); - microsoft.sql.DateTimeOffset value = (microsoft.sql.DateTimeOffset) getValue(columnIndex, JDBCType.DATETIMEOFFSET); + microsoft.sql.DateTimeOffset value = (microsoft.sql.DateTimeOffset) getValue(columnIndex, + JDBCType.DATETIMEOFFSET); loggerExternal.exiting(getClassNameLogging(), "getDateTimeOffset", value); return value; } @@ -2709,10 +2684,11 @@ public microsoft.sql.DateTimeOffset getDateTimeOffset(String columnName) throws // DateTimeOffset is not supported with SQL Server versions earlier than Katmai if (!stmt.connection.isKatmaiOrLater()) - throw new SQLServerException(SQLServerException.getErrString("R_notSupported"), SQLState.DATA_EXCEPTION_NOT_SPECIFIC, DriverError.NOT_SET, - null); + throw new SQLServerException(SQLServerException.getErrString("R_notSupported"), + SQLState.DATA_EXCEPTION_NOT_SPECIFIC, DriverError.NOT_SET, null); - microsoft.sql.DateTimeOffset value = (microsoft.sql.DateTimeOffset) getValue(findColumn(columnName), JDBCType.DATETIMEOFFSET); + microsoft.sql.DateTimeOffset value = (microsoft.sql.DateTimeOffset) getValue(findColumn(columnName), + JDBCType.DATETIMEOFFSET); loggerExternal.exiting(getClassNameLogging(), "getDateTimeOffset", value); return value; } @@ -2734,8 +2710,7 @@ public java.io.InputStream getUnicodeStream(String columnName) throws SQLExcepti } @Override - public Object getObject(int i, - java.util.Map> map) throws SQLException { + public Object getObject(int i, java.util.Map> map) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "getObject", new Object[] {i, map}); SQLServerException.throwNotSupportedException(stmt.connection, stmt); @@ -2816,8 +2791,7 @@ public Array getArray(int i) throws SQLException { } @Override - public Object getObject(String colName, - java.util.Map> map) throws SQLException { + public Object getObject(String colName, java.util.Map> map) throws SQLException { SQLServerException.throwNotSupportedException(stmt.connection, stmt); return null; } @@ -2837,7 +2811,8 @@ public Array getArray(String colName) throws SQLException { @Override public String getCursorName() throws SQLException { loggerExternal.entering(getClassNameLogging(), "getCursorName"); - SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_positionedUpdatesNotSupported"), null, false); + SQLServerException.makeFromDriverError(null, null, + SQLServerException.getErrString("R_positionedUpdatesNotSupported"), null, false); loggerExternal.exiting(getClassNameLogging(), "getCursorName", null); return null; } @@ -3009,8 +2984,8 @@ public boolean rowDeleted() throws SQLServerException { /** * Determines whether the current row of this result set is deleted. * - * A row may be deleted via the result set cursor (via ResultSet.deleteRow) or it may have been deleted outside the cursor. This function checks - * for both possibilities. + * A row may be deleted via the result set cursor (via ResultSet.deleteRow) or it may have been deleted outside the + * cursor. This function checks for both possibilities. */ private boolean currentRowDeleted() throws SQLServerException { // Never call this function without a current row @@ -3019,7 +2994,8 @@ private boolean currentRowDeleted() throws SQLServerException { // Having a current row implies we have a fetch buffer in which that row exists. assert null != tdsReader; - return deletedCurrentRow || (0 != serverCursorId && TDS.ROWSTAT_FETCH_MISSING == loadColumn(columns.length).getInt(tdsReader)); + return deletedCurrentRow + || (0 != serverCursorId && TDS.ROWSTAT_FETCH_MISSING == loadColumn(columns.length).getInt(tdsReader)); } /* ---------------- Column updates ---------------------- */ @@ -3028,7 +3004,7 @@ private boolean currentRowDeleted() throws SQLServerException { * Does all the common stuff necessary when calling a getter for the column at index. * * @param index - * the index of the column to get + * the index of the column to get */ private Column updaterGetColumn(int index) throws SQLServerException { // From JDBC spec: @@ -3039,7 +3015,8 @@ private Column updaterGetColumn(int index) throws SQLServerException { // Verify that the column is updatable (i.e. that it is not a computed column). if (!columns[index - 1].isUpdatable()) { - SQLServerException.makeFromDriverError(stmt.connection, stmt, SQLServerException.getErrString("R_cantUpdateColumn"), "07009", false); + SQLServerException.makeFromDriverError(stmt.connection, stmt, + SQLServerException.getErrString("R_cantUpdateColumn"), "07009", false); } // Column values on the insert row are always updatable, @@ -3050,7 +3027,8 @@ private Column updaterGetColumn(int index) throws SQLServerException { // that this ResultSet has a current row (i.e. that the ResultSet's position // is not before the first row or after the last row). if (!hasCurrentRow()) { - SQLServerException.makeFromDriverError(stmt.connection, stmt, SQLServerException.getErrString("R_resultsetNoCurrentRow"), null, true); + SQLServerException.makeFromDriverError(stmt.connection, stmt, + SQLServerException.getErrString("R_resultsetNoCurrentRow"), null, true); } // A current row exists. Its column values are updatable only if the row @@ -3061,47 +3039,32 @@ private Column updaterGetColumn(int index) throws SQLServerException { return getColumn(index); } - private void updateValue(int columnIndex, - JDBCType jdbcType, - Object value, - JavaType javaType, + private void updateValue(int columnIndex, JDBCType jdbcType, Object value, JavaType javaType, boolean forceEncrypt) throws SQLServerException { - updaterGetColumn(columnIndex).updateValue(jdbcType, value, javaType, null, null, null, stmt.connection, stmt.stmtColumnEncriptionSetting, - null, forceEncrypt, columnIndex); + updaterGetColumn(columnIndex).updateValue(jdbcType, value, javaType, null, null, null, stmt.connection, + stmt.stmtColumnEncriptionSetting, null, forceEncrypt, columnIndex); } - private void updateValue(int columnIndex, - JDBCType jdbcType, - Object value, - JavaType javaType, - Calendar cal, + private void updateValue(int columnIndex, JDBCType jdbcType, Object value, JavaType javaType, Calendar cal, boolean forceEncrypt) throws SQLServerException { - updaterGetColumn(columnIndex).updateValue(jdbcType, value, javaType, null, cal, null, stmt.connection, stmt.stmtColumnEncriptionSetting, null, - forceEncrypt, columnIndex); + updaterGetColumn(columnIndex).updateValue(jdbcType, value, javaType, null, cal, null, stmt.connection, + stmt.stmtColumnEncriptionSetting, null, forceEncrypt, columnIndex); } - private void updateValue(int columnIndex, - JDBCType jdbcType, - Object value, - JavaType javaType, - Integer precision, - Integer scale, - boolean forceEncrypt) throws SQLServerException { - updaterGetColumn(columnIndex).updateValue(jdbcType, value, javaType, null, null, scale, stmt.connection, stmt.stmtColumnEncriptionSetting, - precision, forceEncrypt, columnIndex); + private void updateValue(int columnIndex, JDBCType jdbcType, Object value, JavaType javaType, Integer precision, + Integer scale, boolean forceEncrypt) throws SQLServerException { + updaterGetColumn(columnIndex).updateValue(jdbcType, value, javaType, null, null, scale, stmt.connection, + stmt.stmtColumnEncriptionSetting, precision, forceEncrypt, columnIndex); } - private void updateStream(int columnIndex, - StreamType streamType, - Object value, - JavaType javaType, + private void updateStream(int columnIndex, StreamType streamType, Object value, JavaType javaType, long length) throws SQLServerException { - updaterGetColumn(columnIndex).updateValue(streamType.getJDBCType(), value, javaType, new StreamSetterArgs(streamType, length), null, null, - stmt.connection, stmt.stmtColumnEncriptionSetting, null, false, columnIndex); + updaterGetColumn(columnIndex).updateValue(streamType.getJDBCType(), value, javaType, + new StreamSetterArgs(streamType, length), null, null, stmt.connection, stmt.stmtColumnEncriptionSetting, + null, false, columnIndex); } - private void updateSQLXMLInternal(int columnIndex, - SQLXML value) throws SQLServerException { + private void updateSQLXMLInternal(int columnIndex, SQLXML value) throws SQLServerException { updaterGetColumn(columnIndex).updateValue(JDBCType.SQLXML, value, JavaType.SQLXML, new StreamSetterArgs(StreamType.SQLXML, DataTypes.UNKNOWN_STREAM_LENGTH), null, null, stmt.connection, stmt.stmtColumnEncriptionSetting, null, false, columnIndex); @@ -3112,14 +3075,14 @@ public void updateNull(int index) throws SQLServerException { loggerExternal.entering(getClassNameLogging(), "updateNull", index); checkClosed(); - updateValue(index, updaterGetColumn(index).getTypeInfo().getSSType().getJDBCType(), null, JavaType.OBJECT, false); + updateValue(index, updaterGetColumn(index).getTypeInfo().getSSType().getJDBCType(), null, JavaType.OBJECT, + false); loggerExternal.exiting(getClassNameLogging(), "updateNull"); } @Override - public void updateBoolean(int index, - boolean x) throws SQLException { + public void updateBoolean(int index, boolean x) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateBoolean", new Object[] {index, x}); checkClosed(); @@ -3129,9 +3092,7 @@ public void updateBoolean(int index, } @Override - public void updateBoolean(int index, - boolean x, - boolean forceEncrypt) throws SQLServerException { + public void updateBoolean(int index, boolean x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateBoolean", new Object[] {index, x, forceEncrypt}); checkClosed(); @@ -3141,8 +3102,7 @@ public void updateBoolean(int index, } @Override - public void updateByte(int index, - byte x) throws SQLException { + public void updateByte(int index, byte x) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateByte", new Object[] {index, x}); @@ -3153,9 +3113,7 @@ public void updateByte(int index, } @Override - public void updateByte(int index, - byte x, - boolean forceEncrypt) throws SQLServerException { + public void updateByte(int index, byte x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateByte", new Object[] {index, x, forceEncrypt}); @@ -3166,8 +3124,7 @@ public void updateByte(int index, } @Override - public void updateShort(int index, - short x) throws SQLException { + public void updateShort(int index, short x) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateShort", new Object[] {index, x}); @@ -3178,9 +3135,7 @@ public void updateShort(int index, } @Override - public void updateShort(int index, - short x, - boolean forceEncrypt) throws SQLServerException { + public void updateShort(int index, short x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateShort", new Object[] {index, x, forceEncrypt}); @@ -3191,8 +3146,7 @@ public void updateShort(int index, } @Override - public void updateInt(int index, - int x) throws SQLException { + public void updateInt(int index, int x) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateInt", new Object[] {index, x}); @@ -3203,9 +3157,7 @@ public void updateInt(int index, } @Override - public void updateInt(int index, - int x, - boolean forceEncrypt) throws SQLServerException { + public void updateInt(int index, int x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateInt", new Object[] {index, x, forceEncrypt}); @@ -3216,8 +3168,7 @@ public void updateInt(int index, } @Override - public void updateLong(int index, - long x) throws SQLException { + public void updateLong(int index, long x) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateLong", new Object[] {index, x}); @@ -3228,9 +3179,7 @@ public void updateLong(int index, } @Override - public void updateLong(int index, - long x, - boolean forceEncrypt) throws SQLServerException { + public void updateLong(int index, long x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateLong", new Object[] {index, x, forceEncrypt}); @@ -3241,8 +3190,7 @@ public void updateLong(int index, } @Override - public void updateFloat(int index, - float x) throws SQLException { + public void updateFloat(int index, float x) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateFloat", new Object[] {index, x}); @@ -3253,9 +3201,7 @@ public void updateFloat(int index, } @Override - public void updateFloat(int index, - float x, - boolean forceEncrypt) throws SQLServerException { + public void updateFloat(int index, float x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateFloat", new Object[] {index, x, forceEncrypt}); @@ -3266,8 +3212,7 @@ public void updateFloat(int index, } @Override - public void updateDouble(int index, - double x) throws SQLException { + public void updateDouble(int index, double x) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateDouble", new Object[] {index, x}); @@ -3278,9 +3223,7 @@ public void updateDouble(int index, } @Override - public void updateDouble(int index, - double x, - boolean forceEncrypt) throws SQLServerException { + public void updateDouble(int index, double x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateDouble", new Object[] {index, x, forceEncrypt}); @@ -3291,8 +3234,7 @@ public void updateDouble(int index, } @Override - public void updateMoney(int index, - BigDecimal x) throws SQLServerException { + public void updateMoney(int index, BigDecimal x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateMoney", new Object[] {index, x}); checkClosed(); @@ -3302,9 +3244,7 @@ public void updateMoney(int index, } @Override - public void updateMoney(int index, - BigDecimal x, - boolean forceEncrypt) throws SQLServerException { + public void updateMoney(int index, BigDecimal x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateMoney", new Object[] {index, x, forceEncrypt}); checkClosed(); @@ -3314,8 +3254,7 @@ public void updateMoney(int index, } @Override - public void updateMoney(String columnName, - BigDecimal x) throws SQLServerException { + public void updateMoney(String columnName, BigDecimal x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateMoney", new Object[] {columnName, x}); checkClosed(); @@ -3325,9 +3264,7 @@ public void updateMoney(String columnName, } @Override - public void updateMoney(String columnName, - BigDecimal x, - boolean forceEncrypt) throws SQLServerException { + public void updateMoney(String columnName, BigDecimal x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateMoney", new Object[] {columnName, x, forceEncrypt}); checkClosed(); @@ -3337,8 +3274,7 @@ public void updateMoney(String columnName, } @Override - public void updateSmallMoney(int index, - BigDecimal x) throws SQLServerException { + public void updateSmallMoney(int index, BigDecimal x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateSmallMoney", new Object[] {index, x}); checkClosed(); @@ -3348,9 +3284,7 @@ public void updateSmallMoney(int index, } @Override - public void updateSmallMoney(int index, - BigDecimal x, - boolean forceEncrypt) throws SQLServerException { + public void updateSmallMoney(int index, BigDecimal x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateSmallMoney", new Object[] {index, x, forceEncrypt}); checkClosed(); @@ -3360,8 +3294,7 @@ public void updateSmallMoney(int index, } @Override - public void updateSmallMoney(String columnName, - BigDecimal x) throws SQLServerException { + public void updateSmallMoney(String columnName, BigDecimal x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateSmallMoney", new Object[] {columnName, x}); checkClosed(); @@ -3371,11 +3304,10 @@ public void updateSmallMoney(String columnName, } @Override - public void updateSmallMoney(String columnName, - BigDecimal x, - boolean forceEncrypt) throws SQLServerException { + public void updateSmallMoney(String columnName, BigDecimal x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateSmallMoney", new Object[] {columnName, x, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "updateSmallMoney", + new Object[] {columnName, x, forceEncrypt}); checkClosed(); updateValue(findColumn(columnName), JDBCType.SMALLMONEY, x, JavaType.BIGDECIMAL, forceEncrypt); @@ -3383,8 +3315,7 @@ public void updateSmallMoney(String columnName, } @Override - public void updateBigDecimal(int index, - BigDecimal x) throws SQLServerException { + public void updateBigDecimal(int index, BigDecimal x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateBigDecimal", new Object[] {index, x}); @@ -3395,10 +3326,7 @@ public void updateBigDecimal(int index, } @Override - public void updateBigDecimal(int index, - BigDecimal x, - Integer precision, - Integer scale) throws SQLServerException { + public void updateBigDecimal(int index, BigDecimal x, Integer precision, Integer scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateBigDecimal", new Object[] {index, x, scale}); @@ -3409,13 +3337,11 @@ public void updateBigDecimal(int index, } @Override - public void updateBigDecimal(int index, - BigDecimal x, - Integer precision, - Integer scale, + public void updateBigDecimal(int index, BigDecimal x, Integer precision, Integer scale, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateBigDecimal", new Object[] {index, x, scale, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "updateBigDecimal", + new Object[] {index, x, scale, forceEncrypt}); checkClosed(); updateValue(index, JDBCType.DECIMAL, x, JavaType.BIGDECIMAL, precision, scale, forceEncrypt); @@ -3424,8 +3350,7 @@ public void updateBigDecimal(int index, } @Override - public void updateString(int columnIndex, - String stringValue) throws SQLServerException { + public void updateString(int columnIndex, String stringValue) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateString", new Object[] {columnIndex, stringValue}); @@ -3436,11 +3361,10 @@ public void updateString(int columnIndex, } @Override - public void updateString(int columnIndex, - String stringValue, - boolean forceEncrypt) throws SQLServerException { + public void updateString(int columnIndex, String stringValue, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateString", new Object[] {columnIndex, stringValue, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "updateString", + new Object[] {columnIndex, stringValue, forceEncrypt}); checkClosed(); updateValue(columnIndex, JDBCType.VARCHAR, stringValue, JavaType.STRING, forceEncrypt); @@ -3449,8 +3373,7 @@ public void updateString(int columnIndex, } @Override - public void updateNString(int columnIndex, - String nString) throws SQLException { + public void updateNString(int columnIndex, String nString) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateNString", new Object[] {columnIndex, nString}); @@ -3461,11 +3384,10 @@ public void updateNString(int columnIndex, } @Override - public void updateNString(int columnIndex, - String nString, - boolean forceEncrypt) throws SQLServerException { + public void updateNString(int columnIndex, String nString, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateNString", new Object[] {columnIndex, nString, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "updateNString", + new Object[] {columnIndex, nString, forceEncrypt}); checkClosed(); updateValue(columnIndex, JDBCType.NVARCHAR, nString, JavaType.STRING, forceEncrypt); @@ -3474,8 +3396,7 @@ public void updateNString(int columnIndex, } @Override - public void updateNString(String columnLabel, - String nString) throws SQLException { + public void updateNString(String columnLabel, String nString) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateNString", new Object[] {columnLabel, nString}); @@ -3486,11 +3407,10 @@ public void updateNString(String columnLabel, } @Override - public void updateNString(String columnLabel, - String nString, - boolean forceEncrypt) throws SQLServerException { + public void updateNString(String columnLabel, String nString, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateNString", new Object[] {columnLabel, nString, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "updateNString", + new Object[] {columnLabel, nString, forceEncrypt}); checkClosed(); updateValue(findColumn(columnLabel), JDBCType.NVARCHAR, nString, JavaType.STRING, forceEncrypt); @@ -3499,8 +3419,7 @@ public void updateNString(String columnLabel, } @Override - public void updateBytes(int index, - byte x[]) throws SQLException { + public void updateBytes(int index, byte x[]) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateBytes", new Object[] {index, x}); @@ -3511,9 +3430,7 @@ public void updateBytes(int index, } @Override - public void updateBytes(int index, - byte x[], - boolean forceEncrypt) throws SQLServerException { + public void updateBytes(int index, byte x[], boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateBytes", new Object[] {index, x, forceEncrypt}); @@ -3524,8 +3441,7 @@ public void updateBytes(int index, } @Override - public void updateDate(int index, - java.sql.Date x) throws SQLServerException { + public void updateDate(int index, java.sql.Date x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateDate", new Object[] {index, x}); @@ -3536,9 +3452,7 @@ public void updateDate(int index, } @Override - public void updateDate(int index, - java.sql.Date x, - boolean forceEncrypt) throws SQLServerException { + public void updateDate(int index, java.sql.Date x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateDate", new Object[] {index, x, forceEncrypt}); @@ -3549,8 +3463,7 @@ public void updateDate(int index, } @Override - public void updateTime(int index, - java.sql.Time x) throws SQLServerException { + public void updateTime(int index, java.sql.Time x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateTime", new Object[] {index, x}); @@ -3561,9 +3474,7 @@ public void updateTime(int index, } @Override - public void updateTime(int index, - java.sql.Time x, - Integer scale) throws SQLServerException { + public void updateTime(int index, java.sql.Time x, Integer scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateTime", new Object[] {index, x, scale}); @@ -3574,10 +3485,7 @@ public void updateTime(int index, } @Override - public void updateTime(int index, - java.sql.Time x, - Integer scale, - boolean forceEncrypt) throws SQLServerException { + public void updateTime(int index, java.sql.Time x, Integer scale, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateTime", new Object[] {index, x, scale, forceEncrypt}); @@ -3588,8 +3496,7 @@ public void updateTime(int index, } @Override - public void updateTimestamp(int index, - java.sql.Timestamp x) throws SQLServerException { + public void updateTimestamp(int index, java.sql.Timestamp x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateTimestamp", new Object[] {index, x}); @@ -3600,9 +3507,7 @@ public void updateTimestamp(int index, } @Override - public void updateTimestamp(int index, - java.sql.Timestamp x, - int scale) throws SQLServerException { + public void updateTimestamp(int index, java.sql.Timestamp x, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateTimestamp", new Object[] {index, x, scale}); @@ -3613,12 +3518,11 @@ public void updateTimestamp(int index, } @Override - public void updateTimestamp(int index, - java.sql.Timestamp x, - int scale, + public void updateTimestamp(int index, java.sql.Timestamp x, int scale, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateTimestamp", new Object[] {index, x, scale, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "updateTimestamp", + new Object[] {index, x, scale, forceEncrypt}); checkClosed(); updateValue(index, JDBCType.TIMESTAMP, x, JavaType.TIMESTAMP, null, scale, forceEncrypt); @@ -3627,8 +3531,7 @@ public void updateTimestamp(int index, } @Override - public void updateDateTime(int index, - java.sql.Timestamp x) throws SQLServerException { + public void updateDateTime(int index, java.sql.Timestamp x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateDateTime", new Object[] {index, x}); @@ -3639,9 +3542,7 @@ public void updateDateTime(int index, } @Override - public void updateDateTime(int index, - java.sql.Timestamp x, - Integer scale) throws SQLServerException { + public void updateDateTime(int index, java.sql.Timestamp x, Integer scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateDateTime", new Object[] {index, x, scale}); @@ -3652,12 +3553,11 @@ public void updateDateTime(int index, } @Override - public void updateDateTime(int index, - java.sql.Timestamp x, - Integer scale, + public void updateDateTime(int index, java.sql.Timestamp x, Integer scale, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateDateTime", new Object[] {index, x, scale, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "updateDateTime", + new Object[] {index, x, scale, forceEncrypt}); checkClosed(); updateValue(index, JDBCType.DATETIME, x, JavaType.TIMESTAMP, null, scale, forceEncrypt); @@ -3666,8 +3566,7 @@ public void updateDateTime(int index, } @Override - public void updateSmallDateTime(int index, - java.sql.Timestamp x) throws SQLServerException { + public void updateSmallDateTime(int index, java.sql.Timestamp x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateSmallDateTime", new Object[] {index, x}); @@ -3678,9 +3577,7 @@ public void updateSmallDateTime(int index, } @Override - public void updateSmallDateTime(int index, - java.sql.Timestamp x, - Integer scale) throws SQLServerException { + public void updateSmallDateTime(int index, java.sql.Timestamp x, Integer scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateSmallDateTime", new Object[] {index, x, scale}); @@ -3691,12 +3588,11 @@ public void updateSmallDateTime(int index, } @Override - public void updateSmallDateTime(int index, - java.sql.Timestamp x, - Integer scale, + public void updateSmallDateTime(int index, java.sql.Timestamp x, Integer scale, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateSmallDateTime", new Object[] {index, x, scale, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "updateSmallDateTime", + new Object[] {index, x, scale, forceEncrypt}); checkClosed(); updateValue(index, JDBCType.SMALLDATETIME, x, JavaType.TIMESTAMP, null, scale, forceEncrypt); @@ -3705,8 +3601,7 @@ public void updateSmallDateTime(int index, } @Override - public void updateDateTimeOffset(int index, - microsoft.sql.DateTimeOffset x) throws SQLServerException { + public void updateDateTimeOffset(int index, microsoft.sql.DateTimeOffset x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateDateTimeOffset", new Object[] {index, x}); @@ -3717,8 +3612,7 @@ public void updateDateTimeOffset(int index, } @Override - public void updateDateTimeOffset(int index, - microsoft.sql.DateTimeOffset x, + public void updateDateTimeOffset(int index, microsoft.sql.DateTimeOffset x, Integer scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateDateTimeOffset", new Object[] {index, x, scale}); @@ -3730,12 +3624,11 @@ public void updateDateTimeOffset(int index, } @Override - public void updateDateTimeOffset(int index, - microsoft.sql.DateTimeOffset x, - Integer scale, + public void updateDateTimeOffset(int index, microsoft.sql.DateTimeOffset x, Integer scale, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateDateTimeOffset", new Object[] {index, x, scale, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "updateDateTimeOffset", + new Object[] {index, x, scale, forceEncrypt}); checkClosed(); updateValue(index, JDBCType.DATETIMEOFFSET, x, JavaType.DATETIMEOFFSET, null, scale, forceEncrypt); @@ -3744,8 +3637,7 @@ public void updateDateTimeOffset(int index, } @Override - public void updateUniqueIdentifier(int index, - String x) throws SQLServerException { + public void updateUniqueIdentifier(int index, String x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateUniqueIdentifier", new Object[] {index, x}); @@ -3756,11 +3648,10 @@ public void updateUniqueIdentifier(int index, } @Override - public void updateUniqueIdentifier(int index, - String x, - boolean forceEncrypt) throws SQLServerException { + public void updateUniqueIdentifier(int index, String x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateUniqueIdentifier", new Object[] {index, x, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "updateUniqueIdentifier", + new Object[] {index, x, forceEncrypt}); checkClosed(); updateValue(index, JDBCType.GUID, x, JavaType.STRING, null, forceEncrypt); @@ -3769,8 +3660,7 @@ public void updateUniqueIdentifier(int index, } @Override - public void updateAsciiStream(int columnIndex, - InputStream x) throws SQLException { + public void updateAsciiStream(int columnIndex, InputStream x) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateAsciiStream", new Object[] {columnIndex, x}); @@ -3781,9 +3671,7 @@ public void updateAsciiStream(int columnIndex, } @Override - public void updateAsciiStream(int index, - InputStream x, - int length) throws SQLServerException { + public void updateAsciiStream(int index, InputStream x, int length) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateAsciiStream", new Object[] {index, x, length}); @@ -3794,9 +3682,7 @@ public void updateAsciiStream(int index, } @Override - public void updateAsciiStream(int columnIndex, - InputStream x, - long length) throws SQLException { + public void updateAsciiStream(int columnIndex, InputStream x, long length) throws SQLException { loggerExternal.entering(getClassNameLogging(), "updateAsciiStream", new Object[] {columnIndex, x, length}); checkClosed(); @@ -3806,21 +3692,19 @@ public void updateAsciiStream(int columnIndex, } @Override - public void updateAsciiStream(String columnLabel, - InputStream x) throws SQLException { + public void updateAsciiStream(String columnLabel, InputStream x) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateAsciiStream", new Object[] {columnLabel, x}); checkClosed(); - updateStream(findColumn(columnLabel), StreamType.ASCII, x, JavaType.INPUTSTREAM, DataTypes.UNKNOWN_STREAM_LENGTH); + updateStream(findColumn(columnLabel), StreamType.ASCII, x, JavaType.INPUTSTREAM, + DataTypes.UNKNOWN_STREAM_LENGTH); loggerExternal.exiting(getClassNameLogging(), "updateAsciiStream"); } @Override - public void updateAsciiStream(java.lang.String columnName, - InputStream x, - int length) throws SQLServerException { + public void updateAsciiStream(java.lang.String columnName, InputStream x, int length) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateAsciiStream", new Object[] {columnName, x, length}); @@ -3831,11 +3715,10 @@ public void updateAsciiStream(java.lang.String columnName, } @Override - public void updateAsciiStream(String columnName, - InputStream streamValue, - long length) throws SQLException { + public void updateAsciiStream(String columnName, InputStream streamValue, long length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateAsciiStream", new Object[] {columnName, streamValue, length}); + loggerExternal.entering(getClassNameLogging(), "updateAsciiStream", + new Object[] {columnName, streamValue, length}); checkClosed(); updateStream(findColumn(columnName), StreamType.ASCII, streamValue, JavaType.INPUTSTREAM, length); @@ -3844,8 +3727,7 @@ public void updateAsciiStream(String columnName, } @Override - public void updateBinaryStream(int columnIndex, - InputStream x) throws SQLException { + public void updateBinaryStream(int columnIndex, InputStream x) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateBinaryStream", new Object[] {columnIndex, x}); @@ -3856,11 +3738,10 @@ public void updateBinaryStream(int columnIndex, } @Override - public void updateBinaryStream(int columnIndex, - InputStream streamValue, - int length) throws SQLException { + public void updateBinaryStream(int columnIndex, InputStream streamValue, int length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateBinaryStream", new Object[] {columnIndex, streamValue, length}); + loggerExternal.entering(getClassNameLogging(), "updateBinaryStream", + new Object[] {columnIndex, streamValue, length}); checkClosed(); updateStream(columnIndex, StreamType.BINARY, streamValue, JavaType.INPUTSTREAM, length); @@ -3869,9 +3750,7 @@ public void updateBinaryStream(int columnIndex, } @Override - public void updateBinaryStream(int columnIndex, - InputStream x, - long length) throws SQLException { + public void updateBinaryStream(int columnIndex, InputStream x, long length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateBinaryStream", new Object[] {columnIndex, x, length}); @@ -3882,23 +3761,22 @@ public void updateBinaryStream(int columnIndex, } @Override - public void updateBinaryStream(String columnLabel, - InputStream x) throws SQLException { + public void updateBinaryStream(String columnLabel, InputStream x) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateBinaryStream", new Object[] {columnLabel, x}); checkClosed(); - updateStream(findColumn(columnLabel), StreamType.BINARY, x, JavaType.INPUTSTREAM, DataTypes.UNKNOWN_STREAM_LENGTH); + updateStream(findColumn(columnLabel), StreamType.BINARY, x, JavaType.INPUTSTREAM, + DataTypes.UNKNOWN_STREAM_LENGTH); loggerExternal.exiting(getClassNameLogging(), "updateBinaryStream"); } @Override - public void updateBinaryStream(String columnName, - InputStream streamValue, - int length) throws SQLException { + public void updateBinaryStream(String columnName, InputStream streamValue, int length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateBinaryStream", new Object[] {columnName, streamValue, length}); + loggerExternal.entering(getClassNameLogging(), "updateBinaryStream", + new Object[] {columnName, streamValue, length}); checkClosed(); updateStream(findColumn(columnName), StreamType.BINARY, streamValue, JavaType.INPUTSTREAM, length); @@ -3907,9 +3785,7 @@ public void updateBinaryStream(String columnName, } @Override - public void updateBinaryStream(String columnLabel, - InputStream x, - long length) throws SQLException { + public void updateBinaryStream(String columnLabel, InputStream x, long length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateBinaryStream", new Object[] {columnLabel, x, length}); @@ -3920,8 +3796,7 @@ public void updateBinaryStream(String columnLabel, } @Override - public void updateCharacterStream(int columnIndex, - Reader x) throws SQLException { + public void updateCharacterStream(int columnIndex, Reader x) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateCharacterStream", new Object[] {columnIndex, x}); @@ -3932,11 +3807,10 @@ public void updateCharacterStream(int columnIndex, } @Override - public void updateCharacterStream(int columnIndex, - Reader readerValue, - int length) throws SQLServerException { + public void updateCharacterStream(int columnIndex, Reader readerValue, int length) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateCharacterStream", new Object[] {columnIndex, readerValue, length}); + loggerExternal.entering(getClassNameLogging(), "updateCharacterStream", + new Object[] {columnIndex, readerValue, length}); checkClosed(); updateStream(columnIndex, StreamType.CHARACTER, readerValue, JavaType.READER, length); @@ -3945,11 +3819,10 @@ public void updateCharacterStream(int columnIndex, } @Override - public void updateCharacterStream(int columnIndex, - Reader x, - long length) throws SQLException { + public void updateCharacterStream(int columnIndex, Reader x, long length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateCharacterStream", new Object[] {columnIndex, x, length}); + loggerExternal.entering(getClassNameLogging(), "updateCharacterStream", + new Object[] {columnIndex, x, length}); checkClosed(); updateStream(columnIndex, StreamType.CHARACTER, x, JavaType.READER, length); @@ -3958,23 +3831,22 @@ public void updateCharacterStream(int columnIndex, } @Override - public void updateCharacterStream(String columnLabel, - Reader reader) throws SQLException { + public void updateCharacterStream(String columnLabel, Reader reader) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateCharacterStream", new Object[] {columnLabel, reader}); checkClosed(); - updateStream(findColumn(columnLabel), StreamType.CHARACTER, reader, JavaType.READER, DataTypes.UNKNOWN_STREAM_LENGTH); + updateStream(findColumn(columnLabel), StreamType.CHARACTER, reader, JavaType.READER, + DataTypes.UNKNOWN_STREAM_LENGTH); loggerExternal.exiting(getClassNameLogging(), "updateCharacterStream"); } @Override - public void updateCharacterStream(String columnName, - Reader readerValue, - int length) throws SQLServerException { + public void updateCharacterStream(String columnName, Reader readerValue, int length) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateCharacterStream", new Object[] {columnName, readerValue, length}); + loggerExternal.entering(getClassNameLogging(), "updateCharacterStream", + new Object[] {columnName, readerValue, length}); checkClosed(); updateStream(findColumn(columnName), StreamType.CHARACTER, readerValue, JavaType.READER, length); @@ -3983,11 +3855,10 @@ public void updateCharacterStream(String columnName, } @Override - public void updateCharacterStream(String columnLabel, - Reader reader, - long length) throws SQLException { + public void updateCharacterStream(String columnLabel, Reader reader, long length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateCharacterStream", new Object[] {columnLabel, reader, length}); + loggerExternal.entering(getClassNameLogging(), "updateCharacterStream", + new Object[] {columnLabel, reader, length}); checkClosed(); updateStream(findColumn(columnLabel), StreamType.CHARACTER, reader, JavaType.READER, length); @@ -3996,8 +3867,7 @@ public void updateCharacterStream(String columnLabel, } @Override - public void updateNCharacterStream(int columnIndex, - Reader x) throws SQLException { + public void updateNCharacterStream(int columnIndex, Reader x) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateNCharacterStream", new Object[] {columnIndex, x}); @@ -4008,11 +3878,10 @@ public void updateNCharacterStream(int columnIndex, } @Override - public void updateNCharacterStream(int columnIndex, - Reader x, - long length) throws SQLException { + public void updateNCharacterStream(int columnIndex, Reader x, long length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateNCharacterStream", new Object[] {columnIndex, x, length}); + loggerExternal.entering(getClassNameLogging(), "updateNCharacterStream", + new Object[] {columnIndex, x, length}); checkClosed(); updateStream(columnIndex, StreamType.NCHARACTER, x, JavaType.READER, length); @@ -4021,23 +3890,23 @@ public void updateNCharacterStream(int columnIndex, } @Override - public void updateNCharacterStream(String columnLabel, - Reader reader) throws SQLException { + public void updateNCharacterStream(String columnLabel, Reader reader) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateNCharacterStream", new Object[] {columnLabel, reader}); + loggerExternal.entering(getClassNameLogging(), "updateNCharacterStream", + new Object[] {columnLabel, reader}); checkClosed(); - updateStream(findColumn(columnLabel), StreamType.NCHARACTER, reader, JavaType.READER, DataTypes.UNKNOWN_STREAM_LENGTH); + updateStream(findColumn(columnLabel), StreamType.NCHARACTER, reader, JavaType.READER, + DataTypes.UNKNOWN_STREAM_LENGTH); loggerExternal.exiting(getClassNameLogging(), "updateNCharacterStream"); } @Override - public void updateNCharacterStream(String columnLabel, - Reader reader, - long length) throws SQLException { + public void updateNCharacterStream(String columnLabel, Reader reader, long length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateNCharacterStream", new Object[] {columnLabel, reader, length}); + loggerExternal.entering(getClassNameLogging(), "updateNCharacterStream", + new Object[] {columnLabel, reader, length}); checkClosed(); updateStream(findColumn(columnLabel), StreamType.NCHARACTER, reader, JavaType.READER, length); @@ -4046,8 +3915,7 @@ public void updateNCharacterStream(String columnLabel, } @Override - public void updateObject(int index, - Object obj) throws SQLServerException { + public void updateObject(int index, Object obj) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateObject", new Object[] {index, obj}); @@ -4058,9 +3926,7 @@ public void updateObject(int index, } @Override - public void updateObject(int index, - Object x, - int scale) throws SQLServerException { + public void updateObject(int index, Object x, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateObject", new Object[] {index, x, scale}); @@ -4071,10 +3937,7 @@ public void updateObject(int index, } @Override - public void updateObject(int index, - Object x, - int precision, - int scale) throws SQLServerException { + public void updateObject(int index, Object x, int precision, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateObject", new Object[] {index, x, scale}); @@ -4085,13 +3948,11 @@ public void updateObject(int index, } @Override - public void updateObject(int index, - Object x, - int precision, - int scale, + public void updateObject(int index, Object x, int precision, int scale, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateObject", new Object[] {index, x, scale, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "updateObject", + new Object[] {index, x, scale, forceEncrypt}); checkClosed(); updateObject(index, x, scale, null, precision, forceEncrypt); @@ -4099,11 +3960,7 @@ public void updateObject(int index, loggerExternal.exiting(getClassNameLogging(), "updateObject"); } - protected final void updateObject(int index, - Object x, - Integer scale, - JDBCType jdbcType, - Integer precision, + protected final void updateObject(int index, Object x, Integer scale, JDBCType jdbcType, Integer precision, boolean forceEncrypt) throws SQLServerException { Column column = updaterGetColumn(index); SSType ssType = column.getTypeInfo().getSSType(); @@ -4116,16 +3973,14 @@ protected final void updateObject(int index, column.updateValue(jdbcType, x, JavaType.OBJECT, null, // streamSetterArgs null, scale, stmt.connection, stmt.stmtColumnEncriptionSetting, precision, forceEncrypt, index); - } - else { + } else { JavaType javaType = JavaType.of(x); JDBCType objectJdbcType = javaType.getJDBCType(ssType, ssType.getJDBCType()); if (null == jdbcType) { // JDBCType is not specified by user, derive from the object's JavaType jdbcType = objectJdbcType; - } - else { + } else { // Check convertibility of the value to the desired JDBC type. if (!objectJdbcType.convertsTo(jdbcType)) DataTypes.throwConversionError(objectJdbcType.toString(), jdbcType.toString()); @@ -4138,7 +3993,8 @@ protected final void updateObject(int index, break; case INPUTSTREAM: - streamSetterArgs = new StreamSetterArgs(jdbcType.isTextual() ? StreamType.CHARACTER : StreamType.BINARY, + streamSetterArgs = new StreamSetterArgs( + jdbcType.isTextual() ? StreamType.CHARACTER : StreamType.BINARY, DataTypes.UNKNOWN_STREAM_LENGTH); break; @@ -4151,8 +4007,8 @@ protected final void updateObject(int index, break; } - column.updateValue(jdbcType, x, javaType, streamSetterArgs, null, scale, stmt.connection, stmt.stmtColumnEncriptionSetting, precision, - forceEncrypt, index); + column.updateValue(jdbcType, x, javaType, streamSetterArgs, null, scale, stmt.connection, + stmt.stmtColumnEncriptionSetting, precision, forceEncrypt, index); } } @@ -4162,14 +4018,14 @@ public void updateNull(String columnName) throws SQLServerException { checkClosed(); int columnIndex = findColumn(columnName); - updateValue(columnIndex, updaterGetColumn(columnIndex).getTypeInfo().getSSType().getJDBCType(), null, JavaType.OBJECT, false); + updateValue(columnIndex, updaterGetColumn(columnIndex).getTypeInfo().getSSType().getJDBCType(), null, + JavaType.OBJECT, false); loggerExternal.exiting(getClassNameLogging(), "updateNull"); } @Override - public void updateBoolean(String columnName, - boolean x) throws SQLServerException { + public void updateBoolean(String columnName, boolean x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateBoolean", new Object[] {columnName, x}); @@ -4180,9 +4036,7 @@ public void updateBoolean(String columnName, } @Override - public void updateBoolean(String columnName, - boolean x, - boolean forceEncrypt) throws SQLServerException { + public void updateBoolean(String columnName, boolean x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateBoolean", new Object[] {columnName, x, forceEncrypt}); @@ -4193,8 +4047,7 @@ public void updateBoolean(String columnName, } @Override - public void updateByte(String columnName, - byte x) throws SQLServerException { + public void updateByte(String columnName, byte x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateByte", new Object[] {columnName, x}); @@ -4205,9 +4058,7 @@ public void updateByte(String columnName, } @Override - public void updateByte(String columnName, - byte x, - boolean forceEncrypt) throws SQLServerException { + public void updateByte(String columnName, byte x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateByte", new Object[] {columnName, x, forceEncrypt}); @@ -4218,8 +4069,7 @@ public void updateByte(String columnName, } @Override - public void updateShort(String columnName, - short x) throws SQLServerException { + public void updateShort(String columnName, short x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateShort", new Object[] {columnName, x}); @@ -4230,9 +4080,7 @@ public void updateShort(String columnName, } @Override - public void updateShort(String columnName, - short x, - boolean forceEncrypt) throws SQLServerException { + public void updateShort(String columnName, short x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateShort", new Object[] {columnName, x, forceEncrypt}); @@ -4243,8 +4091,7 @@ public void updateShort(String columnName, } @Override - public void updateInt(String columnName, - int x) throws SQLServerException { + public void updateInt(String columnName, int x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateInt", new Object[] {columnName, x}); @@ -4255,9 +4102,7 @@ public void updateInt(String columnName, } @Override - public void updateInt(String columnName, - int x, - boolean forceEncrypt) throws SQLServerException { + public void updateInt(String columnName, int x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateInt", new Object[] {columnName, x, forceEncrypt}); @@ -4268,8 +4113,7 @@ public void updateInt(String columnName, } @Override - public void updateLong(String columnName, - long x) throws SQLServerException { + public void updateLong(String columnName, long x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateLong", new Object[] {columnName, x}); @@ -4280,9 +4124,7 @@ public void updateLong(String columnName, } @Override - public void updateLong(String columnName, - long x, - boolean forceEncrypt) throws SQLServerException { + public void updateLong(String columnName, long x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateLong", new Object[] {columnName, x, forceEncrypt}); @@ -4293,8 +4135,7 @@ public void updateLong(String columnName, } @Override - public void updateFloat(String columnName, - float x) throws SQLServerException { + public void updateFloat(String columnName, float x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateFloat", new Object[] {columnName, x}); @@ -4305,9 +4146,7 @@ public void updateFloat(String columnName, } @Override - public void updateFloat(String columnName, - float x, - boolean forceEncrypt) throws SQLServerException { + public void updateFloat(String columnName, float x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateFloat", new Object[] {columnName, x, forceEncrypt}); @@ -4318,8 +4157,7 @@ public void updateFloat(String columnName, } @Override - public void updateDouble(String columnName, - double x) throws SQLServerException { + public void updateDouble(String columnName, double x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateDouble", new Object[] {columnName, x}); @@ -4330,9 +4168,7 @@ public void updateDouble(String columnName, } @Override - public void updateDouble(String columnName, - double x, - boolean forceEncrypt) throws SQLServerException { + public void updateDouble(String columnName, double x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateDouble", new Object[] {columnName, x, forceEncrypt}); @@ -4343,8 +4179,7 @@ public void updateDouble(String columnName, } @Override - public void updateBigDecimal(String columnName, - BigDecimal x) throws SQLServerException { + public void updateBigDecimal(String columnName, BigDecimal x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateBigDecimal", new Object[] {columnName, x}); @@ -4355,11 +4190,10 @@ public void updateBigDecimal(String columnName, } @Override - public void updateBigDecimal(String columnName, - BigDecimal x, - boolean forceEncrypt) throws SQLServerException { + public void updateBigDecimal(String columnName, BigDecimal x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateBigDecimal", new Object[] {columnName, x, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "updateBigDecimal", + new Object[] {columnName, x, forceEncrypt}); checkClosed(); updateValue(findColumn(columnName), JDBCType.DECIMAL, x, JavaType.BIGDECIMAL, forceEncrypt); @@ -4368,12 +4202,11 @@ public void updateBigDecimal(String columnName, } @Override - public void updateBigDecimal(String columnName, - BigDecimal x, - Integer precision, + public void updateBigDecimal(String columnName, BigDecimal x, Integer precision, Integer scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateBigDecimal", new Object[] {columnName, x, precision, scale}); + loggerExternal.entering(getClassNameLogging(), "updateBigDecimal", + new Object[] {columnName, x, precision, scale}); checkClosed(); updateValue(findColumn(columnName), JDBCType.DECIMAL, x, JavaType.BIGDECIMAL, precision, scale, false); @@ -4382,13 +4215,11 @@ public void updateBigDecimal(String columnName, } @Override - public void updateBigDecimal(String columnName, - BigDecimal x, - Integer precision, - Integer scale, + public void updateBigDecimal(String columnName, BigDecimal x, Integer precision, Integer scale, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateBigDecimal", new Object[] {columnName, x, precision, scale, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "updateBigDecimal", + new Object[] {columnName, x, precision, scale, forceEncrypt}); checkClosed(); updateValue(findColumn(columnName), JDBCType.DECIMAL, x, JavaType.BIGDECIMAL, precision, scale, forceEncrypt); @@ -4397,8 +4228,7 @@ public void updateBigDecimal(String columnName, } @Override - public void updateString(String columnName, - String x) throws SQLServerException { + public void updateString(String columnName, String x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateString", new Object[] {columnName, x}); @@ -4409,9 +4239,7 @@ public void updateString(String columnName, } @Override - public void updateString(String columnName, - String x, - boolean forceEncrypt) throws SQLServerException { + public void updateString(String columnName, String x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateString", new Object[] {columnName, x, forceEncrypt}); @@ -4422,8 +4250,7 @@ public void updateString(String columnName, } @Override - public void updateBytes(String columnName, - byte x[]) throws SQLServerException { + public void updateBytes(String columnName, byte x[]) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateBytes", new Object[] {columnName, x}); @@ -4434,9 +4261,7 @@ public void updateBytes(String columnName, } @Override - public void updateBytes(String columnName, - byte x[], - boolean forceEncrypt) throws SQLServerException { + public void updateBytes(String columnName, byte x[], boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateBytes", new Object[] {columnName, x, forceEncrypt}); @@ -4447,8 +4272,7 @@ public void updateBytes(String columnName, } @Override - public void updateDate(String columnName, - java.sql.Date x) throws SQLServerException { + public void updateDate(String columnName, java.sql.Date x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateDate", new Object[] {columnName, x}); @@ -4459,9 +4283,7 @@ public void updateDate(String columnName, } @Override - public void updateDate(String columnName, - java.sql.Date x, - boolean forceEncrypt) throws SQLServerException { + public void updateDate(String columnName, java.sql.Date x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateDate", new Object[] {columnName, x, forceEncrypt}); @@ -4472,8 +4294,7 @@ public void updateDate(String columnName, } @Override - public void updateTime(String columnName, - java.sql.Time x) throws SQLServerException { + public void updateTime(String columnName, java.sql.Time x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateTime", new Object[] {columnName, x}); @@ -4484,9 +4305,7 @@ public void updateTime(String columnName, } @Override - public void updateTime(String columnName, - java.sql.Time x, - int scale) throws SQLServerException { + public void updateTime(String columnName, java.sql.Time x, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateTime", new Object[] {columnName, x, scale}); @@ -4497,12 +4316,11 @@ public void updateTime(String columnName, } @Override - public void updateTime(String columnName, - java.sql.Time x, - int scale, + public void updateTime(String columnName, java.sql.Time x, int scale, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateTime", new Object[] {columnName, x, scale, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "updateTime", + new Object[] {columnName, x, scale, forceEncrypt}); checkClosed(); updateValue(findColumn(columnName), JDBCType.TIME, x, JavaType.TIME, null, scale, forceEncrypt); @@ -4511,8 +4329,7 @@ public void updateTime(String columnName, } @Override - public void updateTimestamp(String columnName, - java.sql.Timestamp x) throws SQLServerException { + public void updateTimestamp(String columnName, java.sql.Timestamp x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateTimestamp", new Object[] {columnName, x}); @@ -4523,9 +4340,7 @@ public void updateTimestamp(String columnName, } @Override - public void updateTimestamp(String columnName, - java.sql.Timestamp x, - int scale) throws SQLServerException { + public void updateTimestamp(String columnName, java.sql.Timestamp x, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateTimestamp", new Object[] {columnName, x, scale}); @@ -4536,12 +4351,11 @@ public void updateTimestamp(String columnName, } @Override - public void updateTimestamp(String columnName, - java.sql.Timestamp x, - int scale, + public void updateTimestamp(String columnName, java.sql.Timestamp x, int scale, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateTimestamp", new Object[] {columnName, x, scale, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "updateTimestamp", + new Object[] {columnName, x, scale, forceEncrypt}); checkClosed(); updateValue(findColumn(columnName), JDBCType.TIMESTAMP, x, JavaType.TIMESTAMP, null, scale, forceEncrypt); @@ -4550,8 +4364,7 @@ public void updateTimestamp(String columnName, } @Override - public void updateDateTime(String columnName, - java.sql.Timestamp x) throws SQLServerException { + public void updateDateTime(String columnName, java.sql.Timestamp x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateDateTime", new Object[] {columnName, x}); @@ -4562,9 +4375,7 @@ public void updateDateTime(String columnName, } @Override - public void updateDateTime(String columnName, - java.sql.Timestamp x, - int scale) throws SQLServerException { + public void updateDateTime(String columnName, java.sql.Timestamp x, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateDateTime", new Object[] {columnName, x, scale}); @@ -4575,12 +4386,11 @@ public void updateDateTime(String columnName, } @Override - public void updateDateTime(String columnName, - java.sql.Timestamp x, - int scale, + public void updateDateTime(String columnName, java.sql.Timestamp x, int scale, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateDateTime", new Object[] {columnName, x, scale, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "updateDateTime", + new Object[] {columnName, x, scale, forceEncrypt}); checkClosed(); updateValue(findColumn(columnName), JDBCType.DATETIME, x, JavaType.TIMESTAMP, null, scale, forceEncrypt); @@ -4589,8 +4399,7 @@ public void updateDateTime(String columnName, } @Override - public void updateSmallDateTime(String columnName, - java.sql.Timestamp x) throws SQLServerException { + public void updateSmallDateTime(String columnName, java.sql.Timestamp x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateSmallDateTime", new Object[] {columnName, x}); @@ -4601,9 +4410,7 @@ public void updateSmallDateTime(String columnName, } @Override - public void updateSmallDateTime(String columnName, - java.sql.Timestamp x, - int scale) throws SQLServerException { + public void updateSmallDateTime(String columnName, java.sql.Timestamp x, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateSmallDateTime", new Object[] {columnName, x, scale}); @@ -4614,12 +4421,11 @@ public void updateSmallDateTime(String columnName, } @Override - public void updateSmallDateTime(String columnName, - java.sql.Timestamp x, - int scale, + public void updateSmallDateTime(String columnName, java.sql.Timestamp x, int scale, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateSmallDateTime", new Object[] {columnName, x, scale, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "updateSmallDateTime", + new Object[] {columnName, x, scale, forceEncrypt}); checkClosed(); updateValue(findColumn(columnName), JDBCType.SMALLDATETIME, x, JavaType.TIMESTAMP, null, scale, forceEncrypt); @@ -4628,8 +4434,7 @@ public void updateSmallDateTime(String columnName, } @Override - public void updateDateTimeOffset(String columnName, - microsoft.sql.DateTimeOffset x) throws SQLServerException { + public void updateDateTimeOffset(String columnName, microsoft.sql.DateTimeOffset x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateDateTimeOffset", new Object[] {columnName, x}); @@ -4640,8 +4445,7 @@ public void updateDateTimeOffset(String columnName, } @Override - public void updateDateTimeOffset(String columnName, - microsoft.sql.DateTimeOffset x, + public void updateDateTimeOffset(String columnName, microsoft.sql.DateTimeOffset x, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateDateTimeOffset", new Object[] {columnName, x, scale}); @@ -4653,22 +4457,21 @@ public void updateDateTimeOffset(String columnName, } @Override - public void updateDateTimeOffset(String columnName, - microsoft.sql.DateTimeOffset x, - int scale, + public void updateDateTimeOffset(String columnName, microsoft.sql.DateTimeOffset x, int scale, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateDateTimeOffset", new Object[] {columnName, x, scale, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "updateDateTimeOffset", + new Object[] {columnName, x, scale, forceEncrypt}); checkClosed(); - updateValue(findColumn(columnName), JDBCType.DATETIMEOFFSET, x, JavaType.DATETIMEOFFSET, null, scale, forceEncrypt); + updateValue(findColumn(columnName), JDBCType.DATETIMEOFFSET, x, JavaType.DATETIMEOFFSET, null, scale, + forceEncrypt); loggerExternal.exiting(getClassNameLogging(), "updateDateTimeOffset"); } @Override - public void updateUniqueIdentifier(String columnName, - String x) throws SQLServerException { + public void updateUniqueIdentifier(String columnName, String x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateUniqueIdentifier", new Object[] {columnName, x}); @@ -4679,11 +4482,10 @@ public void updateUniqueIdentifier(String columnName, } @Override - public void updateUniqueIdentifier(String columnName, - String x, - boolean forceEncrypt) throws SQLServerException { + public void updateUniqueIdentifier(String columnName, String x, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateUniqueIdentifier", new Object[] {columnName, x, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "updateUniqueIdentifier", + new Object[] {columnName, x, forceEncrypt}); checkClosed(); updateValue(findColumn(columnName), JDBCType.GUID, x, JavaType.STRING, null, forceEncrypt); @@ -4692,9 +4494,7 @@ public void updateUniqueIdentifier(String columnName, } @Override - public void updateObject(String columnName, - Object x, - int scale) throws SQLServerException { + public void updateObject(String columnName, Object x, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateObject", new Object[] {columnName, x, scale}); @@ -4705,12 +4505,10 @@ public void updateObject(String columnName, } @Override - public void updateObject(String columnName, - Object x, - int precision, - int scale) throws SQLServerException { + public void updateObject(String columnName, Object x, int precision, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateObject", new Object[] {columnName, x, precision, scale}); + loggerExternal.entering(getClassNameLogging(), "updateObject", + new Object[] {columnName, x, precision, scale}); checkClosed(); updateObject(findColumn(columnName), x, scale, null, precision, false); @@ -4719,13 +4517,11 @@ public void updateObject(String columnName, } @Override - public void updateObject(String columnName, - Object x, - int precision, - int scale, + public void updateObject(String columnName, Object x, int precision, int scale, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateObject", new Object[] {columnName, x, precision, scale, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "updateObject", + new Object[] {columnName, x, precision, scale, forceEncrypt}); checkClosed(); updateObject(findColumn(columnName), x, scale, null, precision, forceEncrypt); @@ -4734,8 +4530,7 @@ public void updateObject(String columnName, } @Override - public void updateObject(String columnName, - Object x) throws SQLServerException { + public void updateObject(String columnName, Object x) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateObject", new Object[] {columnName, x}); @@ -4746,20 +4541,17 @@ public void updateObject(String columnName, } @Override - public void updateRowId(int columnIndex, - RowId x) throws SQLException { + public void updateRowId(int columnIndex, RowId x) throws SQLException { SQLServerException.throwNotSupportedException(stmt.connection, stmt); } @Override - public void updateRowId(String columnLabel, - RowId x) throws SQLException { + public void updateRowId(String columnLabel, RowId x) throws SQLException { SQLServerException.throwNotSupportedException(stmt.connection, stmt); } @Override - public void updateSQLXML(int columnIndex, - SQLXML xmlObject) throws SQLException { + public void updateSQLXML(int columnIndex, SQLXML xmlObject) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateSQLXML", new Object[] {columnIndex, xmlObject}); updateSQLXMLInternal(columnIndex, xmlObject); @@ -4767,8 +4559,7 @@ public void updateSQLXML(int columnIndex, } @Override - public void updateSQLXML(String columnLabel, - SQLXML x) throws SQLException { + public void updateSQLXML(String columnLabel, SQLXML x) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateSQLXML", new Object[] {columnLabel, x}); updateSQLXMLInternal(findColumn(columnLabel), x); @@ -4790,7 +4581,7 @@ public int getHoldability() throws SQLException { // For Yukon and later server-cursored result sets, holdability // was determined at statement execution time and does not change. - stmt.getExecProps().getHoldability(); + stmt.getExecProps().getHoldability(); loggerExternal.exiting(getClassNameLogging(), "getHoldability", holdability); @@ -4830,7 +4621,8 @@ final boolean doExecute() throws SQLServerException { verifyResultSetIsUpdatable(); if (!isOnInsertRow) { - SQLServerException.makeFromDriverError(stmt.connection, stmt, SQLServerException.getErrString("R_mustBeOnInsertRow"), null, true); + SQLServerException.makeFromDriverError(stmt.connection, stmt, + SQLServerException.getErrString("R_mustBeOnInsertRow"), null, true); } // Determine the table/view into which the row is to be inserted. @@ -4860,7 +4652,8 @@ final boolean doExecute() throws SQLServerException { } if (null == tableColumn) { - SQLServerException.makeFromDriverError(stmt.connection, stmt, SQLServerException.getErrString("R_noColumnParameterValue"), null, true); + SQLServerException.makeFromDriverError(stmt.connection, stmt, + SQLServerException.getErrString("R_noColumnParameterValue"), null, true); } assert tableColumn.isUpdatable(); @@ -4873,8 +4666,7 @@ final boolean doExecute() throws SQLServerException { loggerExternal.exiting(getClassNameLogging(), "insertRow"); } - private void doInsertRowRPC(TDSCommand command, - String tableName) throws SQLServerException { + private void doInsertRowRPC(TDSCommand command, String tableName) throws SQLServerException { assert 0 != serverCursorId; assert null != tableName; assert tableName.length() > 0; @@ -4882,8 +4674,8 @@ private void doInsertRowRPC(TDSCommand command, TDSWriter tdsWriter = command.startRequest(TDS.PKT_RPC); tdsWriter.writeShort((short) 0xFFFF); // procedure name length -> use ProcIDs tdsWriter.writeShort(TDS.PROCID_SP_CURSOR); - tdsWriter.writeByte((byte) 0); // RPC procedure option 1 - tdsWriter.writeByte((byte) 0); // RPC procedure option 2 + tdsWriter.writeByte((byte) 0); // RPC procedure option 1 + tdsWriter.writeByte((byte) 0); // RPC procedure option 2 tdsWriter.writeRPCInt(null, serverCursorId, false); tdsWriter.writeRPCInt(null, (int) TDS.SP_CURSOR_OP_INSERT, false); tdsWriter.writeRPCInt(null, fetchBufferGetRow(), false); @@ -4893,8 +4685,7 @@ private void doInsertRowRPC(TDSCommand command, for (Column column : columns) column.sendByRPC(tdsWriter, stmt.connection); - } - else { + } else { tdsWriter.writeRPCStringUnicode(""); tdsWriter.writeRPCStringUnicode("INSERT INTO " + tableName + " DEFAULT VALUES"); } @@ -4938,13 +4729,13 @@ final boolean doExecute() throws SQLServerException { verifyCurrentRowIsNotDeleted("R_cantUpdateDeletedRow"); if (!hasUpdatedColumns()) { - SQLServerException.makeFromDriverError(stmt.connection, stmt, SQLServerException.getErrString("R_noColumnParameterValue"), null, true); + SQLServerException.makeFromDriverError(stmt.connection, stmt, + SQLServerException.getErrString("R_noColumnParameterValue"), null, true); } try { stmt.executeCommand(new UpdateRowRPC()); - } - finally { + } finally { cancelUpdates(); } @@ -4958,8 +4749,8 @@ private void doUpdateRowRPC(TDSCommand command) throws SQLServerException { TDSWriter tdsWriter = command.startRequest(TDS.PKT_RPC); tdsWriter.writeShort((short) 0xFFFF); // procedure name length -> use ProcIDs tdsWriter.writeShort(TDS.PROCID_SP_CURSOR); - tdsWriter.writeByte((byte) 0); // RPC procedure option 1 - tdsWriter.writeByte((byte) 0); // RPC procedure option 2 + tdsWriter.writeByte((byte) 0); // RPC procedure option 1 + tdsWriter.writeByte((byte) 0); // RPC procedure option 2 tdsWriter.writeRPCInt(null, serverCursorId, false); tdsWriter.writeRPCInt(null, TDS.SP_CURSOR_OP_UPDATE | TDS.SP_CURSOR_OP_SETPOSITION, false); tdsWriter.writeRPCInt(null, fetchBufferGetRow(), false); @@ -5017,8 +4808,7 @@ final boolean doExecute() throws SQLServerException { try { stmt.executeCommand(new DeleteRowRPC()); - } - finally { + } finally { cancelUpdates(); } @@ -5032,8 +4822,8 @@ private void doDeleteRowRPC(TDSCommand command) throws SQLServerException { TDSWriter tdsWriter = command.startRequest(TDS.PKT_RPC); tdsWriter.writeShort((short) 0xFFFF); // procedure name length -> use ProcIDs tdsWriter.writeShort(TDS.PROCID_SP_CURSOR); - tdsWriter.writeByte((byte) 0); // RPC procedure option 1 - tdsWriter.writeByte((byte) 0); // RPC procedure option 2 + tdsWriter.writeByte((byte) 0); // RPC procedure option 1 + tdsWriter.writeByte((byte) 0); // RPC procedure option 2 tdsWriter.writeRPCInt(null, serverCursorId, false); tdsWriter.writeRPCInt(null, TDS.SP_CURSOR_OP_DELETE | TDS.SP_CURSOR_OP_SETPOSITION, false); tdsWriter.writeRPCInt(null, fetchBufferGetRow(), false); @@ -5103,7 +4893,8 @@ private void doRefreshRow() throws SQLServerException { // the refresh -- rows may have been added, modified, or deleted -- so the current row // may not end up where it was before the refresh. int fetchBufferRestoredRow = 0; - while (fetchBufferRestoredRow < fetchBufferSavedRow && (isForwardOnly() ? fetchBufferNext() : scrollWindow.next(this))) { + while (fetchBufferRestoredRow < fetchBufferSavedRow + && (isForwardOnly() ? fetchBufferNext() : scrollWindow.next(this))) { ++fetchBufferRestoredRow; } @@ -5186,8 +4977,7 @@ public java.sql.Statement getStatement() throws SQLServerException { /* JDBC 3.0 */ @Override - public void updateClob(int columnIndex, - Clob clobValue) throws SQLException { + public void updateClob(int columnIndex, Clob clobValue) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateClob", new Object[] {columnIndex, clobValue}); @@ -5198,8 +4988,7 @@ public void updateClob(int columnIndex, } @Override - public void updateClob(int columnIndex, - Reader reader) throws SQLException { + public void updateClob(int columnIndex, Reader reader) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateClob", new Object[] {columnIndex, reader}); @@ -5210,9 +4999,7 @@ public void updateClob(int columnIndex, } @Override - public void updateClob(int columnIndex, - Reader reader, - long length) throws SQLException { + public void updateClob(int columnIndex, Reader reader, long length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateClob", new Object[] {columnIndex, reader, length}); @@ -5223,8 +5010,7 @@ public void updateClob(int columnIndex, } @Override - public void updateClob(String columnName, - Clob clobValue) throws SQLException { + public void updateClob(String columnName, Clob clobValue) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateClob", new Object[] {columnName, clobValue}); @@ -5235,21 +5021,19 @@ public void updateClob(String columnName, } @Override - public void updateClob(String columnLabel, - Reader reader) throws SQLException { + public void updateClob(String columnLabel, Reader reader) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateClob", new Object[] {columnLabel, reader}); checkClosed(); - updateStream(findColumn(columnLabel), StreamType.CHARACTER, reader, JavaType.READER, DataTypes.UNKNOWN_STREAM_LENGTH); + updateStream(findColumn(columnLabel), StreamType.CHARACTER, reader, JavaType.READER, + DataTypes.UNKNOWN_STREAM_LENGTH); loggerExternal.exiting(getClassNameLogging(), "updateClob"); } @Override - public void updateClob(String columnLabel, - Reader reader, - long length) throws SQLException { + public void updateClob(String columnLabel, Reader reader, long length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateClob", new Object[] {columnLabel, reader, length}); @@ -5260,8 +5044,7 @@ public void updateClob(String columnLabel, } @Override - public void updateNClob(int columnIndex, - NClob nClob) throws SQLException { + public void updateNClob(int columnIndex, NClob nClob) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateClob", new Object[] {columnIndex, nClob}); @@ -5272,8 +5055,7 @@ public void updateNClob(int columnIndex, } @Override - public void updateNClob(int columnIndex, - Reader reader) throws SQLException { + public void updateNClob(int columnIndex, Reader reader) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateNClob", new Object[] {columnIndex, reader}); @@ -5284,9 +5066,7 @@ public void updateNClob(int columnIndex, } @Override - public void updateNClob(int columnIndex, - Reader reader, - long length) throws SQLException { + public void updateNClob(int columnIndex, Reader reader, long length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateNClob", new Object[] {columnIndex, reader, length}); @@ -5297,8 +5077,7 @@ public void updateNClob(int columnIndex, } @Override - public void updateNClob(String columnLabel, - NClob nClob) throws SQLException { + public void updateNClob(String columnLabel, NClob nClob) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateNClob", new Object[] {columnLabel, nClob}); @@ -5309,21 +5088,19 @@ public void updateNClob(String columnLabel, } @Override - public void updateNClob(String columnLabel, - Reader reader) throws SQLException { + public void updateNClob(String columnLabel, Reader reader) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateNClob", new Object[] {columnLabel, reader}); checkClosed(); - updateStream(findColumn(columnLabel), StreamType.NCHARACTER, reader, JavaType.READER, DataTypes.UNKNOWN_STREAM_LENGTH); + updateStream(findColumn(columnLabel), StreamType.NCHARACTER, reader, JavaType.READER, + DataTypes.UNKNOWN_STREAM_LENGTH); loggerExternal.exiting(getClassNameLogging(), "updateNClob"); } @Override - public void updateNClob(String columnLabel, - Reader reader, - long length) throws SQLException { + public void updateNClob(String columnLabel, Reader reader, long length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateNClob", new Object[] {columnLabel, reader, length}); @@ -5334,8 +5111,7 @@ public void updateNClob(String columnLabel, } @Override - public void updateBlob(int columnIndex, - Blob blobValue) throws SQLException { + public void updateBlob(int columnIndex, Blob blobValue) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateBlob", new Object[] {columnIndex, blobValue}); @@ -5346,23 +5122,22 @@ public void updateBlob(int columnIndex, } @Override - public void updateBlob(int columnIndex, - InputStream inputStream) throws SQLException { + public void updateBlob(int columnIndex, InputStream inputStream) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateBlob", new Object[] {columnIndex, inputStream}); checkClosed(); - updateStream(columnIndex, StreamType.BINARY, inputStream, JavaType.INPUTSTREAM, DataTypes.UNKNOWN_STREAM_LENGTH); + updateStream(columnIndex, StreamType.BINARY, inputStream, JavaType.INPUTSTREAM, + DataTypes.UNKNOWN_STREAM_LENGTH); loggerExternal.exiting(getClassNameLogging(), "updateBlob"); } @Override - public void updateBlob(int columnIndex, - InputStream inputStream, - long length) throws SQLException { + public void updateBlob(int columnIndex, InputStream inputStream, long length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateBlob", new Object[] {columnIndex, inputStream, length}); + loggerExternal.entering(getClassNameLogging(), "updateBlob", + new Object[] {columnIndex, inputStream, length}); checkClosed(); updateStream(columnIndex, StreamType.BINARY, inputStream, JavaType.INPUTSTREAM, length); @@ -5371,8 +5146,7 @@ public void updateBlob(int columnIndex, } @Override - public void updateBlob(String columnName, - Blob blobValue) throws SQLException { + public void updateBlob(String columnName, Blob blobValue) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateBlob", new Object[] {columnName, blobValue}); @@ -5383,23 +5157,22 @@ public void updateBlob(String columnName, } @Override - public void updateBlob(String columnLabel, - InputStream inputStream) throws SQLException { + public void updateBlob(String columnLabel, InputStream inputStream) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateBlob", new Object[] {columnLabel, inputStream}); checkClosed(); - updateStream(findColumn(columnLabel), StreamType.BINARY, inputStream, JavaType.INPUTSTREAM, DataTypes.UNKNOWN_STREAM_LENGTH); + updateStream(findColumn(columnLabel), StreamType.BINARY, inputStream, JavaType.INPUTSTREAM, + DataTypes.UNKNOWN_STREAM_LENGTH); loggerExternal.exiting(getClassNameLogging(), "updateBlob"); } @Override - public void updateBlob(String columnLabel, - InputStream inputStream, - long length) throws SQLException { + public void updateBlob(String columnLabel, InputStream inputStream, long length) throws SQLException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateBlob", new Object[] {columnLabel, inputStream, length}); + loggerExternal.entering(getClassNameLogging(), "updateBlob", + new Object[] {columnLabel, inputStream, length}); checkClosed(); updateStream(findColumn(columnLabel), StreamType.BINARY, inputStream, JavaType.INPUTSTREAM, length); @@ -5408,26 +5181,22 @@ public void updateBlob(String columnLabel, } @Override - public void updateArray(int columnIndex, - Array x) throws SQLException { + public void updateArray(int columnIndex, Array x) throws SQLException { SQLServerException.throwNotSupportedException(stmt.connection, stmt); } @Override - public void updateArray(java.lang.String columnName, - Array x) throws SQLException { + public void updateArray(java.lang.String columnName, Array x) throws SQLException { SQLServerException.throwNotSupportedException(stmt.connection, stmt); } @Override - public void updateRef(int columnIndex, - Ref x) throws SQLException { + public void updateRef(int columnIndex, Ref x) throws SQLException { SQLServerException.throwNotSupportedException(stmt.connection, stmt); } @Override - public void updateRef(java.lang.String columnName, - Ref x) throws SQLException { + public void updateRef(java.lang.String columnName, Ref x) throws SQLException { SQLServerException.throwNotSupportedException(stmt.connection, stmt); } @@ -5449,16 +5218,19 @@ public java.net.URL getURL(String sColumn) throws SQLException { /** * Fetch buffer that provides a source of rows to this ResultSet. * - * The FetchBuffer class is different conceptually from the ScrollWindow class. The latter provides indexing and arbitrary scrolling over rows - * provided by the fetch buffer. The fetch buffer itself just provides the rows and supports rewinding back to the start of the buffer. When - * server cursors are involved, the fetch buffer is typically the same size as the scroll window. However, with client side scrollable cursors, - * the fetch buffer would contain all of the rows in the result set, but the scroll window would only contain some of them (determined by - * ResultSet.setFetchSize). + * The FetchBuffer class is different conceptually from the ScrollWindow class. The latter provides indexing and + * arbitrary scrolling over rows provided by the fetch buffer. The fetch buffer itself just provides the rows and + * supports rewinding back to the start of the buffer. When server cursors are involved, the fetch buffer is + * typically the same size as the scroll window. However, with client side scrollable cursors, the fetch buffer + * would contain all of the rows in the result set, but the scroll window would only contain some of them + * (determined by ResultSet.setFetchSize). * - * The fetch buffer contains 0 or more ROW tokens followed by a DONE (cmd=SELECT, 0xC1) token indicating the number of rows in the fetch buffer. + * The fetch buffer contains 0 or more ROW tokens followed by a DONE (cmd=SELECT, 0xC1) token indicating the number + * of rows in the fetch buffer. * - * For client-cursored result sets, the fetch buffer contains all of the rows in the result set, and the DONE token indicates the total number of - * rows in the result set, though we don't use that information, as we always count rows as we encounter them. + * For client-cursored result sets, the fetch buffer contains all of the rows in the result set, and the DONE token + * indicates the total number of rows in the result set, though we don't use that information, as we always count + * rows as we encounter them. */ private final class FetchBuffer { private final class FetchBufferTokenHandler extends TDSTokenHandler { @@ -5470,7 +5242,8 @@ private final class FetchBufferTokenHandler extends TDSTokenHandler { // the server still returns a COLMETADATA_TOKEN containing the magic NoMetaData // value that we need to read through. boolean onColMetaData(TDSReader tdsReader) throws SQLServerException { - (new StreamColumns(Util.shouldHonorAEForRead(stmt.stmtColumnEncriptionSetting, stmt.connection))).setFromTDS(tdsReader); + (new StreamColumns(Util.shouldHonorAEForRead(stmt.stmtColumnEncriptionSetting, stmt.connection))) + .setFromTDS(tdsReader); return true; } @@ -5581,8 +5354,8 @@ final void reset() { } /** - * Initializes the fetch buffer with new contents and optionally sets a TDSReaderMark at the start of the fetch buffer to allow the fetch - * buffer to be scrolled back to the beginning. + * Initializes the fetch buffer with new contents and optionally sets a TDSReaderMark at the start of the fetch + * buffer to allow the fetch buffer to be scrolled back to the beginning. */ final void init() { startMark = (0 == serverCursorId && !isForwardOnly()) ? tdsReader.mark() : null; @@ -5600,8 +5373,10 @@ final RowType nextRow() throws SQLServerException { while (null != tdsReader && !done && fetchBufferCurrentRowType.equals(RowType.UNKNOWN)) TDSParser.parse(tdsReader, fetchBufferTokenHandler); - if (fetchBufferCurrentRowType.equals(RowType.UNKNOWN) && null != fetchBufferTokenHandler.getDatabaseError()) { - SQLServerException.makeFromDatabaseError(stmt.connection, null, fetchBufferTokenHandler.getDatabaseError().getMessage(), + if (fetchBufferCurrentRowType.equals(RowType.UNKNOWN) + && null != fetchBufferTokenHandler.getDatabaseError()) { + SQLServerException.makeFromDatabaseError(stmt.connection, null, + fetchBufferTokenHandler.getDatabaseError().getMessage(), fetchBufferTokenHandler.getDatabaseError(), false); } @@ -5615,10 +5390,7 @@ private final class CursorFetchCommand extends TDSCommand { private int startRow; private int numRows; - CursorFetchCommand(int serverCursorId, - int fetchType, - int startRow, - int numRows) { + CursorFetchCommand(int serverCursorId, int fetchType, int startRow, int numRows) { super("doServerFetch", stmt.queryTimeout, stmt.cancelQueryTimeoutSeconds); this.serverCursorId = serverCursorId; this.fetchType = fetchType; @@ -5631,7 +5403,7 @@ final boolean doExecute() throws SQLServerException { tdsWriter.writeShort((short) 0xFFFF); // procedure name length -> use ProcIDs tdsWriter.writeShort(TDS.PROCID_SP_CURSORFETCH); tdsWriter.writeByte(TDS.RPC_OPTION_NO_METADATA); - tdsWriter.writeByte((byte) 0); // RPC procedure option 2 + tdsWriter.writeByte((byte) 0); // RPC procedure option 2 tdsWriter.writeRPCInt(null, serverCursorId, false); tdsWriter.writeRPCInt(null, fetchType, false); tdsWriter.writeRPCInt(null, startRow, false); @@ -5644,7 +5416,8 @@ final boolean doExecute() throws SQLServerException { // can do a forward only updatable pass through a ResultSet with large // data values. tdsReader = startResponse(isForwardOnly() && CONCUR_READ_ONLY != stmt.resultSetConcurrency - && stmt.getExecProps().wasResponseBufferingSet() && stmt.getExecProps().isResponseBufferingAdaptive()); + && stmt.getExecProps().wasResponseBufferingSet() + && stmt.getExecProps().isResponseBufferingAdaptive()); return false; } @@ -5659,17 +5432,15 @@ final void processResponse(TDSReader responseTDSReader) throws SQLServerExceptio * Position a server side cursor. * * @param fetchType - * The type of fetch + * The type of fetch * @param startRow - * The starting row + * The starting row * @param numRows - * The number of rows to fetch + * The number of rows to fetch * @exception SQLServerException - * The cursor was invalid. + * The cursor was invalid. */ - final void doServerFetch(int fetchType, - int startRow, - int numRows) throws SQLServerException { + final void doServerFetch(int fetchType, int startRow, int numRows) throws SQLServerException { if (logger.isLoggable(java.util.logging.Level.FINER)) logger.finer(toString() + " fetchType:" + fetchType + " startRow:" + startRow + " numRows:" + numRows); @@ -5702,15 +5473,14 @@ final void doServerFetch(int fetchType, if (numRows < 0 || startRow < 0) { // Scroll past all the returned rows, caching in the scroll window as we go. try { - while (scrollWindow.next(this)) - ; - } - catch (SQLException e) { + while (scrollWindow.next(this)); + } catch (SQLException e) { // If there is a row error in the results, don't throw an exception from here. // Ignore it for now and defer the exception until the app encounters the // error through normal cursor movement. if (logger.isLoggable(java.util.logging.Level.FINER)) - logger.finer(toString() + " Ignored exception from row error during server cursor fixup: " + e.getMessage()); + logger.finer(toString() + " Ignored exception from row error during server cursor fixup: " + + e.getMessage()); } // Force the cursor to move to before the first row if necessary. @@ -5725,20 +5495,18 @@ final void doServerFetch(int fetchType, } /* - * Checks for any LOBs which need to be available after the RS is closed, and loads their contents from stream into memory. Closed LOBs will not - * be populated. + * Checks for any LOBs which need to be available after the RS is closed, and loads their contents from stream into + * memory. Closed LOBs will not be populated. */ private void fillLOBs() { if (null != activeLOB) { try { activeLOB.fillFromStream(); - } - catch (SQLException e) { + } catch (SQLException e) { if (logger.isLoggable(java.util.logging.Level.FINER)) { logger.finer(toString() + "Filling Lobs before closing: " + e.getMessage()); } - } - finally { + } finally { activeLOB = null; } } @@ -5747,12 +5515,14 @@ private void fillLOBs() { /** * Discards the contents of the current fetch buffer. * - * This method ensures that the contents of the current fetch buffer have been completely read from the TDS channel, processed, and discarded. + * This method ensures that the contents of the current fetch buffer have been completely read from the TDS channel, + * processed, and discarded. * - * Note that exceptions resulting from database errors, such as row errors or transaction rollbacks, and from I/O errors, such as a closed - * connection, are caught, logged, and ignored. The expectation is that callers of this method just want the fetch buffer cleared out and do not - * care about what errors may have occurred when it was last populated. If the connection is closed while discarding the fetch buffer, then the - * fetch buffer is considered to be discarded. + * Note that exceptions resulting from database errors, such as row errors or transaction rollbacks, and from I/O + * errors, such as a closed connection, are caught, logged, and ignored. The expectation is that callers of this + * method just want the fetch buffer cleared out and do not care about what errors may have occurred when it was + * last populated. If the connection is closed while discarding the fetch buffer, then the fetch buffer is + * considered to be discarded. */ private void discardFetchBuffer() { // fills blobs before discarding anything @@ -5768,10 +5538,8 @@ private void discardFetchBuffer() { // Once there are no TDSReader marks left referring to the fetch buffer // contents, process the remainder of the current row and all subsequent rows. try { - while (fetchBufferNext()) - ; - } - catch (SQLServerException e) { + while (fetchBufferNext()); + } catch (SQLServerException e) { if (logger.isLoggable(java.util.logging.Level.FINER)) logger.finer(this + " Encountered exception discarding fetch buffer: " + e.getMessage()); } @@ -5791,8 +5559,7 @@ final void closeServerCursor() { if (stmt.connection.isSessionUnAvailable()) { if (logger.isLoggable(java.util.logging.Level.FINER)) logger.finer(this + ": Not closing cursor:" + serverCursorId + "; connection is already closed."); - } - else { + } else { if (logger.isLoggable(java.util.logging.Level.FINER)) logger.finer(toString() + " Closing cursor:" + serverCursorId); @@ -5805,8 +5572,8 @@ final boolean doExecute() throws SQLServerException { TDSWriter tdsWriter = startRequest(TDS.PKT_RPC); tdsWriter.writeShort((short) 0xFFFF); // procedure name length -> use ProcIDs tdsWriter.writeShort(TDS.PROCID_SP_CURSORCLOSE); - tdsWriter.writeByte((byte) 0); // RPC procedure option 1 - tdsWriter.writeByte((byte) 0); // RPC procedure option 2 + tdsWriter.writeByte((byte) 0); // RPC procedure option 1 + tdsWriter.writeByte((byte) 0); // RPC procedure option 2 tdsWriter.writeRPCInt(null, serverCursorId, false); TDSParser.parse(startResponse(), getLogContext()); return true; @@ -5816,8 +5583,7 @@ final boolean doExecute() throws SQLServerException { // Try to close the server cursor. Any failure is caught, logged, and ignored. try { stmt.executeCommand(new CloseServerCursorCommand()); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { if (logger.isLoggable(java.util.logging.Level.FINER)) logger.finer(toString() + " Ignored error closing cursor:" + serverCursorId + " " + e.getMessage()); } @@ -5828,9 +5594,7 @@ final boolean doExecute() throws SQLServerException { } @Override - public void updateObject(int index, - Object obj, - SQLType targetSqlType) throws SQLServerException { + public void updateObject(int index, Object obj, SQLType targetSqlType) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) loggerExternal.entering(getClassNameLogging(), "updateObject", new Object[] {index, obj, targetSqlType}); @@ -5843,13 +5607,11 @@ public void updateObject(int index, } @Override - public void updateObject(int index, - Object obj, - SQLType targetSqlType, - int scale) throws SQLServerException { + public void updateObject(int index, Object obj, SQLType targetSqlType, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateObject", new Object[] {index, obj, targetSqlType, scale}); + loggerExternal.entering(getClassNameLogging(), "updateObject", + new Object[] {index, obj, targetSqlType, scale}); checkClosed(); // getVendorTypeNumber() returns the same constant integer values as in java.sql.Types @@ -5859,14 +5621,12 @@ public void updateObject(int index, } @Override - public void updateObject(int index, - Object obj, - SQLType targetSqlType, - int scale, + public void updateObject(int index, Object obj, SQLType targetSqlType, int scale, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateObject", new Object[] {index, obj, targetSqlType, scale, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "updateObject", + new Object[] {index, obj, targetSqlType, scale, forceEncrypt}); checkClosed(); // getVendorTypeNumber() returns the same constant integer values as in java.sql.Types @@ -5876,13 +5636,12 @@ public void updateObject(int index, } @Override - public void updateObject(String columnName, - Object obj, - SQLType targetSqlType, + public void updateObject(String columnName, Object obj, SQLType targetSqlType, int scale) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateObject", new Object[] {columnName, obj, targetSqlType, scale}); + loggerExternal.entering(getClassNameLogging(), "updateObject", + new Object[] {columnName, obj, targetSqlType, scale}); checkClosed(); @@ -5893,30 +5652,28 @@ public void updateObject(String columnName, } @Override - public void updateObject(String columnName, - Object obj, - SQLType targetSqlType, - int scale, + public void updateObject(String columnName, Object obj, SQLType targetSqlType, int scale, boolean forceEncrypt) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateObject", new Object[] {columnName, obj, targetSqlType, scale, forceEncrypt}); + loggerExternal.entering(getClassNameLogging(), "updateObject", + new Object[] {columnName, obj, targetSqlType, scale, forceEncrypt}); checkClosed(); // getVendorTypeNumber() returns the same constant integer values as in java.sql.Types - updateObject(findColumn(columnName), obj, scale, JDBCType.of(targetSqlType.getVendorTypeNumber()), null, forceEncrypt); + updateObject(findColumn(columnName), obj, scale, JDBCType.of(targetSqlType.getVendorTypeNumber()), null, + forceEncrypt); loggerExternal.exiting(getClassNameLogging(), "updateObject"); } @Override - public void updateObject(String columnName, - Object obj, - SQLType targetSqlType) throws SQLServerException { + public void updateObject(String columnName, Object obj, SQLType targetSqlType) throws SQLServerException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "updateObject", new Object[] {columnName, obj, targetSqlType}); + loggerExternal.entering(getClassNameLogging(), "updateObject", + new Object[] {columnName, obj, targetSqlType}); checkClosed(); diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSetMetaData.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSetMetaData.java index e3b7679fa..5f36d2d75 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSetMetaData.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSetMetaData.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -11,20 +8,22 @@ import java.sql.SQLException; import java.util.concurrent.atomic.AtomicInteger; + /** - * A ResultSetMetaData object can be used to obtain the meta data (types and type properties) of the columns in a ResultSet. + * Provides an implementation of the result set metadata to the SQL Server. A ResultSetMetaData object can be used to + * obtain the meta data (types and type properties) of the columns in a ResultSet. * - * The API javadoc for JDBC API methods that this class implements are not repeated here. Please see Sun's JDBC API interfaces javadoc for those - * details. + * The API javadoc for JDBC API methods that this class implements are not repeated here. Please see Sun's JDBC API + * interfaces javadoc for those details. */ - public final class SQLServerResultSetMetaData implements ISQLServerResultSetMetaData { private SQLServerConnection con; private final SQLServerResultSet rs; static final private java.util.logging.Logger logger = java.util.logging.Logger .getLogger("com.microsoft.sqlserver.jdbc.internals.SQLServerResultSetMetaData"); - static private final AtomicInteger baseID = new AtomicInteger(0); // Unique id generator for each instance (used for logging). + static private final AtomicInteger baseID = new AtomicInteger(0); // Unique id generator for each instance (used for + // logging). final private String traceID; // Returns unique id for each instance. @@ -37,15 +36,14 @@ final public String toString() { } /** - * Create a new meta data object for the result set. + * Constructs a SQLServerResultSetMetaData meta data object for the result set. * * @param con - * the connection + * the connection * @param rs - * the parent result set + * the parent result set */ - SQLServerResultSetMetaData(SQLServerConnection con, - SQLServerResultSet rs) { + SQLServerResultSetMetaData(SQLServerConnection con, SQLServerResultSet rs) { traceID = " SQLServerResultSetMetaData:" + nextInstanceID(); this.con = con; this.rs = rs; @@ -68,8 +66,7 @@ public T unwrap(Class iface) throws SQLException { T t; try { t = iface.cast(this); - } - catch (ClassCastException e) { + } catch (ClassCastException e) { throw new SQLServerException(e.getMessage(), e); } return t; @@ -114,11 +111,12 @@ public int getColumnType(int column) throws SQLServerException { if (null != cryptoMetadata) { typeInfo = cryptoMetadata.getBaseTypeInfo(); } - + JDBCType jdbcType = typeInfo.getSSType().getJDBCType(); SSType sqlType = typeInfo.getSSType(); - // in bulkcopy for instance, we need to return the real jdbc type which is sql variant and not the default Char one. - if ( SSType.SQL_VARIANT == sqlType){ + // in bulkcopy for instance, we need to return the real jdbc type which is sql variant and not the default Char + // one. + if (SSType.SQL_VARIANT == sqlType) { jdbcType = JDBCType.SQL_VARIANT; } if (SSType.UDT == sqlType) { @@ -269,8 +267,7 @@ public boolean isSearchable(int column) throws SQLServerException { if (null != cryptoMetadata) { ssType = cryptoMetadata.getBaseTypeInfo().getSSType(); - } - else { + } else { ssType = rs.getColumn(column).getTypeInfo().getSSType(); } @@ -313,8 +310,7 @@ public boolean isWritable(int column) throws SQLServerException { CryptoMetadata cryptoMetadata = rs.getColumn(column).getCryptoMetadata(); if (null != cryptoMetadata) { updatability = cryptoMetadata.getBaseTypeInfo().getUpdatability(); - } - else { + } else { updatability = rs.getColumn(column).getTypeInfo().getUpdatability(); } return TypeInfo.UPDATABLE_READ_WRITE == updatability || TypeInfo.UPDATABLE_UNKNOWN == updatability; diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSQLXML.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSQLXML.java index da860456a..b58a715c3 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSQLXML.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSQLXML.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -50,10 +47,11 @@ import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; + + /** - * SQLServerSQLXML represents an XML object and implements a java.sql.SQLXML. + * Represents an XML object and implements a java.sql.SQLXML. */ - final class SQLServerSQLXML implements java.sql.SQLXML { // Connection that created this SQLXML only set when created for setting data private final SQLServerConnection con; @@ -75,14 +73,19 @@ final class SQLServerSQLXML implements java.sql.SQLXML { private String strValue; // End of setter values - static private final AtomicInteger baseID = new AtomicInteger(0); // Unique id generator for each instance (used for logging). + static private final AtomicInteger baseID = new AtomicInteger(0); // Unique id generator for each instance (used for + // logging). final private String traceID; final public String toString() { return traceID; } - // Returns unique id for each instance. + /** + * Returns unique id for each instance. + * + * @return + */ private static int nextInstanceID() { return baseID.incrementAndGet(); } @@ -92,18 +95,19 @@ private static int nextInstanceID() { // possible optimization transform DOM straight to tds InputStream getValue() throws SQLServerException { checkClosed(); - // the user should have called one of the setter methods, the setter methods "use" the object and write some value. + // the user should have called one of the setter methods, the setter methods "use" the object and write some + // value. // Note just calling one of the setters is enough. if (!isUsed) - SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_noDataXML"), null, true); + SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_noDataXML"), null, + true); assert null == contents; ByteArrayInputStream o = null; if (null != outputStreamValue) { o = outputStreamValue.getInputStream(); assert null == docValue; assert null == strValue; - } - else if (null != docValue) { + } else if (null != docValue) { assert null == outputStreamValue; assert null == strValue; ByteArrayOutputStreamToInputStream strm = new ByteArrayOutputStreamToInputStream(); @@ -112,15 +116,13 @@ else if (null != docValue) { try { factory = TransformerFactory.newInstance(); factory.newTransformer().transform(new DOMSource(docValue), new StreamResult(strm)); - } - catch (javax.xml.transform.TransformerException e) { + } catch (javax.xml.transform.TransformerException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_noParserSupport")); Object[] msgArgs = {e.toString()}; SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true); } o = strm.getInputStream(); - } - else { + } else { assert null == outputStreamValue; assert null == docValue; assert null != strValue; @@ -143,9 +145,7 @@ else if (null != docValue) { typeInfo = null; } - SQLServerSQLXML(InputStream stream, - InputStreamGetterArgs getterArgs, - TypeInfo typeInfo) throws SQLServerException { + SQLServerSQLXML(InputStream stream, InputStreamGetterArgs getterArgs, TypeInfo typeInfo) throws SQLServerException { traceID = " SQLServerSQLXML:" + nextInstanceID(); contents = (PLPXMLInputStream) stream; this.con = null; @@ -158,7 +158,7 @@ else if (null != docValue) { InputStream getStream() { return contents; } - + @Override public void free() throws SQLException { if (!isFreed) { @@ -166,8 +166,7 @@ public void free() throws SQLException { if (null != contents) { try { contents.close(); - } - catch (IOException e) { + } catch (IOException e) { SQLServerException.makeFromDriverError(null, null, e.getMessage(), null, true); } } @@ -183,13 +182,14 @@ private void checkClosed() throws SQLServerException { private void checkReadXML() throws SQLException { if (null == contents) - SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_writeOnlyXML"), null, true); + SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_writeOnlyXML"), null, + true); if (isUsed) - SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_dataHasBeenReadXML"), null, true); + SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_dataHasBeenReadXML"), + null, true); try { contents.checkClosed(); - } - catch (IOException e) { + } catch (IOException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_isFreed")); SQLServerException.makeFromDriverError(con, null, form.format(new Object[] {"SQLXML"}), null, true); } @@ -197,17 +197,19 @@ private void checkReadXML() throws SQLException { void checkWriteXML() throws SQLException { if (null != contents) - SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_readOnlyXML"), null, true); + SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_readOnlyXML"), null, + true); if (isUsed) - SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_dataHasBeenSetXML"), null, true); + SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_dataHasBeenSetXML"), + null, true); } /** - * Return an input stream to read data from this SQLXML + * Returns an input stream to read data from this SQLXML. * * @throws SQLException - * when an error occurs + * when an error occurs * @return the input stream to that contains the SQLXML data */ @Override @@ -219,11 +221,11 @@ public InputStream getBinaryStream() throws SQLException { } /** - * Retrieves a stream that can be used to write to the SQLXML value that this SQLXML object represents The user has to write the BOM for binary - * streams. + * Sets a stream that can be used to write to the SQLXML value that this SQLXML object represents The user has to + * write the BOM for binary streams. * * @throws SQLException - * when an error occurs + * when an error occurs * @return OutputStream */ @Override @@ -250,15 +252,15 @@ public Reader getCharacterStream() throws SQLException { checkReadXML(); isUsed = true; StreamType type = StreamType.CHARACTER; - InputStreamGetterArgs newArgs = new InputStreamGetterArgs(type, getterArgs.isAdaptive, getterArgs.isStreaming, getterArgs.logContext); + InputStreamGetterArgs newArgs = new InputStreamGetterArgs(type, getterArgs.isAdaptive, getterArgs.isStreaming, + getterArgs.logContext); // Skip the BOM bytes from the plpinputstream we do not need it for the conversion assert null != contents; // Read two bytes to eat BOM try { contents.read(); contents.read(); - } - catch (IOException e) { + } catch (IOException e) { SQLServerException.makeFromDriverError(null, null, e.getMessage(), null, true); } @@ -276,8 +278,7 @@ public String getString() throws SQLException { try { contents.read(); contents.read(); - } - catch (IOException e) { + } catch (IOException e) { SQLServerException.makeFromDriverError(null, null, e.getMessage(), null, true); } @@ -291,7 +292,8 @@ public void setString(String value) throws SQLException { checkWriteXML(); isUsed = true; if (null == value) - SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_cantSetNull"), null, true); + SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_cantSetNull"), null, + true); strValue = value; } // Support the following DOMSource, SAXSource, StAX and Stream. Also, null means default which is stream source @@ -306,8 +308,7 @@ public T getSource(Class iface) throws SQLException { @SuppressWarnings("unchecked") T src = (T) getSourceInternal(StreamSource.class); return src; - } - else + } else return getSourceInternal(iface); } @@ -316,19 +317,16 @@ T getSourceInternal(Class iface) throws SQLException { T src = null; if (DOMSource.class == iface) { src = iface.cast(getDOMSource()); - } - else if (SAXSource.class == iface) { + } else if (SAXSource.class == iface) { src = iface.cast(getSAXSource()); - } - else if (StAXSource.class == iface) { + } else if (StAXSource.class == iface) { src = iface.cast(getStAXSource()); - } - else if (StreamSource.class == iface) { + } else if (StreamSource.class == iface) { src = iface.cast(new StreamSource(contents)); - } - else + } else // Do not support this type - SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_notSupported"), null, true); + SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_notSupported"), null, + true); return src; } @@ -342,8 +340,7 @@ public T setResult(Class resultClass) throws SQLException @SuppressWarnings("unchecked") T result = (T) setResultInternal(StreamResult.class); return result; - } - else + } else return setResultInternal(resultClass); } @@ -353,19 +350,16 @@ T setResultInternal(Class resultClass) throws SQLException T result = null; if (DOMResult.class == resultClass) { result = resultClass.cast(getDOMResult()); - } - else if (SAXResult.class == resultClass) { + } else if (SAXResult.class == resultClass) { result = resultClass.cast(getSAXResult()); - } - else if (StAXResult.class == resultClass) { + } else if (StAXResult.class == resultClass) { result = resultClass.cast(getStAXResult()); - } - else if (StreamResult.class == resultClass) { + } else if (StreamResult.class == resultClass) { outputStreamValue = new ByteArrayOutputStreamToInputStream(); result = resultClass.cast(new StreamResult(outputStreamValue)); - } - else - SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_notSupported"), null, true); + } else + SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_notSupported"), null, + true); return result; } @@ -388,8 +382,7 @@ private DOMSource getDOMSource() throws SQLException { builder.setEntityResolver(new SQLServerEntityResolver()); try { document = builder.parse(contents); - } - catch (IOException e) { + } catch (IOException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_errorReadingStream")); Object[] msgArgs = {e.toString()}; SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), "", true); @@ -397,13 +390,11 @@ private DOMSource getDOMSource() throws SQLException { DOMSource inputSource = new DOMSource(document); return inputSource; - } - catch (ParserConfigurationException e) { + } catch (ParserConfigurationException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_noParserSupport")); Object[] msgArgs = {e.toString()}; SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true); - } - catch (SAXException e) { + } catch (SAXException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_failedToParseXML")); Object[] msgArgs = {e.toString()}; SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true); @@ -420,8 +411,7 @@ private SAXSource getSAXSource() throws SQLException { SAXSource saxSource = new SAXSource(reader, src); return saxSource; - } - catch (SAXException | ParserConfigurationException e) { + } catch (SAXException | ParserConfigurationException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_failedToParseXML")); Object[] msgArgs = {e.toString()}; SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true); @@ -436,8 +426,7 @@ private StAXSource getStAXSource() throws SQLException { StAXSource result = new StAXSource(r); return result; - } - catch (XMLStreamException e) { + } catch (XMLStreamException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_noParserSupport")); Object[] msgArgs = {e.toString()}; SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true); @@ -453,8 +442,7 @@ private StAXResult getStAXResult() throws SQLException { StAXResult result = new StAXResult(r); return result; - } - catch (XMLStreamException e) { + } catch (XMLStreamException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_noParserSupport")); Object[] msgArgs = {e.toString()}; SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true); @@ -467,13 +455,11 @@ private SAXResult getSAXResult() throws SQLException { try { SAXTransformerFactory stf = (SAXTransformerFactory) TransformerFactory.newInstance(); handler = stf.newTransformerHandler(); - } - catch (TransformerConfigurationException e) { + } catch (TransformerConfigurationException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_noParserSupport")); Object[] msgArgs = {e.toString()}; SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true); - } - catch (ClassCastException e) { + } catch (ClassCastException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_noParserSupport")); Object[] msgArgs = {e.toString()}; SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true); @@ -494,8 +480,7 @@ private DOMResult getDOMResult() throws SQLException { DOMResult result = new DOMResult(docValue); return result; - } - catch (ParserConfigurationException e) { + } catch (ParserConfigurationException e) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_noParserSupport")); Object[] msgArgs = {e.toString()}; SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true); @@ -505,8 +490,10 @@ private DOMResult getDOMResult() throws SQLException { } -// We use this class to convert the byte information we have in the string to -// an inputstream which is used when sending to the info to the server + +/** + * Converts the byte information in the string to an inputstream which is used when sending to the info to the server. + */ final class ByteArrayOutputStreamToInputStream extends ByteArrayOutputStream { ByteArrayInputStream getInputStream() throws SQLServerException { ByteArrayInputStream is = new ByteArrayInputStream(buf, 0, count); @@ -514,10 +501,13 @@ ByteArrayInputStream getInputStream() throws SQLServerException { } } -// Resolves External entities in an XML with inline DTDs to empty string + +/** + * Resolves External entities in an XML with inline DTDs to empty string. + * + */ final class SQLServerEntityResolver implements EntityResolver { - public InputSource resolveEntity(String publicId, - String systemId) { + public InputSource resolveEntity(String publicId, String systemId) { return new InputSource(new StringReader("")); } } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSavepoint.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSavepoint.java index 0d10816f5..94679be97 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSavepoint.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSavepoint.java @@ -1,21 +1,19 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; import java.text.MessageFormat; + /** - * SQLServerSavepoint implements JDBC 3.0 savepoints. A savepoint is checkpoint to which a transaction can be rolled back. Savepoints are defined - * relative to a connection. + * Provides an implementation of JDBC Interface java.sql.Savepoint. A savepoint is checkpoint to which a transaction can + * be rolled back. Savepoints are defined relative to a connection. *

- * The API javadoc for JDBC API methods that this class implements are not repeated here. Please see Sun's JDBC API interfaces javadoc for those - * details. + * The API javadoc for JDBC API methods that this class implements are not repeated here. Please see Sun's JDBC API + * interfaces javadoc for those details. */ public final class SQLServerSavepoint implements ISQLServerSavepoint { @@ -24,21 +22,19 @@ public final class SQLServerSavepoint implements ISQLServerSavepoint { private final SQLServerConnection con; /** - * Create a new savepoint + * Constructs a SQLServerSavepoint. * * @param con - * the connection + * the connection * @param sName - * the savepoint name + * the savepoint name */ - public SQLServerSavepoint(SQLServerConnection con, - String sName) { + public SQLServerSavepoint(SQLServerConnection con, String sName) { this.con = con; if (sName == null) { nId = con.getNextSavepointId(); this.sName = null; - } - else { + } else { this.sName = sName; nId = 0; } @@ -47,7 +43,8 @@ public SQLServerSavepoint(SQLServerConnection con, @Override public String getSavepointName() throws SQLServerException { if (sName == null) - SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_savepointNotNamed"), null, false); + SQLServerException.makeFromDriverError(con, null, SQLServerException.getErrString("R_savepointNotNamed"), + null, false); return sName; } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSecurityUtility.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSecurityUtility.java index a54c8a6aa..45fa6c87b 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSecurityUtility.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSecurityUtility.java @@ -1,198 +1,192 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.util.Iterator; - -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; - -/** - * Various SQLServer security utilities. - * - */ -class SQLServerSecurityUtility { - - /** - * Give the hash of given plain text - * - * @param plainText - * @param key - * @param length - * @return hash of the plain text using provided key - * @throws NoSuchAlgorithmException - * @throws InvalidKeyException - */ - static byte[] getHMACWithSHA256(byte[] plainText, - byte[] key, - int length) throws NoSuchAlgorithmException, InvalidKeyException { - byte[] computedHash; - byte[] hash = new byte[length]; - Mac mac = Mac.getInstance("HmacSHA256"); - SecretKeySpec ivkeySpec = new SecretKeySpec(key, "HmacSHA256"); - mac.init(ivkeySpec); - computedHash = mac.doFinal(plainText); - // truncating hash if needed - System.arraycopy(computedHash, 0, hash, 0, hash.length); - return hash; - } - - /** - * Compare two arrays - * - * @param buffer1 - * first array - * @param buffer2 - * second array - * @param buffer2Index - * @param lengthToCompare - * @return true if array contains same bytes otherwise false - */ - static boolean compareBytes(byte[] buffer1, - byte[] buffer2, - int buffer2Index, - int lengthToCompare) { - if (null == buffer1 || null == buffer2) { - return false; - } - - if ((buffer2.length - buffer2Index) < lengthToCompare) { - return false; - } - - for (int index = 0; index < buffer1.length && index < lengthToCompare; ++index) { - if (buffer1[index] != buffer2[buffer2Index + index]) { - return false; - } - } - return true; - - } - - /* - * Encrypts the ciphertext. - */ - static byte[] encryptWithKey(byte[] plainText, - CryptoMetadata md, - SQLServerConnection connection) throws SQLServerException { - String serverName = connection.getTrustedServerNameAE(); - assert serverName != null : "Server name should npt be null in EncryptWithKey"; - - // Initialize cipherAlgo if not already done. - if (!md.IsAlgorithmInitialized()) { - SQLServerSecurityUtility.decryptSymmetricKey(md, connection); - } - - assert md.IsAlgorithmInitialized(); - byte[] cipherText = md.cipherAlgorithm.encryptData(plainText); // this call succeeds or throws. - if (null == cipherText || 0 == cipherText.length) { - throw new SQLServerException(null, SQLServerException.getErrString("R_NullCipherTextAE"), null, 0, false); - } - return cipherText; - } - - /** - * Return the algorithm name mapped to an Id - * - * @param cipherAlgorithmId - * The cipher algorithm Id - * @param cipherAlgorithmName - * The cipher algorithm name - * @return The cipher algorithm name - */ - private static String ValidateAndGetEncryptionAlgorithmName(byte cipherAlgorithmId, - String cipherAlgorithmName) throws SQLServerException { - // Custom cipher algorithm not supported for CTP. - if (TDS.AEAD_AES_256_CBC_HMAC_SHA256 != cipherAlgorithmId) { - throw new SQLServerException(null, SQLServerException.getErrString("R_CustomCipherAlgorithmNotSupportedAE"), null, 0, false); - } - return SQLServerAeadAes256CbcHmac256Algorithm.algorithmName; - } - - /** - * Decrypts the symmetric key and saves it in metadata. In addition, initializes the SqlClientEncryptionAlgorithm for rapid decryption. - * - * @param md - * The cipher metadata - * @param connection - * The connection - */ - static void decryptSymmetricKey(CryptoMetadata md, - SQLServerConnection connection) throws SQLServerException { - assert null != md : "md should not be null in DecryptSymmetricKey."; - assert null != md.cekTableEntry : "md.EncryptionInfo should not be null in DecryptSymmetricKey."; - assert null != md.cekTableEntry.columnEncryptionKeyValues : "md.EncryptionInfo.ColumnEncryptionKeyValues should not be null in DecryptSymmetricKey."; - - SQLServerSymmetricKey symKey = null; - EncryptionKeyInfo encryptionkeyInfoChosen = null; - SQLServerSymmetricKeyCache cache = SQLServerSymmetricKeyCache.getInstance(); - Iterator it = md.cekTableEntry.columnEncryptionKeyValues.iterator(); - SQLServerException lastException = null; - while (it.hasNext()) { - EncryptionKeyInfo keyInfo = it.next(); - try { - symKey = cache.getKey(keyInfo, connection); - if (null != symKey) { - encryptionkeyInfoChosen = keyInfo; - break; - } - } - catch (SQLServerException e) { - lastException = e; - } - } - - if (null == symKey) { - if (null != lastException) { - throw lastException; - } - else { - throw new SQLServerException(null, SQLServerException.getErrString("R_CEKDecryptionFailed"), null, 0, false); - } - } - - // Given the symmetric key instantiate a SqlClientEncryptionAlgorithm object and cache it in metadata. - md.cipherAlgorithm = null; - SQLServerEncryptionAlgorithm cipherAlgorithm = null; - String algorithmName = ValidateAndGetEncryptionAlgorithmName(md.cipherAlgorithmId, md.cipherAlgorithmName); // may throw - cipherAlgorithm = SQLServerEncryptionAlgorithmFactoryList.getInstance().getAlgorithm(symKey, md.encryptionType, algorithmName); // will - // validate - // algorithm - // name and - // type - assert null != cipherAlgorithm : "Cipher algorithm cannot be null in DecryptSymmetricKey"; - md.cipherAlgorithm = cipherAlgorithm; - md.encryptionKeyInfo = encryptionkeyInfoChosen; - } - - /* - * Decrypts the ciphertext. - */ - static byte[] decryptWithKey(byte[] cipherText, - CryptoMetadata md, - SQLServerConnection connection) throws SQLServerException { - String serverName = connection.getTrustedServerNameAE(); - assert null != serverName : "serverName should not be null in DecryptWithKey."; - - // Initialize cipherAlgo if not already done. - if (!md.IsAlgorithmInitialized()) { - SQLServerSecurityUtility.decryptSymmetricKey(md, connection); - } - - assert md.IsAlgorithmInitialized() : "Decryption Algorithm is not initialized"; - byte[] plainText = md.cipherAlgorithm.decryptData(cipherText); // this call succeeds or throws. - if (null == plainText) { - throw new SQLServerException(null, SQLServerException.getErrString("R_PlainTextNullAE"), null, 0, false); - } - - return plainText; - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.util.Iterator; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + + +/** + * Various SQLServer security utilities. + * + */ +class SQLServerSecurityUtility { + + /** + * Give the hash of given plain text + * + * @param plainText + * @param key + * @param length + * @return hash of the plain text using provided key + * @throws NoSuchAlgorithmException + * @throws InvalidKeyException + */ + static byte[] getHMACWithSHA256(byte[] plainText, byte[] key, + int length) throws NoSuchAlgorithmException, InvalidKeyException { + byte[] computedHash; + byte[] hash = new byte[length]; + Mac mac = Mac.getInstance("HmacSHA256"); + SecretKeySpec ivkeySpec = new SecretKeySpec(key, "HmacSHA256"); + mac.init(ivkeySpec); + computedHash = mac.doFinal(plainText); + // truncating hash if needed + System.arraycopy(computedHash, 0, hash, 0, hash.length); + return hash; + } + + /** + * Compare two arrays + * + * @param buffer1 + * first array + * @param buffer2 + * second array + * @param buffer2Index + * @param lengthToCompare + * @return true if array contains same bytes otherwise false + */ + static boolean compareBytes(byte[] buffer1, byte[] buffer2, int buffer2Index, int lengthToCompare) { + if (null == buffer1 || null == buffer2) { + return false; + } + + if ((buffer2.length - buffer2Index) < lengthToCompare) { + return false; + } + + for (int index = 0; index < buffer1.length && index < lengthToCompare; ++index) { + if (buffer1[index] != buffer2[buffer2Index + index]) { + return false; + } + } + return true; + + } + + /* + * Encrypts the ciphertext. + */ + static byte[] encryptWithKey(byte[] plainText, CryptoMetadata md, + SQLServerConnection connection) throws SQLServerException { + String serverName = connection.getTrustedServerNameAE(); + assert serverName != null : "Server name should npt be null in EncryptWithKey"; + + // Initialize cipherAlgo if not already done. + if (!md.IsAlgorithmInitialized()) { + SQLServerSecurityUtility.decryptSymmetricKey(md, connection); + } + + assert md.IsAlgorithmInitialized(); + byte[] cipherText = md.cipherAlgorithm.encryptData(plainText); // this call succeeds or throws. + if (null == cipherText || 0 == cipherText.length) { + throw new SQLServerException(null, SQLServerException.getErrString("R_NullCipherTextAE"), null, 0, false); + } + return cipherText; + } + + /** + * Return the algorithm name mapped to an Id + * + * @param cipherAlgorithmId + * The cipher algorithm Id + * @param cipherAlgorithmName + * The cipher algorithm name + * @return The cipher algorithm name + */ + private static String ValidateAndGetEncryptionAlgorithmName(byte cipherAlgorithmId, + String cipherAlgorithmName) throws SQLServerException { + // Custom cipher algorithm not supported for CTP. + if (TDS.AEAD_AES_256_CBC_HMAC_SHA256 != cipherAlgorithmId) { + throw new SQLServerException(null, SQLServerException.getErrString("R_CustomCipherAlgorithmNotSupportedAE"), + null, 0, false); + } + return SQLServerAeadAes256CbcHmac256Algorithm.algorithmName; + } + + /** + * Decrypts the symmetric key and saves it in metadata. In addition, initializes the SqlClientEncryptionAlgorithm + * for rapid decryption. + * + * @param md + * The cipher metadata + * @param connection + * The connection + */ + static void decryptSymmetricKey(CryptoMetadata md, SQLServerConnection connection) throws SQLServerException { + assert null != md : "md should not be null in DecryptSymmetricKey."; + assert null != md.cekTableEntry : "md.EncryptionInfo should not be null in DecryptSymmetricKey."; + assert null != md.cekTableEntry.columnEncryptionKeyValues : "md.EncryptionInfo.ColumnEncryptionKeyValues should not be null in DecryptSymmetricKey."; + + SQLServerSymmetricKey symKey = null; + EncryptionKeyInfo encryptionkeyInfoChosen = null; + SQLServerSymmetricKeyCache cache = SQLServerSymmetricKeyCache.getInstance(); + Iterator it = md.cekTableEntry.columnEncryptionKeyValues.iterator(); + SQLServerException lastException = null; + while (it.hasNext()) { + EncryptionKeyInfo keyInfo = it.next(); + try { + symKey = cache.getKey(keyInfo, connection); + if (null != symKey) { + encryptionkeyInfoChosen = keyInfo; + break; + } + } catch (SQLServerException e) { + lastException = e; + } + } + + if (null == symKey) { + if (null != lastException) { + throw lastException; + } else { + throw new SQLServerException(null, SQLServerException.getErrString("R_CEKDecryptionFailed"), null, 0, + false); + } + } + + // Given the symmetric key instantiate a SqlClientEncryptionAlgorithm object and cache it in metadata. + md.cipherAlgorithm = null; + SQLServerEncryptionAlgorithm cipherAlgorithm = null; + String algorithmName = ValidateAndGetEncryptionAlgorithmName(md.cipherAlgorithmId, md.cipherAlgorithmName); // may + // throw + cipherAlgorithm = SQLServerEncryptionAlgorithmFactoryList.getInstance().getAlgorithm(symKey, md.encryptionType, + algorithmName); // will + // validate + // algorithm + // name and + // type + assert null != cipherAlgorithm : "Cipher algorithm cannot be null in DecryptSymmetricKey"; + md.cipherAlgorithm = cipherAlgorithm; + md.encryptionKeyInfo = encryptionkeyInfoChosen; + } + + /* + * Decrypts the ciphertext. + */ + static byte[] decryptWithKey(byte[] cipherText, CryptoMetadata md, + SQLServerConnection connection) throws SQLServerException { + String serverName = connection.getTrustedServerNameAE(); + assert null != serverName : "serverName should not be null in DecryptWithKey."; + + // Initialize cipherAlgo if not already done. + if (!md.IsAlgorithmInitialized()) { + SQLServerSecurityUtility.decryptSymmetricKey(md, connection); + } + + assert md.IsAlgorithmInitialized() : "Decryption Algorithm is not initialized"; + byte[] plainText = md.cipherAlgorithm.decryptData(cipherText); // this call succeeds or throws. + if (null == plainText) { + throw new SQLServerException(null, SQLServerException.getErrString("R_PlainTextNullAE"), null, 0, false); + } + + return plainText; + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSortOrder.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSortOrder.java index 542912b76..8d724643d 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSortOrder.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSortOrder.java @@ -1,26 +1,23 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -/** - * - * Specifies the sorting order - * - */ -public enum SQLServerSortOrder { - Ascending (0), - Descending (1), - Unspecified (-1); - - final int value; - - SQLServerSortOrder(int sortOrderVal) { - value = sortOrderVal; - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +/** + * + * Specifies the sorting order + * + */ +public enum SQLServerSortOrder { + Ascending(0), + Descending(1), + Unspecified(-1); + + final int value; + + SQLServerSortOrder(int sortOrderVal) { + value = sortOrderVal; + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSpatialDatatype.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSpatialDatatype.java index 4c75590c3..4d18fcc28 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSpatialDatatype.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSpatialDatatype.java @@ -1,26 +1,29 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; import java.math.BigDecimal; import java.nio.ByteBuffer; +import java.nio.ByteOrder; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import java.util.Locale; + +/** + * Abstract parent class for Spatial Datatypes that contains common functionalities. + */ + abstract class SQLServerSpatialDatatype { /** WKT = Well-Known-Text, WKB = Well-Knwon-Binary */ /** - * As a general rule, the ~IndexEnd variables are non-inclusive (i.e. pointIndexEnd = 8 means the shape using it will only go up to the 7th index - * of the array) + * As a general rule, the ~IndexEnd variables are non-inclusive (i.e. pointIndexEnd = 8 means the shape using it + * will only go up to the 7th index of the array) */ protected ByteBuffer buffer; protected InternalSpatialDatatype internalType; @@ -40,7 +43,8 @@ abstract class SQLServerSpatialDatatype { protected int currentFigureIndex = 0; protected int currentSegmentIndex = 0; protected int currentShapeIndex = 0; - protected double points[]; + protected double xValues[]; + protected double yValues[]; protected double zValues[]; protected double mValues[]; protected Figure figures[]; @@ -91,48 +95,144 @@ abstract class SQLServerSpatialDatatype { * Serializes the Geogemetry/Geography instance to WKB. * * @param noZM - * flag to indicate if Z and M coordinates should be included + * flag to indicate if Z and M coordinates should be included */ - protected abstract void serializeToWkb(boolean noZM); + protected void serializeToWkb(boolean noZM, SQLServerSpatialDatatype type) { + ByteBuffer buf = ByteBuffer.allocate(determineWkbCapacity()); + createSerializationProperties(); + + buf.order(ByteOrder.LITTLE_ENDIAN); + buf.putInt(srid); + buf.put(version); + buf.put(serializationProperties); + + if (!isSinglePoint && !isSingleLineSegment) { + buf.putInt(numberOfPoints); + } + + if (type instanceof Geometry) { + for (int i = 0; i < numberOfPoints; i++) { + buf.putDouble(xValues[i]); + buf.putDouble(yValues[i]); + } + } else { // Geography + for (int i = 0; i < numberOfPoints; i++) { + buf.putDouble(yValues[i]); + buf.putDouble(xValues[i]); + } + } + + if (!noZM) { + if (hasZvalues) { + for (int i = 0; i < numberOfPoints; i++) { + buf.putDouble(zValues[i]); + } + } + + if (hasMvalues) { + for (int i = 0; i < numberOfPoints; i++) { + buf.putDouble(mValues[i]); + } + } + } + + if (isSinglePoint || isSingleLineSegment) { + wkb = buf.array(); + return; + } + + buf.putInt(numberOfFigures); + for (int i = 0; i < numberOfFigures; i++) { + buf.put(figures[i].getFiguresAttribute()); + buf.putInt(figures[i].getPointOffset()); + } + + buf.putInt(numberOfShapes); + for (int i = 0; i < numberOfShapes; i++) { + buf.putInt(shapes[i].getParentOffset()); + buf.putInt(shapes[i].getFigureOffset()); + buf.put(shapes[i].getOpenGISType()); + } + + if (version == 2 && null != segments) { + buf.putInt(numberOfSegments); + for (int i = 0; i < numberOfSegments; i++) { + buf.put(segments[i].getSegmentType()); + } + } + + if (noZM) { + wkbNoZM = buf.array(); + } else { + wkb = buf.array(); + } + } /** - * Deserialize the buffer (that contains WKB representation of Geometry/Geography data), and stores it into multiple corresponding data - * structures. + * Deserializes the buffer (that contains WKB representation of Geometry/Geography data), and stores it into + * multiple corresponding data structures. * */ - protected abstract void parseWkb(); + protected void parseWkb(SQLServerSpatialDatatype type) throws SQLServerException { + srid = readInt(); + version = readByte(); + serializationProperties = readByte(); + + interpretSerializationPropBytes(); + readNumberOfPoints(); + readPoints(type); + + if (hasZvalues) { + readZvalues(); + } + + if (hasMvalues) { + readMvalues(); + } + + if (!(isSinglePoint || isSingleLineSegment)) { + readNumberOfFigures(); + readFigures(); + readNumberOfShapes(); + readShapes(); + } + + determineInternalType(); + + if (buffer.hasRemaining()) { + if (version == 2 && internalType.getTypeCode() != 8 && internalType.getTypeCode() != 11) { + readNumberOfSegments(); + readSegments(); + } + } + } /** - * Create the WKT representation of Geometry/Geography from the deserialized data. + * Constructs the WKT representation of Geometry/Geography from the deserialized data. * * @param sd - * the Geometry/Geography instance. + * the Geometry/Geography instance. * @param isd - * internal spatial datatype object + * internal spatial datatype object * @param pointIndexEnd - * upper bound for reading points + * upper bound for reading points * @param figureIndexEnd - * upper bound for reading figures + * upper bound for reading figures * @param segmentIndexEnd - * upper bound for reading segments + * upper bound for reading segments * @param shapeIndexEnd - * upper bound for reading shapes + * upper bound for reading shapes * @throws SQLServerException - * if an exception occurs + * if an exception occurs */ - protected void constructWKT(SQLServerSpatialDatatype sd, - InternalSpatialDatatype isd, - int pointIndexEnd, - int figureIndexEnd, - int segmentIndexEnd, - int shapeIndexEnd) throws SQLServerException { - if (null == points || numberOfPoints == 0) { + protected void constructWKT(SQLServerSpatialDatatype sd, InternalSpatialDatatype isd, int pointIndexEnd, + int figureIndexEnd, int segmentIndexEnd, int shapeIndexEnd) throws SQLServerException { + if (numberOfPoints == 0) { if (isd.getTypeCode() == 11) { // FULLGLOBE if (sd instanceof Geometry) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_illegalTypeForGeometry")); throw new SQLServerException(form.format(new Object[] {"Fullglobe"}), null, 0, null); - } - else { + } else { appendToWKTBuffers("FULLGLOBE"); return; } @@ -141,8 +241,8 @@ protected void constructWKT(SQLServerSpatialDatatype sd, if (isd.getTypeCode() == 7 && currentShapeIndex != shapeIndexEnd - 1) { currentShapeIndex++; appendToWKTBuffers(isd.getTypeName() + "("); - constructWKT(this, InternalSpatialDatatype.valueOf(shapes[currentShapeIndex].getOpenGISType()), numberOfPoints, numberOfFigures, - numberOfSegments, numberOfShapes); + constructWKT(this, InternalSpatialDatatype.valueOf(shapes[currentShapeIndex].getOpenGISType()), + numberOfPoints, numberOfFigures, numberOfSegments, numberOfShapes); appendToWKTBuffers(")"); return; } @@ -181,8 +281,7 @@ protected void constructWKT(SQLServerSpatialDatatype sd, constructCurvepolygonWKT(currentFigureIndex, figureIndexEnd, currentSegmentIndex, segmentIndexEnd); break; default: - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_illegalWKTposition")); - throw new SQLServerException(form.format(new Object[] {currentWktPos}), null, 0, null); + throwIllegalWKTPosition(); } appendToWKTBuffers(")"); @@ -192,19 +291,17 @@ protected void constructWKT(SQLServerSpatialDatatype sd, * Parses WKT and populates the data structures of the Geometry/Geography instance. * * @param sd - * the Geometry/Geography instance. + * the Geometry/Geography instance. * @param startPos - * The index to start from from the WKT. + * The index to start from from the WKT. * @param parentShapeIndex - * The index of the parent's Shape in the shapes array. Used to determine this shape's parent. + * The index of the parent's Shape in the shapes array. Used to determine this shape's parent. * @param isGeoCollection - * flag to indicate if this is part of a GeometryCollection. + * flag to indicate if this is part of a GeometryCollection. * @throws SQLServerException - * if an exception occurs + * if an exception occurs */ - protected void parseWKTForSerialization(SQLServerSpatialDatatype sd, - int startPos, - int parentShapeIndex, + protected void parseWKTForSerialization(SQLServerSpatialDatatype sd, int startPos, int parentShapeIndex, boolean isGeoCollection) throws SQLServerException { // after every iteration of this while loop, the currentWktPosition will be set to the // end of the geometry/geography shape, except for the very first iteration of it. @@ -215,8 +312,7 @@ protected void parseWKTForSerialization(SQLServerSpatialDatatype sd, if (startPos != 0) { if (wkt.charAt(currentWktPos) == ')') { return; - } - else if (wkt.charAt(currentWktPos) == ',') { + } else if (wkt.charAt(currentWktPos) == ',') { currentWktPos++; } } @@ -226,14 +322,13 @@ else if (wkt.charAt(currentWktPos) == ',') { InternalSpatialDatatype isd = InternalSpatialDatatype.INVALID_TYPE; try { isd = InternalSpatialDatatype.valueOf(nextToken); - } - catch (Exception e) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_illegalWKTposition")); - throw new SQLServerException(form.format(new Object[] {currentWktPos}), null, 0, null); + } catch (Exception e) { + throwIllegalWKTPosition(); } byte fa = 0; - if (version == 1 && (nextToken.equals("CIRCULARSTRING") || nextToken.equals("COMPOUNDCURVE") || nextToken.equals("CURVEPOLYGON"))) { + if (version == 1 && (nextToken.equals("CIRCULARSTRING") || nextToken.equals("COMPOUNDCURVE") + || nextToken.equals("CURVEPOLYGON"))) { version = 2; } @@ -245,8 +340,7 @@ else if (wkt.charAt(currentWktPos) == ',') { } if (startPos != 0) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_illegalWKTposition")); - throw new SQLServerException(form.format(new Object[] {currentWktPos}), null, 0, null); + throwIllegalWKTPosition(); } shapeList.add(new Shape(parentShapeIndex, -1, isd.getTypeCode())); @@ -266,6 +360,7 @@ else if (wkt.charAt(currentWktPos) == ',') { case "POINT": if (startPos == 0 && nextToken.toUpperCase().equals("POINT")) { isSinglePoint = true; + internalType = InternalSpatialDatatype.POINT; } if (isGeoCollection) { @@ -278,7 +373,8 @@ else if (wkt.charAt(currentWktPos) == ',') { case "LINESTRING": case "CIRCULARSTRING": shapeList.add(new Shape(parentShapeIndex, figureList.size(), isd.getTypeCode())); - fa = isd.getTypeCode() == InternalSpatialDatatype.LINESTRING.getTypeCode() ? FA_STROKE : FA_EXTERIOR_RING; + fa = isd.getTypeCode() == InternalSpatialDatatype.LINESTRING.getTypeCode() ? FA_STROKE + : FA_EXTERIOR_RING; figureList.add(new Figure(fa, pointList.size())); readLineWkt(); @@ -324,8 +420,7 @@ else if (wkt.charAt(currentWktPos) == ',') { break; default: - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_illegalWKTposition")); - throw new SQLServerException(form.format(new Object[] {currentWktPos}), null, 0, null); + throwIllegalWKTPosition(); } readCloseBracket(); } @@ -334,53 +429,47 @@ else if (wkt.charAt(currentWktPos) == ',') { } /** - * Constructs and appends a Point type in WKT form to the stringbuffer. There are two stringbuffers - WKTsb and WKTsbNoZM. WKTsb contains the X, - * Y, Z and M coordinates, whereas WKTsbNoZM contains only X and Y coordinates. + * Constructs and appends a Point type in WKT form to the stringbuffer. There are two stringbuffers - WKTsb and + * WKTsbNoZM. WKTsb contains the X, Y, Z and M coordinates, whereas WKTsbNoZM contains only X and Y coordinates. * * @param pointIndex - * indicates which point to append to the stringbuffer. + * indicates which point to append to the stringbuffer. * */ protected void constructPointWKT(int pointIndex) { - int firstPointIndex = pointIndex * 2; - int secondPointIndex = firstPointIndex + 1; - int zValueIndex = pointIndex; - int mValueIndex = pointIndex; - - if (points[firstPointIndex] % 1 == 0) { - appendToWKTBuffers((int) points[firstPointIndex]); - } - else { - appendToWKTBuffers(points[firstPointIndex]); + if (xValues[pointIndex] % 1 == 0) { + appendToWKTBuffers((int) xValues[pointIndex]); + } else { + appendToWKTBuffers(xValues[pointIndex]); } appendToWKTBuffers(" "); - if (points[secondPointIndex] % 1 == 0) { - appendToWKTBuffers((int) points[secondPointIndex]); - } - else { - appendToWKTBuffers(points[secondPointIndex]); + if (yValues[pointIndex] % 1 == 0) { + appendToWKTBuffers((int) yValues[pointIndex]); + } else { + appendToWKTBuffers(yValues[pointIndex]); } appendToWKTBuffers(" "); - if (hasZvalues && !Double.isNaN(zValues[zValueIndex]) && !(zValues[zValueIndex] == 0)) { - if (zValues[zValueIndex] % 1 == 0) { - WKTsb.append((int) zValues[zValueIndex]); - } - else { - WKTsb.append(zValues[zValueIndex]); + if (hasZvalues && !Double.isNaN(zValues[pointIndex])) { + if (zValues[pointIndex] % 1 == 0) { + WKTsb.append((long) zValues[pointIndex]); + } else { + WKTsb.append(zValues[pointIndex]); } WKTsb.append(" "); + } else if (hasMvalues && !Double.isNaN(mValues[pointIndex])) { + // Handle the case where the user has POINT (1 2 NULL M) value. + WKTsb.append("NULL "); + } - if (hasMvalues && !Double.isNaN(mValues[mValueIndex]) && !(mValues[mValueIndex] <= 0)) { - if (mValues[mValueIndex] % 1 == 0) { - WKTsb.append((int) mValues[mValueIndex]); - } - else { - WKTsb.append(mValues[mValueIndex]); - } - WKTsb.append(" "); + if (hasMvalues && !Double.isNaN(mValues[pointIndex])) { + if (mValues[pointIndex] % 1 == 0) { + WKTsb.append((long) mValues[pointIndex]); + } else { + WKTsb.append(mValues[pointIndex]); } + WKTsb.append(" "); } currentPointIndex++; @@ -393,12 +482,11 @@ protected void constructPointWKT(int pointIndex) { * Constructs a line in WKT form. * * @param pointStartIndex - * . + * . * @param pointEndIndex - * . + * . */ - protected void constructLineWKT(int pointStartIndex, - int pointEndIndex) { + protected void constructLineWKT(int pointStartIndex, int pointEndIndex) { for (int i = pointStartIndex; i < pointEndIndex; i++) { constructPointWKT(i); @@ -413,25 +501,22 @@ protected void constructLineWKT(int pointStartIndex, * Constructs a shape (simple Geometry/Geography entities that are contained within a single bracket) in WKT form. * * @param figureStartIndex - * . + * . * @param figureEndIndex - * . + * . */ - protected void constructShapeWKT(int figureStartIndex, - int figureEndIndex) { + protected void constructShapeWKT(int figureStartIndex, int figureEndIndex) { for (int i = figureStartIndex; i < figureEndIndex; i++) { appendToWKTBuffers("("); if (i != numberOfFigures - 1) { // not the last figure constructLineWKT(figures[i].getPointOffset(), figures[i + 1].getPointOffset()); - } - else { + } else { constructLineWKT(figures[i].getPointOffset(), numberOfPoints); } if (i != figureEndIndex - 1) { appendToWKTBuffers("), "); - } - else { + } else { appendToWKTBuffers(")"); } } @@ -441,17 +526,15 @@ protected void constructShapeWKT(int figureStartIndex, * Constructs a mutli-shape (MultiPoint / MultiLineString) in WKT form. * * @param shapeStartIndex - * . + * . * @param shapeEndIndex - * . + * . */ - protected void constructMultiShapeWKT(int shapeStartIndex, - int shapeEndIndex) { + protected void constructMultiShapeWKT(int shapeStartIndex, int shapeEndIndex) { for (int i = shapeStartIndex + 1; i < shapeEndIndex; i++) { if (shapes[i].getFigureOffset() == -1) { // EMPTY appendToWKTBuffers("EMPTY"); - } - else { + } else { constructShapeWKT(shapes[i].getFigureOffset(), shapes[i].getFigureOffset() + 1); } if (i != shapeEndIndex - 1) { @@ -464,15 +547,13 @@ protected void constructMultiShapeWKT(int shapeStartIndex, * Constructs a CompoundCurve in WKT form. * * @param segmentStartIndex - * . + * . * @param segmentEndIndex - * . + * . * @param pointEndIndex - * . + * . */ - protected void constructCompoundcurveWKT(int segmentStartIndex, - int segmentEndIndex, - int pointEndIndex) { + protected void constructCompoundcurveWKT(int segmentStartIndex, int segmentEndIndex, int pointEndIndex) { for (int i = segmentStartIndex; i < segmentEndIndex; i++) { byte segment = segments[i].getSegmentType(); constructSegmentWKT(i, segment, pointEndIndex); @@ -505,12 +586,11 @@ protected void constructCompoundcurveWKT(int segmentStartIndex, * Constructs a MultiPolygon in WKT form. * * @param shapeStartIndex - * . + * . * @param shapeEndIndex - * . + * . */ - protected void constructMultipolygonWKT(int shapeStartIndex, - int shapeEndIndex) { + protected void constructMultipolygonWKT(int shapeStartIndex, int shapeEndIndex) { int figureStartIndex; int figureEndIndex; @@ -526,8 +606,7 @@ protected void constructMultipolygonWKT(int shapeStartIndex, figureStartIndex = shapes[i].getFigureOffset(); if (i == shapes.length - 1) { // last shape figureEndIndex = figures.length; - } - else { + } else { // look ahead and find the next shape that doesn't have -1 as its figure offset (which signifies EMPTY) int tempCurrentShapeIndex = i + 1; // We need to iterate this through until the very end of the shapes list, since if the last shape @@ -536,8 +615,7 @@ protected void constructMultipolygonWKT(int shapeStartIndex, if (shapes[tempCurrentShapeIndex].getFigureOffset() == -1) { tempCurrentShapeIndex++; continue; - } - else { + } else { figureEndIndex = shapes[tempCurrentShapeIndex].getFigureOffset(); break; } @@ -551,15 +629,13 @@ protected void constructMultipolygonWKT(int shapeStartIndex, if (j == figures.length - 1) { // last figure constructLineWKT(figures[j].getPointOffset(), numberOfPoints); - } - else { + } else { constructLineWKT(figures[j].getPointOffset(), figures[j + 1].getPointOffset()); } if (j == figureEndIndex - 1) { // last polygon of this multipolygon, close off the Multipolygon appendToWKTBuffers(")"); - } - else { // not the last polygon, followed by an interior ring + } else { // not the last polygon, followed by an interior ring appendToWKTBuffers("), "); } } @@ -576,17 +652,15 @@ protected void constructMultipolygonWKT(int shapeStartIndex, * Constructs a CurvePolygon in WKT form. * * @param figureStartIndex - * . + * . * @param figureEndIndex - * . + * . * @param segmentStartIndex - * . + * . * @param segmentEndIndex - * . + * . */ - protected void constructCurvepolygonWKT(int figureStartIndex, - int figureEndIndex, - int segmentStartIndex, + protected void constructCurvepolygonWKT(int figureStartIndex, int figureEndIndex, int segmentStartIndex, int segmentEndIndex) { for (int i = figureStartIndex; i < figureEndIndex; i++) { switch (figures[i].getFiguresAttribute()) { @@ -595,8 +669,7 @@ protected void constructCurvepolygonWKT(int figureStartIndex, if (i == figures.length - 1) { constructLineWKT(currentPointIndex, numberOfPoints); - } - else { + } else { constructLineWKT(currentPointIndex, figures[i + 1].getPointOffset()); } @@ -607,8 +680,7 @@ protected void constructCurvepolygonWKT(int figureStartIndex, if (i == figures.length - 1) { constructLineWKT(currentPointIndex, numberOfPoints); - } - else { + } else { constructLineWKT(currentPointIndex, figures[i + 1].getPointOffset()); } @@ -622,8 +694,7 @@ protected void constructCurvepolygonWKT(int figureStartIndex, if (i == figures.length - 1) { pointEndIndex = numberOfPoints; - } - else { + } else { pointEndIndex = figures[i + 1].getPointOffset(); } @@ -633,8 +704,7 @@ protected void constructCurvepolygonWKT(int figureStartIndex, if (!(currentPointIndex < pointEndIndex)) { appendToWKTBuffers("))"); - } - else { + } else { switch (segment) { case 0: case 2: @@ -669,21 +739,20 @@ protected void constructCurvepolygonWKT(int figureStartIndex, } /** - * Constructs a Segment in WKT form. SQL Server re-uses the last point of a segment if the following segment is of type 3 (first arc) or type 2 - * (first line). This makes sense because the last point of a segment and the first point of the next segment have to match for a valid curve. - * This means that the code has to look ahead and decide to decrement the currentPointIndex depending on what segment comes next, since it may - * have been reused (and it's reflected in the array of points) + * Constructs a Segment in WKT form. SQL Server re-uses the last point of a segment if the following segment is of + * type 3 (first arc) or type 2 (first line). This makes sense because the last point of a segment and the first + * point of the next segment have to match for a valid curve. This means that the code has to look ahead and decide + * to decrement the currentPointIndex depending on what segment comes next, since it may have been reused (and it's + * reflected in the array of points) * * @param currentSegment - * . + * . * @param segment - * . + * . * @param pointEndIndex - * . + * . */ - protected void constructSegmentWKT(int currentSegment, - byte segment, - int pointEndIndex) { + protected void constructSegmentWKT(int currentSegment, byte segment, int pointEndIndex) { switch (segment) { case 0: appendToWKTBuffers(", "); @@ -691,8 +760,8 @@ protected void constructSegmentWKT(int currentSegment, if (currentSegment == segments.length - 1) { // last segment break; - } - else if (segments[currentSegment + 1].getSegmentType() != 0) { // not being followed by another line, but not the last segment + } else if (segments[currentSegment + 1].getSegmentType() != 0) { // not being followed by another line, + // but not the last segment currentPointIndex = currentPointIndex - 1; incrementPointNumStartIfPointNotReused(pointEndIndex); } @@ -704,9 +773,10 @@ else if (segments[currentSegment + 1].getSegmentType() != 0) { // not being foll if (currentSegment == segments.length - 1) { // last segment break; - } - else if (segments[currentSegment + 1].getSegmentType() != 1) { // not being followed by another arc, but not the last segment - currentPointIndex = currentPointIndex - 1; // only increment pointNumStart by one less than what we should be, since the last + } else if (segments[currentSegment + 1].getSegmentType() != 1) { // not being followed by another arc, + // but not the last segment + currentPointIndex = currentPointIndex - 1; // only increment pointNumStart by one less than what we + // should be, since the last // point will be reused incrementPointNumStartIfPointNotReused(pointEndIndex); } @@ -718,9 +788,10 @@ else if (segments[currentSegment + 1].getSegmentType() != 1) { // not being foll if (currentSegment == segments.length - 1) { // last segment break; - } - else if (segments[currentSegment + 1].getSegmentType() != 0) { // not being followed by another line, but not the last segment - currentPointIndex = currentPointIndex - 1; // only increment pointNumStart by one less than what we should be, since the last + } else if (segments[currentSegment + 1].getSegmentType() != 0) { // not being followed by another line, + // but not the last segment + currentPointIndex = currentPointIndex - 1; // only increment pointNumStart by one less than what we + // should be, since the last // point will be reused incrementPointNumStartIfPointNotReused(pointEndIndex); } @@ -732,9 +803,9 @@ else if (segments[currentSegment + 1].getSegmentType() != 0) { // not being foll if (currentSegment == segments.length - 1) { // last segment break; - } - else if (segments[currentSegment + 1].getSegmentType() != 1) { // not being followed by another arc - currentPointIndex = currentPointIndex - 1; // only increment pointNumStart by one less than what we should be, since the last + } else if (segments[currentSegment + 1].getSegmentType() != 1) { // not being followed by another arc + currentPointIndex = currentPointIndex - 1; // only increment pointNumStart by one less than what we + // should be, since the last // point will be reused incrementPointNumStartIfPointNotReused(pointEndIndex); } @@ -749,9 +820,9 @@ else if (segments[currentSegment + 1].getSegmentType() != 1) { // not being foll * The starting point for constructing a GeometryCollection type in WKT form. * * @param shapeEndIndex - * . + * . * @throws SQLServerException - * if an exception occurs + * if an exception occurs */ protected void constructGeometryCollectionWKT(int shapeEndIndex) throws SQLServerException { currentShapeIndex++; @@ -759,16 +830,19 @@ protected void constructGeometryCollectionWKT(int shapeEndIndex) throws SQLServe } /** - * Reads Point WKT and adds it to the list of points. This method will read up until and including the comma that may come at the end of the Point - * WKT. + * Reads Point WKT and adds it to the list of points. This method will read up until and including the comma that + * may come at the end of the Point WKT. * * @throws SQLServerException - * if an exception occurs + * if an exception occurs */ protected void readPointWkt() throws SQLServerException { int numOfCoordinates = 0; double sign; double coords[] = new double[4]; + for (int i = 0; i < coords.length; i++) { + coords[i] = Double.NaN; + } while (numOfCoordinates < 4) { sign = 1; @@ -783,17 +857,30 @@ protected void readPointWkt() throws SQLServerException { break; } - while (currentWktPos < wkt.length() && (Character.isDigit(wkt.charAt(currentWktPos)) || wkt.charAt(currentWktPos) == '.' - || wkt.charAt(currentWktPos) == 'E' || wkt.charAt(currentWktPos) == 'e')) { + while (currentWktPos < wkt.length() + && (Character.isDigit(wkt.charAt(currentWktPos)) || wkt.charAt(currentWktPos) == '.' + || wkt.charAt(currentWktPos) == 'E' || wkt.charAt(currentWktPos) == 'e')) { currentWktPos++; } try { coords[numOfCoordinates] = sign * new BigDecimal(wkt.substring(startPos, currentWktPos)).doubleValue(); - } - catch (Exception e) { // modify to conversion exception - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_illegalWKTposition")); - throw new SQLServerException(form.format(new Object[] {currentWktPos}), null, 0, null); + + if (numOfCoordinates == 2) { + hasZvalues = true; + } else if (numOfCoordinates == 3) { + hasMvalues = true; + } + } catch (Exception e) { // modify to conversion exception + // handle NULL case + // the first check ensures that there is enough space for the wkt to have NULL + if (wkt.length() > currentWktPos + 3 + && wkt.substring(currentWktPos, currentWktPos + 4).equalsIgnoreCase("null")) { + coords[numOfCoordinates] = Double.NaN; + currentWktPos = currentWktPos + 4; + } else { + throwIllegalWKTPosition(); + } } numOfCoordinates++; @@ -803,17 +890,16 @@ protected void readPointWkt() throws SQLServerException { // After skipping white space after the 4th coordinate has been read, the next // character has to be either a , or ), or the WKT is invalid. if (numOfCoordinates == 4) { - if (wkt.charAt(currentWktPos) != ',' && wkt.charAt(currentWktPos) != ')') { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_illegalWKTposition")); - throw new SQLServerException(form.format(new Object[] {currentWktPos}), null, 0, null); + if (checkSQLLength(currentWktPos + 1) && wkt.charAt(currentWktPos) != ',' + && wkt.charAt(currentWktPos) != ')') { + throwIllegalWKTPosition(); } } - if (wkt.charAt(currentWktPos) == ',') { + if (checkSQLLength(currentWktPos + 1) && wkt.charAt(currentWktPos) == ',') { // need at least 2 coordinates if (numOfCoordinates == 1) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_illegalWKTposition")); - throw new SQLServerException(form.format(new Object[] {currentWktPos}), null, 0, null); + throwIllegalWKTPosition(); } currentWktPos++; skipWhiteSpaces(); @@ -822,14 +908,6 @@ protected void readPointWkt() throws SQLServerException { skipWhiteSpaces(); } - if (numOfCoordinates == 4) { - hasZvalues = true; - hasMvalues = true; - } - else if (numOfCoordinates == 3) { - hasZvalues = true; - } - pointList.add(new Point(coords[0], coords[1], coords[2], coords[3])); } @@ -837,7 +915,7 @@ else if (numOfCoordinates == 3) { * Reads a series of Point types. * * @throws SQLServerException - * if an exception occurs + * if an exception occurs */ protected void readLineWkt() throws SQLServerException { while (currentWktPos < wkt.length() && wkt.charAt(currentWktPos) != ')') { @@ -849,40 +927,39 @@ protected void readLineWkt() throws SQLServerException { * Reads a shape (simple Geometry/Geography entities that are contained within a single bracket) WKT. * * @param parentShapeIndex - * shape index of the parent shape that called this method + * shape index of the parent shape that called this method * @param nextToken - * next string token + * next string token * @throws SQLServerException - * if an exception occurs + * if an exception occurs */ - protected void readShapeWkt(int parentShapeIndex, - String nextToken) throws SQLServerException { + protected void readShapeWkt(int parentShapeIndex, String nextToken) throws SQLServerException { byte fa = FA_POINT; while (currentWktPos < wkt.length() && wkt.charAt(currentWktPos) != ')') { // if next keyword is empty, continue the loop. // Do not check this for polygon. - if (!nextToken.equals("POLYGON") && checkEmptyKeyword(parentShapeIndex, InternalSpatialDatatype.valueOf(nextToken), true)) { + if (!nextToken.equals("POLYGON") + && checkEmptyKeyword(parentShapeIndex, InternalSpatialDatatype.valueOf(nextToken), true)) { continue; } if (nextToken.equals("MULTIPOINT")) { - shapeList.add(new Shape(parentShapeIndex, figureList.size(), InternalSpatialDatatype.POINT.getTypeCode())); - } - else if (nextToken.equals("MULTILINESTRING")) { - shapeList.add(new Shape(parentShapeIndex, figureList.size(), InternalSpatialDatatype.LINESTRING.getTypeCode())); + shapeList.add( + new Shape(parentShapeIndex, figureList.size(), InternalSpatialDatatype.POINT.getTypeCode())); + } else if (nextToken.equals("MULTILINESTRING")) { + shapeList.add(new Shape(parentShapeIndex, figureList.size(), + InternalSpatialDatatype.LINESTRING.getTypeCode())); } if (version == 1) { if (nextToken.equals("MULTIPOINT")) { fa = FA_STROKE; - } - else if (nextToken.equals("MULTILINESTRING") || nextToken.equals("POLYGON")) { + } else if (nextToken.equals("MULTILINESTRING") || nextToken.equals("POLYGON")) { fa = FA_EXTERIOR_RING; } version_one_shape_indexes.add(figureList.size()); - } - else if (version == 2) { + } else if (version == 2) { if (nextToken.equals("MULTIPOINT") || nextToken.equals("MULTILINESTRING") || nextToken.equals("POLYGON") || nextToken.equals("MULTIPOLYGON")) { fa = FA_LINE; @@ -896,24 +973,21 @@ else if (version == 2) { skipWhiteSpaces(); - if (wkt.charAt(currentWktPos) == ',') { // more rings to follow + if (checkSQLLength(currentWktPos + 1) && wkt.charAt(currentWktPos) == ',') { // more rings to follow readComma(); - } - else if (wkt.charAt(currentWktPos) == ')') { // about to exit while loop + } else if (wkt.charAt(currentWktPos) == ')') { // about to exit while loop continue; - } - else { // unexpected input - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_illegalWKTposition")); - throw new SQLServerException(form.format(new Object[] {currentWktPos}), null, 0, null); + } else { // unexpected input + throwIllegalWKTPosition(); } } } /** - * Reads a CurvePolygon WKT + * Reads a CurvePolygon WKT. * * @throws SQLServerException - * if an exception occurs + * if an exception occurs */ protected void readCurvePolygon() throws SQLServerException { while (currentWktPos < wkt.length() && wkt.charAt(currentWktPos) != ')') { @@ -923,83 +997,72 @@ protected void readCurvePolygon() throws SQLServerException { readOpenBracket(); readLineWkt(); readCloseBracket(); - } - else if (nextPotentialToken.equals("COMPOUNDCURVE")) { + } else if (nextPotentialToken.equals("COMPOUNDCURVE")) { figureList.add(new Figure(FA_COMPOSITE_CURVE, pointList.size())); readOpenBracket(); readCompoundCurveWkt(true); readCloseBracket(); - } - else if (wkt.charAt(currentWktPos) == '(') { // LineString + } else if (wkt.charAt(currentWktPos) == '(') { // LineString figureList.add(new Figure(FA_LINE, pointList.size())); readOpenBracket(); readLineWkt(); readCloseBracket(); - } - else { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_illegalWKTposition")); - throw new SQLServerException(form.format(new Object[] {currentWktPos}), null, 0, null); + } else { + throwIllegalWKTPosition(); } - if (wkt.charAt(currentWktPos) == ',') { // more polygons to follow + if (checkSQLLength(currentWktPos + 1) && wkt.charAt(currentWktPos) == ',') { // more polygons to follow readComma(); - } - else if (wkt.charAt(currentWktPos) == ')') { // about to exit while loop + } else if (wkt.charAt(currentWktPos) == ')') { // about to exit while loop continue; - } - else { // unexpected input - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_illegalWKTposition")); - throw new SQLServerException(form.format(new Object[] {currentWktPos}), null, 0, null); + } else { // unexpected input + throwIllegalWKTPosition(); } } } /** - * Reads a MultiPolygon WKT + * Reads a MultiPolygon WKT. * * @param thisShapeIndex - * shape index of current shape + * shape index of current shape * @param nextToken - * next string token + * next string token * @throws SQLServerException - * if an exception occurs + * if an exception occurs */ - protected void readMultiPolygonWkt(int thisShapeIndex, - String nextToken) throws SQLServerException { + protected void readMultiPolygonWkt(int thisShapeIndex, String nextToken) throws SQLServerException { while (currentWktPos < wkt.length() && wkt.charAt(currentWktPos) != ')') { if (checkEmptyKeyword(thisShapeIndex, InternalSpatialDatatype.valueOf(nextToken), true)) { continue; } - shapeList.add(new Shape(thisShapeIndex, figureList.size(), InternalSpatialDatatype.POLYGON.getTypeCode())); // exterior polygon + shapeList.add(new Shape(thisShapeIndex, figureList.size(), InternalSpatialDatatype.POLYGON.getTypeCode())); // exterior + // polygon readOpenBracket(); readShapeWkt(thisShapeIndex, nextToken); readCloseBracket(); - if (wkt.charAt(currentWktPos) == ',') { // more polygons to follow + if (checkSQLLength(currentWktPos + 1) && wkt.charAt(currentWktPos) == ',') { // more polygons to follow readComma(); - } - else if (wkt.charAt(currentWktPos) == ')') { // about to exit while loop + } else if (wkt.charAt(currentWktPos) == ')') { // about to exit while loop continue; - } - else { // unexpected input - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_illegalWKTposition")); - throw new SQLServerException(form.format(new Object[] {currentWktPos}), null, 0, null); + } else { // unexpected input + throwIllegalWKTPosition(); } } } /** - * Reads a Segment WKT + * Reads a Segment WKT. * * @param segmentType - * segment type + * segment type * @param isFirstIteration - * flag that indicates if this is the first iteration from the loop outside + * flag that indicates if this is the first iteration from the loop outside * @throws SQLServerException - * if an exception occurs + * if an exception occurs */ - protected void readSegmentWkt(int segmentType, - boolean isFirstIteration) throws SQLServerException { + protected void readSegmentWkt(int segmentType, boolean isFirstIteration) throws SQLServerException { segmentList.add(new Segment((byte) segmentType)); int segmentLength = segmentType; @@ -1010,12 +1073,12 @@ protected void readSegmentWkt(int segmentType, } for (int i = 0; i < segmentLength; i++) { - // If a segment type of 2 (first line) or 3 (first arc) is not from the very first iteration of the while loop, + // If a segment type of 2 (first line) or 3 (first arc) is not from the very first iteration of the while + // loop, // then the first point has to be a duplicate point from the previous segment, so skip the first point. if (i == 0 && !isFirstIteration && segmentType >= 2) { skipFirstPointWkt(); - } - else { + } else { readPointWkt(); } } @@ -1023,20 +1086,19 @@ protected void readSegmentWkt(int segmentType, if (currentWktPos < wkt.length() && wkt.charAt(currentWktPos) != ')') { if (segmentType == SEGMENT_FIRST_ARC || segmentType == SEGMENT_ARC) { readSegmentWkt(SEGMENT_ARC, false); - } - else if (segmentType == SEGMENT_FIRST_LINE | segmentType == SEGMENT_LINE) { + } else if (segmentType == SEGMENT_FIRST_LINE | segmentType == SEGMENT_LINE) { readSegmentWkt(SEGMENT_LINE, false); } } } /** - * Reads a CompoundCurve WKT + * Reads a CompoundCurve WKT. * * @param isFirstIteration - * flag that indicates if this is the first iteration from the loop outside + * flag that indicates if this is the first iteration from the loop outside * @throws SQLServerException - * if an exception occurs + * if an exception occurs */ protected void readCompoundCurveWkt(boolean isFirstIteration) throws SQLServerException { while (currentWktPos < wkt.length() && wkt.charAt(currentWktPos) != ')') { @@ -1045,34 +1107,29 @@ protected void readCompoundCurveWkt(boolean isFirstIteration) throws SQLServerEx readOpenBracket(); readSegmentWkt(SEGMENT_FIRST_ARC, isFirstIteration); readCloseBracket(); - } - else if (wkt.charAt(currentWktPos) == '(') {// LineString + } else if (wkt.charAt(currentWktPos) == '(') {// LineString readOpenBracket(); readSegmentWkt(SEGMENT_FIRST_LINE, isFirstIteration); readCloseBracket(); - } - else { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_illegalWKTposition")); - throw new SQLServerException(form.format(new Object[] {currentWktPos}), null, 0, null); + } else { + throwIllegalWKTPosition(); } isFirstIteration = false; - if (wkt.charAt(currentWktPos) == ',') { // more polygons to follow + if (checkSQLLength(currentWktPos + 1) && wkt.charAt(currentWktPos) == ',') { // more polygons to follow readComma(); - } - else if (wkt.charAt(currentWktPos) == ')') { // about to exit while loop + } else if (wkt.charAt(currentWktPos) == ')') { // about to exit while loop continue; - } - else { // unexpected input - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_illegalWKTposition")); - throw new SQLServerException(form.format(new Object[] {currentWktPos}), null, 0, null); + } else { // unexpected input + throwIllegalWKTPosition(); } } } /** - * Reads the next string token (usually POINT, LINESTRING, etc.). Then increments currentWktPos to the end of the string token. + * Reads the next string token (usually POINT, LINESTRING, etc.). Then increments currentWktPos to the end of the + * string token. * * @return the next string token */ @@ -1090,15 +1147,16 @@ protected String getNextStringToken() { } /** - * Populates the various data structures contained within the Geometry/Geography instace. + * Populates the various data structures contained within the Geometry/Geography instance. */ protected void populateStructures() { if (pointList.size() > 0) { - points = new double[pointList.size() * 2]; + xValues = new double[pointList.size()]; + yValues = new double[pointList.size()]; for (int i = 0; i < pointList.size(); i++) { - points[i * 2] = pointList.get(i).getX(); - points[i * 2 + 1] = pointList.get(i).getY(); + xValues[i] = pointList.get(i).getX(); + yValues[i] = pointList.get(i).getY(); } if (hasZvalues) { @@ -1134,7 +1192,8 @@ protected void populateStructures() { } // There is an edge case of empty GeometryCollections being inside other GeometryCollections. In this case, - // the figure offset of the very first shape (GeometryCollections) has to be -1, but this is not possible to know until + // the figure offset of the very first shape (GeometryCollections) has to be -1, but this is not possible to + // know until // We've parsed through the entire WKT and confirmed that there are 0 points. // Therefore, if so, we make the figure offset of the first shape to be -1. if (pointList.size() == 0 && shapeList.size() > 0 && shapeList.get(0).getOpenGISType() == 7) { @@ -1168,10 +1227,8 @@ protected void readOpenBracket() throws SQLServerException { if (wkt.charAt(currentWktPos) == '(') { currentWktPos++; skipWhiteSpaces(); - } - else { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_illegalWKTposition")); - throw new SQLServerException(form.format(new Object[] {currentWktPos}), null, 0, null); + } else { + throwIllegalWKTPosition(); } } @@ -1180,10 +1237,8 @@ protected void readCloseBracket() throws SQLServerException { if (wkt.charAt(currentWktPos) == ')') { currentWktPos++; skipWhiteSpaces(); - } - else { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_illegalWKTposition")); - throw new SQLServerException(form.format(new Object[] {currentWktPos}), null, 0, null); + } else { + throwIllegalWKTPosition(); } } @@ -1266,7 +1321,7 @@ protected int determineWkbCapacity() { * Append the data to both stringbuffers. * * @param o - * data to append to the stringbuffers. + * data to append to the stringbuffers. */ protected void appendToWKTBuffers(Object o) { WKTsb.append(o); @@ -1282,73 +1337,75 @@ protected void interpretSerializationPropBytes() { isLargerThanHemisphere = (serializationProperties & isLargerThanHemisphereMask) != 0; } - protected void readNumberOfPoints() { + protected void readNumberOfPoints() throws SQLServerException { if (isSinglePoint) { numberOfPoints = 1; - } - else if (isSingleLineSegment) { + } else if (isSingleLineSegment) { numberOfPoints = 2; - } - else { - numberOfPoints = buffer.getInt(); + } else { + numberOfPoints = readInt(); + checkNegSize(numberOfPoints); } } - protected void readZvalues() { + protected void readZvalues() throws SQLServerException { zValues = new double[numberOfPoints]; for (int i = 0; i < numberOfPoints; i++) { - zValues[i] = buffer.getDouble(); + zValues[i] = readDouble(); } } - protected void readMvalues() { + protected void readMvalues() throws SQLServerException { mValues = new double[numberOfPoints]; for (int i = 0; i < numberOfPoints; i++) { - mValues[i] = buffer.getDouble(); + mValues[i] = readDouble(); } } - protected void readNumberOfFigures() { - numberOfFigures = buffer.getInt(); + protected void readNumberOfFigures() throws SQLServerException { + numberOfFigures = readInt(); + checkNegSize(numberOfFigures); } - protected void readFigures() { + protected void readFigures() throws SQLServerException { byte fa; int po; figures = new Figure[numberOfFigures]; for (int i = 0; i < numberOfFigures; i++) { - fa = buffer.get(); - po = buffer.getInt(); + fa = readByte(); + po = readInt(); figures[i] = new Figure(fa, po); } } - protected void readNumberOfShapes() { - numberOfShapes = buffer.getInt(); + protected void readNumberOfShapes() throws SQLServerException { + numberOfShapes = readInt(); + checkNegSize(numberOfShapes); } - protected void readShapes() { + protected void readShapes() throws SQLServerException { int po; int fo; byte ogt; shapes = new Shape[numberOfShapes]; for (int i = 0; i < numberOfShapes; i++) { - po = buffer.getInt(); - fo = buffer.getInt(); - ogt = buffer.get(); + po = readInt(); + fo = readInt(); + ogt = readByte(); shapes[i] = new Shape(po, fo, ogt); } } - protected void readNumberOfSegments() { - numberOfSegments = buffer.getInt(); + protected void readNumberOfSegments() throws SQLServerException { + numberOfSegments = readInt(); + checkNegSize(numberOfSegments); } - protected void readSegments() { + protected void readSegments() throws SQLServerException { byte st; segments = new Segment[numberOfSegments]; for (int i = 0; i < numberOfSegments; i++) { - st = buffer.get(); + st = readByte(); segments[i] = new Segment(st); } } @@ -1356,17 +1413,14 @@ protected void readSegments() { protected void determineInternalType() { if (isSinglePoint) { internalType = InternalSpatialDatatype.POINT; - } - else if (isSingleLineSegment) { + } else if (isSingleLineSegment) { internalType = InternalSpatialDatatype.LINESTRING; - } - else { + } else { internalType = InternalSpatialDatatype.valueOf(shapes[0].getOpenGISType()); } } - protected boolean checkEmptyKeyword(int parentShapeIndex, - InternalSpatialDatatype isd, + protected boolean checkEmptyKeyword(int parentShapeIndex, InternalSpatialDatatype isd, boolean isInsideAnotherShape) throws SQLServerException { String potentialEmptyKeyword = getNextStringToken().toUpperCase(Locale.US); if (potentialEmptyKeyword.equals("EMPTY")) { @@ -1377,22 +1431,17 @@ protected boolean checkEmptyKeyword(int parentShapeIndex, byte parentTypeCode = isd.getTypeCode(); if (parentTypeCode == 4) { // MultiPoint typeCode = InternalSpatialDatatype.POINT.getTypeCode(); - } - else if (parentTypeCode == 5) { // MultiLineString + } else if (parentTypeCode == 5) { // MultiLineString typeCode = InternalSpatialDatatype.LINESTRING.getTypeCode(); - } - else if (parentTypeCode == 6) { // MultiPolygon + } else if (parentTypeCode == 6) { // MultiPolygon typeCode = InternalSpatialDatatype.POLYGON.getTypeCode(); - } - else if (parentTypeCode == 7) { // GeometryCollection + } else if (parentTypeCode == 7) { // GeometryCollection typeCode = InternalSpatialDatatype.GEOMETRYCOLLECTION.getTypeCode(); - } - else { + } else { String strError = SQLServerException.getErrString("R_illegalWKT"); throw new SQLServerException(strError, null, 0, null); } - } - else { + } else { typeCode = isd.getTypeCode(); } @@ -1406,12 +1455,22 @@ else if (parentTypeCode == 7) { // GeometryCollection } if (!potentialEmptyKeyword.equals("")) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_illegalWKTposition")); - throw new SQLServerException(form.format(new Object[] {currentWktPos}), null, 0, null); + throwIllegalWKTPosition(); } return false; } + protected void throwIllegalWKT() throws SQLServerException { + String strError = SQLServerException.getErrString("R_illegalWKT"); + throw new SQLServerException(strError, null, 0, null); + } + + protected void throwIllegalWKB() throws SQLServerException { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_ParsingError")); + Object[] msgArgs = {JDBCType.VARBINARY}; + throw new SQLServerException(this, form.format(msgArgs), null, 0, false); + } + private void incrementPointNumStartIfPointNotReused(int pointEndIndex) { // We need to increment PointNumStart if the last point was actually not re-used in the points array. // 0 for pointNumEnd indicates that this check is not applicable. @@ -1424,9 +1483,9 @@ private void incrementPointNumStartIfPointNotReused(int pointEndIndex) { * Helper used for resurcive iteration for constructing GeometryCollection in WKT form. * * @param shapeEndIndex - * . + * . * @throws SQLServerException - * if an exception occurs + * if an exception occurs */ private void constructGeometryCollectionWKThelper(int shapeEndIndex) throws SQLServerException { // phase 1: assume that there is no multi - stuff and no geometrycollection @@ -1477,12 +1536,12 @@ private void constructGeometryCollectionWKThelper(int shapeEndIndex) throws SQLS int pointOffsetEnd; if (i == figures.length - 1) { pointOffsetEnd = numberOfPoints; - } - else { + } else { pointOffsetEnd = figures[i + 1].getPointOffset(); } - int increment = calculateSegmentIncrement(localCurrentSegmentIndex, pointOffsetEnd - figures[i].getPointOffset()); + int increment = calculateSegmentIncrement(localCurrentSegmentIndex, + pointOffsetEnd - figures[i].getPointOffset()); segmentIndexIncrement = segmentIndexIncrement + increment; localCurrentSegmentIndex = localCurrentSegmentIndex + increment; @@ -1509,8 +1568,10 @@ private void constructGeometryCollectionWKThelper(int shapeEndIndex) throws SQLS // Increment shapeStartIndex to account for the shape index that either Multipoint, MultiLineString // or MultiPolygon takes up tempShapeIndex++; - while (tempShapeIndex < shapes.length && shapes[tempShapeIndex].getParentOffset() != thisShapesParentOffset) { - if (!(tempShapeIndex == shapes.length - 1) && // last iteration, don't check for shapes[tempShapeIndex + 1] + while (tempShapeIndex < shapes.length + && shapes[tempShapeIndex].getParentOffset() != thisShapesParentOffset) { + if (!(tempShapeIndex == shapes.length - 1) && // last iteration, don't check for + // shapes[tempShapeIndex + 1] !(shapes[tempShapeIndex + 1].getFigureOffset() == -1)) { // disregard EMPTY cases figureIndexEnd = shapes[tempShapeIndex + 1].getFigureOffset(); } @@ -1554,8 +1615,7 @@ private void constructGeometryCollectionWKThelper(int shapeEndIndex) throws SQLS if (currentShapeIndex < shapeEndIndex) { appendToWKTBuffers("), "); - } - else { + } else { appendToWKTBuffers(")"); } @@ -1563,12 +1623,12 @@ private void constructGeometryCollectionWKThelper(int shapeEndIndex) throws SQLS case COMPOUNDCURVE: if (currentFigureIndex == figures.length - 1) { pointIndexEnd = numberOfPoints; - } - else { + } else { pointIndexEnd = figures[currentFigureIndex + 1].getPointOffset(); } - int increment = calculateSegmentIncrement(currentSegmentIndex, pointIndexEnd - figures[currentFigureIndex].getPointOffset()); + int increment = calculateSegmentIncrement(currentSegmentIndex, + pointIndexEnd - figures[currentFigureIndex].getPointOffset()); segmentIndexIncrement = increment; segmentIndexEnd = currentSegmentIndex + increment; @@ -1594,17 +1654,17 @@ private void constructGeometryCollectionWKThelper(int shapeEndIndex) throws SQLS } /** - * Calculates how many segments will be used by this shape. Needed to determine when the shape that uses segments (e.g. CompoundCurve) needs to - * stop reading in cases where the CompoundCurve is included as part of GeometryCollection. + * Calculates how many segments will be used by this shape. Needed to determine when the shape that uses segments + * (e.g. CompoundCurve) needs to stop reading in cases where the CompoundCurve is included as part of + * GeometryCollection. * * @param segmentStart - * . + * . * @param pointDifference - * number of points that were assigned to this segment to be used. + * number of points that were assigned to this segment to be used. * @return the number of segments that will be used by this shape. */ - private int calculateSegmentIncrement(int segmentStart, - int pointDifference) { + private int calculateSegmentIncrement(int segmentStart, int pointDifference) { int segmentIncrement = 0; @@ -1615,8 +1675,7 @@ private int calculateSegmentIncrement(int segmentStart, if (segmentStart == segments.length - 1 || pointDifference < 1) { // last segment break; - } - else if (segments[segmentStart + 1].getSegmentType() != 0) { // one point will be reused + } else if (segments[segmentStart + 1].getSegmentType() != 0) { // one point will be reused pointDifference = pointDifference + 1; } break; @@ -1625,8 +1684,7 @@ else if (segments[segmentStart + 1].getSegmentType() != 0) { // one point will b if (segmentStart == segments.length - 1 || pointDifference < 1) { // last segment break; - } - else if (segments[segmentStart + 1].getSegmentType() != 1) { // one point will be reused + } else if (segments[segmentStart + 1].getSegmentType() != 1) { // one point will be reused pointDifference = pointDifference + 1; } break; @@ -1635,8 +1693,7 @@ else if (segments[segmentStart + 1].getSegmentType() != 1) { // one point will b if (segmentStart == segments.length - 1 || pointDifference < 1) { // last segment break; - } - else if (segments[segmentStart + 1].getSegmentType() != 0) { // one point will be reused + } else if (segments[segmentStart + 1].getSegmentType() != 0) { // one point will be reused pointDifference = pointDifference + 1; } break; @@ -1645,8 +1702,7 @@ else if (segments[segmentStart + 1].getSegmentType() != 0) { // one point will b if (segmentStart == segments.length - 1 || pointDifference < 1) { // last segment break; - } - else if (segments[segmentStart + 1].getSegmentType() != 1) { // one point will be reused + } else if (segments[segmentStart + 1].getSegmentType() != 1) { // one point will be reused pointDifference = pointDifference + 1; } break; @@ -1672,8 +1728,9 @@ private void skipFirstPointWkt() { break; } - while (currentWktPos < wkt.length() && (Character.isDigit(wkt.charAt(currentWktPos)) || wkt.charAt(currentWktPos) == '.' - || wkt.charAt(currentWktPos) == 'E' || wkt.charAt(currentWktPos) == 'e')) { + while (currentWktPos < wkt.length() + && (Character.isDigit(wkt.charAt(currentWktPos)) || wkt.charAt(currentWktPos) == '.' + || wkt.charAt(currentWktPos) == 'E' || wkt.charAt(currentWktPos) == 'e')) { currentWktPos++; } @@ -1695,10 +1752,8 @@ private void readComma() throws SQLServerException { if (wkt.charAt(currentWktPos) == ',') { currentWktPos++; skipWhiteSpaces(); - } - else { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_illegalWKTposition")); - throw new SQLServerException(form.format(new Object[] {currentWktPos}), null, 0, null); + } else { + throwIllegalWKTPosition(); } } @@ -1707,37 +1762,110 @@ private void skipWhiteSpaces() { currentWktPos++; } } + + private void checkNegSize(int num) throws SQLServerException { + if (num < 0) { + throwIllegalWKB(); + } + } + + private void readPoints(SQLServerSpatialDatatype type) throws SQLServerException { + xValues = new double[numberOfPoints]; + yValues = new double[numberOfPoints]; + + if (type instanceof Geometry) { + for (int i = 0; i < numberOfPoints; i++) { + xValues[i] = readDouble(); + yValues[i] = readDouble(); + } + } else { // Geography + for (int i = 0; i < numberOfPoints; i++) { + yValues[i] = readDouble(); + xValues[i] = readDouble(); + } + } + } + + private void checkBuffer(int i) throws SQLServerException { + if (buffer.remaining() < i) { + throwIllegalWKB(); + } + } + + private boolean checkSQLLength(int length) throws SQLServerException { + if (null == wkt || wkt.length() < length) { + throwIllegalWKTPosition(); + } + return true; + } + + private void throwIllegalWKTPosition() throws SQLServerException { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_illegalWKTposition")); + throw new SQLServerException(form.format(new Object[] {currentWktPos}), null, 0, null); + } + + protected byte readByte() throws SQLServerException { + checkBuffer(1); + return buffer.get(); + } + + protected int readInt() throws SQLServerException { + checkBuffer(4); + return buffer.getInt(); + } + + protected double readDouble() throws SQLServerException { + checkBuffer(8); + return buffer.getDouble(); + } } + /** - * Class to hold and represent the internal makings of a Figure. + * Represents the internal makings of a Figure. * */ class Figure { private byte figuresAttribute; private int pointOffset; - Figure(byte figuresAttribute, - int pointOffset) { + Figure(byte figuresAttribute, int pointOffset) { this.figuresAttribute = figuresAttribute; this.pointOffset = pointOffset; } + /** + * Returns the figuresAttribute value. + * + * @return byte figuresAttribute value. + */ public byte getFiguresAttribute() { return figuresAttribute; } + /** + * Returns the pointOffset value. + * + * @return int pointOffset value. + */ public int getPointOffset() { return pointOffset; } + /** + * Sets the figuresAttribute value. + * + * @param fa + * figuresAttribute value. + */ public void setFiguresAttribute(byte fa) { figuresAttribute = fa; } } + /** - * Class to hold and represent the internal makings of a Shape. + * Represents the internal makings of a Shape. * */ class Shape { @@ -1745,34 +1873,54 @@ class Shape { private int figureOffset; private byte openGISType; - Shape(int parentOffset, - int figureOffset, - byte openGISType) { + Shape(int parentOffset, int figureOffset, byte openGISType) { this.parentOffset = parentOffset; this.figureOffset = figureOffset; this.openGISType = openGISType; } + /** + * Returns the parentOffset value. + * + * @return int parentOffset value. + */ public int getParentOffset() { return parentOffset; } + /** + * Returns the figureOffset value. + * + * @return int figureOffset value. + */ public int getFigureOffset() { return figureOffset; } + /** + * Returns the openGISType value. + * + * @return byte openGISType value. + */ public byte getOpenGISType() { return openGISType; } + /** + * Sets the figureOffset value. + * + * @param fo + * figureOffset value. + */ public void setFigureOffset(int fo) { figureOffset = fo; } } + /** - * Class to hold and represent the internal makings of a Segment. + * Represents the internal makings of a Segment. * */ class Segment { @@ -1782,13 +1930,19 @@ class Segment { this.segmentType = segmentType; } + /** + * Returns the segmentType value. + * + * @return byte segmentType value. + */ public byte getSegmentType() { return segmentType; } } + /** - * Class to hold and represent the internal makings of a Point. + * Represents the internal makings of a Point. * */ class Point { @@ -1797,29 +1951,46 @@ class Point { private final double z; private final double m; - Point(double x, - double y, - double z, - double m) { + Point(double x, double y, double z, double m) { this.x = x; this.y = y; this.z = z; this.m = m; } + /** + * Returns the x coordinate value. + * + * @return double x coordinate value. + */ public double getX() { return x; } + /** + * Returns the y coordinate value. + * + * @return double y coordinate value. + */ public double getY() { return y; } + /** + * Returns the z (elevation) value. + * + * @return double z value. + */ public double getZ() { return z; } + /** + * Returns the m (measure) value. + * + * @return double m value. + */ public double getM() { return m; } -} \ No newline at end of file +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerStatement.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerStatement.java index cd56a7b84..59fa8482b 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerStatement.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerStatement.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -14,9 +11,9 @@ import java.sql.BatchUpdateException; import java.sql.ResultSet; import java.sql.SQLException; +import java.sql.SQLTimeoutException; import java.sql.SQLWarning; import java.sql.Statement; -import java.sql.SQLTimeoutException; import java.text.MessageFormat; import java.util.ArrayList; import java.util.ListIterator; @@ -28,27 +25,30 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import com.microsoft.sqlserver.jdbc.SQLServerConnection.Sha1HashKey; +import com.microsoft.sqlserver.jdbc.SQLServerConnection.CityHash128Key; + /** - * SQLServerStatment provides the basic implementation of JDBC statement functionality. It also provides a number of base class implementation methods - * for the JDBC prepared statement and callable Statements. SQLServerStatement's basic role is to execute SQL statements and return update counts and - * resultset rows to the user application. + * Provides an implementation of java.sql.Statement JDBC Interface to assist in creating Statements against SQL Server. + * It also provides a number of base class implementation methods for the JDBC prepared statement and callable + * Statements. SQLServerStatement's basic role is to execute SQL statements and return update counts and resultset rows + * to the user application. * - * Documentation for specific public methods that are undocumented can be found under Sun's standard JDBC documentation for class java.sql.Statement. - * Those methods are part of Sun's standard JDBC documentation and therefore their documentation is not duplicated here. + * Documentation for specific public methods that are undocumented can be found under Sun's standard JDBC documentation + * for class java.sql.Statement. Those methods are part of Sun's standard JDBC documentation and therefore their + * documentation is not duplicated here. *

* Implementation Notes *

* Fetching Result sets *

- * The queries first rowset is available immediately after the executeQuery. The first rs.next() does not make a server round trip. For non server - * side resultsets the entire result set is in the rowset. For server side result sets the number of rows in the rowset is set with nFetchSize + * The queries first rowset is available immediately after the executeQuery. The first rs.next() does not make a server + * round trip. For non server side resultsets the entire result set is in the rowset. For server side result sets the + * number of rows in the rowset is set with nFetchSize *

- * The API javadoc for JDBC API methods that this class implements are not repeated here. Please see Sun's JDBC API interfaces javadoc for those - * details. + * The API javadoc for JDBC API methods that this class implements are not repeated here. Please see Sun's JDBC API + * interfaces javadoc for those details. */ - public class SQLServerStatement implements ISQLServerStatement { final static char LEFT_CURLY_BRACKET = 123; final static char RIGHT_CURLY_BRACKET = 125; @@ -103,7 +103,7 @@ final boolean wasExecuted() { Parameter[] inOutParam; // Parameters for prepared stmts and stored procedures /** - * The statements connection. + * The statement's connection. */ final SQLServerConnection connection; @@ -116,18 +116,19 @@ final boolean wasExecuted() { * timeout value for canceling the query timeout */ int cancelQueryTimeoutSeconds; - + /** - * Is closeOnCompletion is enabled? If true statement will be closed when all of its dependent result sets are closed + * Is closeOnCompletion is enabled? If true statement will be closed when all of its dependent result sets are + * closed */ boolean isCloseOnCompletion = false; /** - * Currently executing or most recently executed TDSCommand (statement cmd, server cursor cmd, ...) subject to cancellation through - * Statement.cancel. + * Currently executing or most recently executed TDSCommand (statement cmd, server cursor cmd, ...) subject to + * cancellation through Statement.cancel. * - * Note: currentCommand is declared volatile to ensure that the JVM always returns the most recently set value for currentCommand to the - * cancelling thread. + * Note: currentCommand is declared volatile to ensure that the JVM always returns the most recently set value for + * currentCommand to the cancelling thread. */ private volatile TDSCommand currentCommand = null; private TDSCommand lastStmtExecCmd = null; @@ -140,7 +141,8 @@ final void discardLastExecutionResults() { clearLastResult(); } - static final java.util.logging.Logger loggerExternal = java.util.logging.Logger.getLogger("com.microsoft.sqlserver.jdbc.Statement"); + static final java.util.logging.Logger loggerExternal = java.util.logging.Logger + .getLogger("com.microsoft.sqlserver.jdbc.Statement"); final private String loggingClassName; final private String traceID; @@ -149,16 +151,18 @@ String getClassNameLogging() { } /* - * Column Encryption Override. Defaults to the connection setting, in which case it will be Enabled if columnEncryptionSetting = true in the - * connection setting, Disabled if false. This may also be used to set other behavior which overrides connection level setting. + * Column Encryption Override. Defaults to the connection setting, in which case it will be Enabled if + * columnEncryptionSetting = true in the connection setting, Disabled if false. This may also be used to set other + * behavior which overrides connection level setting. */ protected SQLServerStatementColumnEncryptionSetting stmtColumnEncriptionSetting = SQLServerStatementColumnEncryptionSetting.UseConnectionSetting; protected SQLServerStatementColumnEncryptionSetting getStmtColumnEncriptionSetting() { return stmtColumnEncriptionSetting; } + /** - * ExecuteProperties encapsulates a subset of statement property values as they were set at execution time. + * Encapsulates a subset of statement property values as they were set at execution time. */ final class ExecuteProperties { final private boolean wasResponseBufferingSet; @@ -195,7 +199,8 @@ final ExecuteProperties getExecProps() { /** * Executes this Statement using TDSCommand newStmtCmd. * - * The TDSCommand is assumed to be a statement execution command (StmtExecCmd, PrepStmtExecCmd, PrepStmtBatchExecCmd). + * The TDSCommand is assumed to be a statement execution command (StmtExecCmd, PrepStmtExecCmd, + * PrepStmtBatchExecCmd). */ final void executeStatement(TDSCommand newStmtCmd) throws SQLServerException, SQLTimeoutException { // Ensure that any response left over from a previous execution has been @@ -212,26 +217,26 @@ final void executeStatement(TDSCommand newStmtCmd) throws SQLServerException, SQ // (Re)execute this Statement with the new command executeCommand(newStmtCmd); } catch (SQLServerException e) { - if (e.getDriverErrorCode() == SQLServerException.ERROR_QUERY_TIMEOUT) - throw new SQLTimeoutException(e.getMessage(), e.getSQLState(), e.getErrorCode(), e.getCause()); - else - throw e; - } - finally { + if (e.getDriverErrorCode() == SQLServerException.ERROR_QUERY_TIMEOUT) + throw new SQLTimeoutException(e.getMessage(), e.getSQLState(), e.getErrorCode(), e.getCause()); + else + throw e; + } finally { lastStmtExecCmd = newStmtCmd; } } /** - * Executes TDSCommand newCommand through this Statement object, allowing it to be cancelled through Statement.cancel(). + * Executes TDSCommand newCommand through this Statement object, allowing it to be cancelled through + * Statement.cancel(). * - * The specified command is typically the one used to execute the statement. But it could also be a server cursor command (fetch, move, close) - * generated by a ResultSet that this statement produced. + * The specified command is typically the one used to execute the statement. But it could also be a server cursor + * command (fetch, move, close) generated by a ResultSet that this statement produced. * - * This method does not prevent applications from simultaneously executing commands from multiple threads. The assumption is that apps only call - * cancel() from another thread while the command is executing. + * This method does not prevent applications from simultaneously executing commands from multiple threads. The + * assumption is that apps only call cancel() from another thread while the command is executing. */ - final void executeCommand(TDSCommand newCommand) throws SQLServerException{ + final void executeCommand(TDSCommand newCommand) throws SQLServerException { // Set the new command as the current command so that // its execution can be cancelled from another thread currentCommand = newCommand; @@ -239,7 +244,8 @@ final void executeCommand(TDSCommand newCommand) throws SQLServerException{ } /** - * Flag to indicate that are potentially more results (ResultSets, update counts, or errors) to be processed in the response. + * Flag to indicate that are potentially more results (ResultSets, update counts, or errors) to be processed in the + * response. */ boolean moreResults = false; @@ -261,7 +267,7 @@ synchronized void incrResultSetCount() { } /** - * decrement opened result set counter + * Decrement opened result set counter. */ synchronized void decrResultSetCount() { resultSetCount--; @@ -274,7 +280,8 @@ synchronized void decrResultSetCount() { } /** - * The statement execution method (executeQuery(), executeUpdate(), execute(), or executeBatch()) that was used to execute the statement. + * The statement execution method (executeQuery(), executeUpdate(), execute(), or executeBatch()) that was used to + * execute the statement. */ static final int EXECUTE_NOT_SET = 0; static final int EXECUTE_QUERY = 1; @@ -306,25 +313,27 @@ synchronized void decrResultSetCount() { int resultSetConcurrency; /** - * The app result set type. This is the value passed to the statement's constructor (or inferred by default) when the statement was created. - * ResultSet.getType() returns this value. It may differ from the SQL Server result set type (see below). Namely, an app result set type of - * TYPE_FORWARD_ONLY will have an SQL Server result set type of TYPE_SS_DIRECT_FORWARD_ONLY or TYPE_SS_SERVER_CURSOR_FORWARD_ONLY depending on the - * value of the selectMethod connection property. + * The app result set type. This is the value passed to the statement's constructor (or inferred by default) when + * the statement was created. ResultSet.getType() returns this value. It may differ from the SQL Server result set + * type (see below). Namely, an app result set type of TYPE_FORWARD_ONLY will have an SQL Server result set type of + * TYPE_SS_DIRECT_FORWARD_ONLY or TYPE_SS_SERVER_CURSOR_FORWARD_ONLY depending on the value of the selectMethod + * connection property. * * Possible values of the app result set type are: * - * TYPE_FORWARD_ONLY TYPE_SCROLL_INSENSITIVE TYPE_SCROLL_SENSITIVE TYPE_SS_DIRECT_FORWARD_ONLY TYPE_SS_SERVER_CURSOR_FORWARD_ONLY - * TYPE_SS_SCROLL_DYNAMIC TYPE_SS_SCROLL_KEYSET TYPE_SS_SCROLL_STATIC + * TYPE_FORWARD_ONLY TYPE_SCROLL_INSENSITIVE TYPE_SCROLL_SENSITIVE TYPE_SS_DIRECT_FORWARD_ONLY + * TYPE_SS_SERVER_CURSOR_FORWARD_ONLY TYPE_SS_SCROLL_DYNAMIC TYPE_SS_SCROLL_KEYSET TYPE_SS_SCROLL_STATIC */ int appResultSetType; /** - * The SQL Server result set type. This is the value used everywhere EXCEPT ResultSet.getType(). This value may or may not be the same as the app - * result set type (above). + * The SQL Server result set type. This is the value used everywhere EXCEPT ResultSet.getType(). This value may or + * may not be the same as the app result set type (above). * * Possible values of the SQL Server result set type are: * - * TYPE_SS_DIRECT_FORWARD_ONLY TYPE_SS_SERVER_CURSOR_FORWARD_ONLY TYPE_SS_SCROLL_DYNAMIC TYPE_SS_SCROLL_KEYSET TYPE_SS_SCROLL_STATIC + * TYPE_SS_DIRECT_FORWARD_ONLY TYPE_SS_SERVER_CURSOR_FORWARD_ONLY TYPE_SS_SCROLL_DYNAMIC TYPE_SS_SCROLL_KEYSET + * TYPE_SS_SCROLL_STATIC */ int resultSetType; @@ -337,35 +346,39 @@ final int getCursorType() { } /** - * Indicates whether to request a server cursor when executing this statement. + * Returns whether to request a server cursor when executing this statement. * - * Executing a statement with execute() or executeQuery() requests a server cursor in all scrollability and updatability combinations except - * direct forward-only, read-only. + * Executing a statement with execute() or executeQuery() requests a server cursor in all scrollability and + * updatability combinations except direct forward-only, read-only. * - * Note that when execution requests a server cursor (i.e. this method returns true), there is no guarantee that SQL Server returns one. The - * variable executedSqlDirectly indicates whether SQL Server executed the query with a cursor or not. + * Note that when execution requests a server cursor (i.e. this method returns true), there is no guarantee that SQL + * Server returns one. The variable executedSqlDirectly indicates whether SQL Server executed the query with a + * cursor or not. * * @return true if statement execution requests a server cursor, false otherwise. */ final boolean isCursorable(int executeMethod) { - return resultSetType != SQLServerResultSet.TYPE_SS_DIRECT_FORWARD_ONLY && (EXECUTE == executeMethod || EXECUTE_QUERY == executeMethod); + return resultSetType != SQLServerResultSet.TYPE_SS_DIRECT_FORWARD_ONLY + && (EXECUTE == executeMethod || EXECUTE_QUERY == executeMethod); } /** * Indicates whether SQL Server executed this statement with a cursor or not. * - * When trying to execute a cursor-unfriendly statement with a server cursor, SQL Server may choose to execute the statement directly (i.e. as if - * no server cursor had been requested) rather than fail to execute the statement at all. We need to know when this happens so that if no rows are - * returned, we can tell whether the result is an empty result set or a cursored result set with rows to be fetched later. + * When trying to execute a cursor-unfriendly statement with a server cursor, SQL Server may choose to execute the + * statement directly (i.e. as if no server cursor had been requested) rather than fail to execute the statement at + * all. We need to know when this happens so that if no rows are returned, we can tell whether the result is an + * empty result set or a cursored result set with rows to be fetched later. */ boolean executedSqlDirectly = false; /** - * Indicates whether OUT parameters (cursor ID and row count) from cursorized execution of this statement are expected in the response. + * Indicates whether OUT parameters (cursor ID and row count) from cursorized execution of this statement are + * expected in the response. * - * In most cases, except for severe errors, cursor OUT parameters are returned whenever a cursor is requested for statement execution. Even if SQL - * Server does not cursorize the statement as requested, these values are still present in the response and must be processed, even though their - * values are meaningless in that case. + * In most cases, except for severe errors, cursor OUT parameters are returned whenever a cursor is requested for + * statement execution. Even if SQL Server does not cursorize the statement as requested, these values are still + * present in the response and must be processed, even though their values are meaningless in that case. */ boolean expectCursorOutParams; @@ -381,7 +394,8 @@ boolean onRetStatus(TDSReader tdsReader) throws SQLServerException { boolean onRetValue(TDSReader tdsReader) throws SQLServerException { if (expectCursorOutParams) { - Parameter param = new Parameter(Util.shouldHonorAEForParameters(stmtColumnEncriptionSetting, connection)); + Parameter param = new Parameter( + Util.shouldHonorAEForParameters(stmtColumnEncriptionSetting, connection)); // Read the cursor ID param.skipRetValStatus(tdsReader); @@ -440,7 +454,8 @@ boolean onDone(TDSReader tdsReader) throws SQLServerException { private ResultSet autoGeneratedKeys; /** - * The array of objects in a batched call. Applicable to statements and prepared statements When the iterativeBatching property is turned on. + * The array of objects in a batched call. Applicable to statements and prepared statements When the + * iterativeBatching property is turned on. */ /** The buffer that accumulates batchable statements */ private final ArrayList batchStatementBuffer = new ArrayList<>(); @@ -449,7 +464,7 @@ boolean onDone(TDSReader tdsReader) throws SQLServerException { static final private java.util.logging.Logger stmtlogger = java.util.logging.Logger .getLogger("com.microsoft.sqlserver.jdbc.internals.SQLServerStatement"); - /** The statement's id for logging info */ + /** Returns the statement's id for logging info */ @Override public String toString() { return traceID; @@ -468,22 +483,20 @@ private static int nextStatementID() { } /** - * The regular statement constructor + * Constructs a SQLServerStatement * * @param con - * The statements connections. + * The statements connections. * @param nType - * The statement type. + * The statement type. * @param nConcur - * The statement concurrency. + * The statement concurrency. * @param stmtColEncSetting - * The statement column encryption setting. + * The statement column encryption setting. * @exception SQLServerException - * The statement could not be created. + * The statement could not be created. */ - SQLServerStatement(SQLServerConnection con, - int nType, - int nConcur, + SQLServerStatement(SQLServerConnection con, int nType, int nConcur, SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException { @@ -500,21 +513,28 @@ private static int nextStatementID() { bIsClosed = false; // Validate result set type ... - if (ResultSet.TYPE_FORWARD_ONLY != nType && ResultSet.TYPE_SCROLL_SENSITIVE != nType && ResultSet.TYPE_SCROLL_INSENSITIVE != nType - && SQLServerResultSet.TYPE_SS_DIRECT_FORWARD_ONLY != nType && SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY != nType - && SQLServerResultSet.TYPE_SS_SCROLL_DYNAMIC != nType && SQLServerResultSet.TYPE_SS_SCROLL_KEYSET != nType + if (ResultSet.TYPE_FORWARD_ONLY != nType && ResultSet.TYPE_SCROLL_SENSITIVE != nType + && ResultSet.TYPE_SCROLL_INSENSITIVE != nType && SQLServerResultSet.TYPE_SS_DIRECT_FORWARD_ONLY != nType + && SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY != nType + && SQLServerResultSet.TYPE_SS_SCROLL_DYNAMIC != nType + && SQLServerResultSet.TYPE_SS_SCROLL_KEYSET != nType && SQLServerResultSet.TYPE_SS_SCROLL_STATIC != nType) { - SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_unsupportedCursor"), null, true); + SQLServerException.makeFromDriverError(connection, this, + SQLServerException.getErrString("R_unsupportedCursor"), null, true); } // ... and concurrency - if (ResultSet.CONCUR_READ_ONLY != nConcur && ResultSet.CONCUR_UPDATABLE != nConcur && SQLServerResultSet.CONCUR_SS_SCROLL_LOCKS != nConcur - && SQLServerResultSet.CONCUR_SS_OPTIMISTIC_CC != nConcur && SQLServerResultSet.CONCUR_SS_OPTIMISTIC_CCVAL != nConcur) { - SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_unsupportedConcurrency"), null, true); + if (ResultSet.CONCUR_READ_ONLY != nConcur && ResultSet.CONCUR_UPDATABLE != nConcur + && SQLServerResultSet.CONCUR_SS_SCROLL_LOCKS != nConcur + && SQLServerResultSet.CONCUR_SS_OPTIMISTIC_CC != nConcur + && SQLServerResultSet.CONCUR_SS_OPTIMISTIC_CCVAL != nConcur) { + SQLServerException.makeFromDriverError(connection, this, + SQLServerException.getErrString("R_unsupportedConcurrency"), null, true); } if (null == stmtColEncSetting) { - SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_unsupportedStmtColEncSetting"), null, true); + SQLServerException.makeFromDriverError(connection, this, + SQLServerException.getErrString("R_unsupportedStmtColEncSetting"), null, true); } stmtColumnEncriptionSetting = stmtColEncSetting; @@ -533,31 +553,29 @@ private static int nextStatementID() { // Check selectMethod and set to TYPE_SS_DIRECT_FORWARD_ONLY or // TYPE_SS_SERVER_CURSOR_FORWARD_ONLY accordingly. String selectMethod = con.getSelectMethod(); - resultSetType = (null == selectMethod || !selectMethod.equals("cursor")) ? SQLServerResultSet.TYPE_SS_DIRECT_FORWARD_ONLY : // Default - // forward-only, - // read-only - // cursor - // type - SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY; - } - else { + resultSetType = (null == selectMethod + || !selectMethod.equals("cursor")) ? SQLServerResultSet.TYPE_SS_DIRECT_FORWARD_ONLY : // Default + // forward-only, + // read-only + // cursor + // type + SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY; + } else { resultSetType = SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY; } - } - else if (ResultSet.TYPE_SCROLL_INSENSITIVE == nType) { + } else if (ResultSet.TYPE_SCROLL_INSENSITIVE == nType) { resultSetType = SQLServerResultSet.TYPE_SS_SCROLL_STATIC; - } - else if (ResultSet.TYPE_SCROLL_SENSITIVE == nType) { + } else if (ResultSet.TYPE_SCROLL_SENSITIVE == nType) { resultSetType = SQLServerResultSet.TYPE_SS_SCROLL_KEYSET; - } - else // App specified one of the SQL Server types + } else // App specified one of the SQL Server types { resultSetType = nType; } // Figure out default fetch direction nFetchDirection = (SQLServerResultSet.TYPE_SS_DIRECT_FORWARD_ONLY == resultSetType - || SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY == resultSetType) ? ResultSet.FETCH_FORWARD : ResultSet.FETCH_UNKNOWN; + || SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY == resultSetType) ? ResultSet.FETCH_FORWARD + : ResultSet.FETCH_UNKNOWN; // Figure out fetch size: // @@ -574,10 +592,10 @@ else if (ResultSet.TYPE_SCROLL_SENSITIVE == nType) { // with all but read only concurrency. Against a Shiloh server, such // combinations cause the cursor to be silently "upgraded" to one that // works. We enforce the more restrictive behavior of the two here. - if (ResultSet.CONCUR_READ_ONLY != nConcur - && (SQLServerResultSet.TYPE_SS_DIRECT_FORWARD_ONLY == resultSetType || SQLServerResultSet.TYPE_SS_SCROLL_STATIC == resultSetType)) { - SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_unsupportedCursorAndConcurrency"), null, - true); + if (ResultSet.CONCUR_READ_ONLY != nConcur && (SQLServerResultSet.TYPE_SS_DIRECT_FORWARD_ONLY == resultSetType + || SQLServerResultSet.TYPE_SS_SCROLL_STATIC == resultSetType)) { + SQLServerException.makeFromDriverError(connection, this, + SQLServerException.getErrString("R_unsupportedCursorAndConcurrency"), null, true); } // All result set types other than firehose (SQL Server default) use server side cursors. @@ -587,9 +605,9 @@ else if (ResultSet.TYPE_SCROLL_SENSITIVE == nType) { setDefaultQueryCancelTimeout(); if (stmtlogger.isLoggable(java.util.logging.Level.FINER)) { - stmtlogger.finer("Properties for " + toString() + ":" + " Result type:" + appResultSetType + " (" + resultSetType + ")" + " Concurrency:" - + resultSetConcurrency + " Fetchsize:" + nFetchSize + " bIsClosed:" + bIsClosed + " useLastUpdateCount:" - + connection.useLastUpdateCount()); + stmtlogger.finer("Properties for " + toString() + ":" + " Result type:" + appResultSetType + " (" + + resultSetType + ")" + " Concurrency:" + resultSetConcurrency + " Fetchsize:" + nFetchSize + + " bIsClosed:" + bIsClosed + " useLastUpdateCount:" + connection.useLastUpdateCount()); } if (stmtlogger.isLoggable(java.util.logging.Level.FINE)) { @@ -602,9 +620,9 @@ private void setDefaultQueryCancelTimeout() { if (cancelQueryTimeoutSeconds > 0) { this.cancelQueryTimeoutSeconds = cancelQueryTimeoutSeconds; } - } + } - // add query timeout to statement + // add query timeout to statement private void setDefaultQueryTimeout() { int queryTimeoutSeconds = this.connection.getQueryTimeoutSeconds(); if (queryTimeoutSeconds > 0) { @@ -615,13 +633,14 @@ private void setDefaultQueryTimeout() { final java.util.logging.Logger getStatementLogger() { return stmtlogger; } - + /** - * Close the statement. + * Closes the statement. * - * Note that the public close() method performs all of the cleanup work through this internal method which cannot throw any exceptions. This is - * done deliberately to ensure that ALL of the object's client-side and server-side state is cleaned up as best as possible, even under conditions - * which would normally result in exceptions being thrown. + * Note that the public close() method performs all of the cleanup work through this internal method which cannot + * throw any exceptions. This is done deliberately to ensure that ALL of the object's client-side and server-side + * state is cleaned up as best as possible, even under conditions which would normally result in exceptions being + * thrown. */ void closeInternal() { // Regardless what happens when cleaning up, @@ -666,7 +685,7 @@ public java.sql.ResultSet executeQuery(String sql) throws SQLServerException, SQ loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString()); } checkClosed(); - executeStatement(new StmtExecCmd(this, sql, EXECUTE_QUERY, NO_GENERATED_KEYS)); + executeStatement(new StmtExecCmd(this, sql, EXECUTE_QUERY, NO_GENERATED_KEYS)); loggerExternal.exiting(getClassNameLogging(), "executeQuery", resultSet); return resultSet; } @@ -688,7 +707,8 @@ public int executeUpdate(String sql) throws SQLServerException, SQLTimeoutExcept // this shouldn't happen, caller probably meant to call executeLargeUpdate if (updateCount < Integer.MIN_VALUE || updateCount > Integer.MAX_VALUE) - SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_updateCountOutofRange"), null, true); + SQLServerException.makeFromDriverError(connection, this, + SQLServerException.getErrString("R_updateCountOutofRange"), null, true); loggerExternal.exiting(getClassNameLogging(), "executeUpdate", updateCount); @@ -727,10 +747,7 @@ private final class StmtExecCmd extends TDSCommand { final int executeMethod; final int autoGeneratedKeys; - StmtExecCmd(SQLServerStatement stmt, - String sql, - int executeMethod, - int autoGeneratedKeys) { + StmtExecCmd(SQLServerStatement stmt, String sql, int executeMethod, int autoGeneratedKeys) { super(stmt.toString() + " executeXXX", stmt.queryTimeout, stmt.cancelQueryTimeoutSeconds); this.stmt = stmt; this.sql = sql; @@ -752,7 +769,7 @@ final void processResponse(TDSReader tdsReader) throws SQLServerException { private String ensureSQLSyntax(String sql) throws SQLServerException { if (sql.indexOf(LEFT_CURLY_BRACKET) >= 0) { - Sha1HashKey cacheKey = new Sha1HashKey(sql); + CityHash128Key cacheKey = new CityHash128Key(sql); // Check for cached SQL metadata. ParsedSQLCacheItem cacheItem = getCachedParsedSQL(cacheKey); @@ -775,9 +792,9 @@ final void setMaxRowsAndMaxFieldSize() throws SQLServerException { if (EXECUTE_QUERY == executeMethod || EXECUTE == executeMethod) { connection.setMaxRows(maxRows); connection.setMaxFieldSize(maxFieldSize); - } - else { - assert EXECUTE_UPDATE == executeMethod || EXECUTE_BATCH == executeMethod || EXECUTE_QUERY_INTERNAL == executeMethod; + } else { + assert EXECUTE_UPDATE == executeMethod || EXECUTE_BATCH == executeMethod + || EXECUTE_QUERY_INTERNAL == executeMethod; // If we are executing via any of the above methods then make sure any // previous maxRows limitation on the connection is removed. @@ -816,8 +833,7 @@ final void doExecuteStatement(StmtExecCmd execCmd) throws SQLServerException { stmtlogger.fine(toString() + " Executing server side cursor " + sql); doExecuteCursored(execCmd, sql); - } - else // Non-cursored execution (includes EXECUTE_QUERY_INTERNAL) + } else // Non-cursored execution (includes EXECUTE_QUERY_INTERNAL) { executedSqlDirectly = true; expectCursorOutParams = false; @@ -828,7 +844,8 @@ final void doExecuteStatement(StmtExecCmd execCmd) throws SQLServerException { // If this is an INSERT statement and generated keys were requested // then add on the query to return them. - if (RETURN_GENERATED_KEYS == execCmd.autoGeneratedKeys && (EXECUTE_UPDATE == executeMethod || EXECUTE == executeMethod) + if (RETURN_GENERATED_KEYS == execCmd.autoGeneratedKeys + && (EXECUTE_UPDATE == executeMethod || EXECUTE == executeMethod) && sql.trim().toUpperCase().startsWith("INSERT")) { tdsWriter.writeString(identityQuery); } @@ -845,15 +862,16 @@ final void doExecuteStatement(StmtExecCmd execCmd) throws SQLServerException { // If execution produced no result set, then throw an exception if executeQuery() was used. if (null == resultSet) { if (EXECUTE_QUERY == executeMethod) { - SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_noResultset"), null, true); + SQLServerException.makeFromDriverError(connection, this, + SQLServerException.getErrString("R_noResultset"), null, true); } } // Otherwise, if execution produced a result set, then throw an exception // if executeUpdate() or executeBatch() was used. else { if (EXECUTE_UPDATE == executeMethod || EXECUTE_BATCH == executeMethod) { - SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_resultsetGeneratedForUpdate"), null, - false); + SQLServerException.makeFromDriverError(connection, this, + SQLServerException.getErrString("R_resultsetGeneratedForUpdate"), null, false); } } } @@ -909,12 +927,13 @@ private void doExecuteStatementBatch(StmtBatchExecCmd execCmd) throws SQLServerE // If execution produced a result set, then throw an exception if (null != resultSet) { - SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_resultsetGeneratedForUpdate"), null, false); + SQLServerException.makeFromDriverError(connection, this, + SQLServerException.getErrString("R_resultsetGeneratedForUpdate"), null, false); } } /** - * Reset the state to get the statement for reexecute callable statement overrides this. + * Resets the state to get the statement for reexecute callable statement overrides this. */ final void resetForReexecute() throws SQLServerException { ensureExecuteResultsReader(null); @@ -926,10 +945,10 @@ final void resetForReexecute() throws SQLServerException { } /** - * Determine if the SQL is a SELECT. + * Determines if the SQL is a SELECT. * * @param sql - * The statment SQL. + * The statment SQL. * @return True if the statement is a select. */ final boolean isSelect(String sql) throws SQLServerException { @@ -942,15 +961,15 @@ final boolean isSelect(String sql) throws SQLServerException { } return temp.substring(0, 6).equalsIgnoreCase("select"); } - + /** * Determine if the SQL is a INSERT. * * @param sql - * The statment SQL. + * The statment SQL. * @return True if the statement is an insert. */ - /* L0 */ final boolean isInsert(String sql) throws SQLServerException { + final boolean isInsert(String sql) throws SQLServerException { checkClosed(); // Used to check just the first letter which would cause // "Set" commands to return true... @@ -966,19 +985,17 @@ final boolean isSelect(String sql) throws SQLServerException { } /** - * Replace a JDBC parameter marker with the parameter's string value + * Replaces a JDBC parameter marker with the parameter's string value * * @param str - * the parameter syntax + * the parameter syntax * @param marker - * the parameter marker + * the parameter marker * @param replaceStr - * the param value + * the param value * @return String */ - static String replaceParameterWithString(String str, - char marker, - String replaceStr) { + static String replaceParameterWithString(String str, char marker, String replaceStr) { int index = 0; while ((index = str.indexOf("" + marker)) >= 0) { str = str.substring(0, index) + replaceStr + str.substring(index + 1, str.length()); @@ -987,18 +1004,17 @@ static String replaceParameterWithString(String str, } /** - * Set a JDBC parameter to null. (Used only when processing LOB column sources.) + * Sets a JDBC parameter to null. (Used only when processing LOB column sources.) * * @param sql - * the parameter syntax + * the parameter syntax * @return the result */ static String replaceMarkerWithNull(String sql) { if (!sql.contains("'")) { String retStr = replaceParameterWithString(sql, '?', "null"); return retStr; - } - else { + } else { StringTokenizer st = new StringTokenizer(sql, "'", true); boolean beforeColon = true; String retSql = ""; @@ -1013,8 +1029,7 @@ static String replaceMarkerWithNull(String sql) { String repStr = replaceParameterWithString(str, '?', "null"); retSql += repStr; continue; - } - else { + } else { retSql += str; continue; } @@ -1030,7 +1045,8 @@ void checkClosed() throws SQLServerException { // was closed. connection.checkClosed(); if (bIsClosed) { - SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_statementIsClosed"), null, false); + SQLServerException.makeFromDriverError(connection, this, + SQLServerException.getErrString("R_statementIsClosed"), null, false); } } @@ -1222,7 +1238,8 @@ public final int getUpdateCount() throws SQLServerException { // this shouldn't happen, caller probably meant to call getLargeUpdateCount if (updateCount < Integer.MIN_VALUE || updateCount > Integer.MAX_VALUE) - SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_updateCountOutofRange"), null, true); + SQLServerException.makeFromDriverError(connection, this, + SQLServerException.getErrString("R_updateCountOutofRange"), null, true); loggerExternal.exiting(getClassNameLogging(), "getUpdateCount", updateCount); @@ -1261,15 +1278,15 @@ final void processResults() throws SQLServerException { // Get the next result try { getNextResult(); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { // If an exception is thrown while processing the results // then decide what to do with it: if (moreResults) { // Silently discard database errors and continue processing the remaining results if (SQLServerException.DRIVER_ERROR_FROM_DATABASE == e.getDriverErrorCode()) { if (stmtlogger.isLoggable(java.util.logging.Level.FINEST)) { - stmtlogger.finest(this + " ignoring database error: " + e.getErrorCode() + " " + e.getMessage()); + stmtlogger.finest( + this + " ignoring database error: " + e.getErrorCode() + " " + e.getMessage()); } continue; @@ -1277,7 +1294,8 @@ final void processResults() throws SQLServerException { // If statement execution was canceled then continue processing the // remaining results before throwing the "statement canceled" exception. - if (e.getSQLState()!=null && e.getSQLState().equals(SQLState.STATEMENT_CANCELED.getSQLStateCode())) { + if (e.getSQLState() != null + && e.getSQLState().equals(SQLState.STATEMENT_CANCELED.getSQLStateCode())) { interruptException = e; continue; } @@ -1296,10 +1314,10 @@ final void processResults() throws SQLServerException { } /** - * Check for more results in the TDS stream + * Returns more results in the TDS stream. * - * @return true if the next result is a ResultSet object; false if it is an integer (indicating that it is an update count or there are no more - * results). + * @return true if the next result is a ResultSet object; false if it is an integer (indicating that it is an update + * count or there are no more results). */ @Override public final boolean getMoreResults() throws SQLServerException { @@ -1319,10 +1337,11 @@ public final boolean getMoreResults() throws SQLServerException { * * This method is used to clean up before moving to the next result and after processing the last result. * - * Note that errors closing the ResultSet (if the last result is a ResultSet) are caught, logged, and ignored. The reason for this is that this - * method is only for cleanup for when the app fails to do the cleanup itself (for example by leaving a ResultSet open when closing the - * statement). If the app wants to be able to handle errors from closing the current result set, then it should close that ResultSet itself before - * closing the statement, moving to the next result, or whatever. This is the recommended practice with JDBC. + * Note that errors closing the ResultSet (if the last result is a ResultSet) are caught, logged, and ignored. The + * reason for this is that this method is only for cleanup for when the app fails to do the cleanup itself (for + * example by leaving a ResultSet open when closing the statement). If the app wants to be able to handle errors + * from closing the current result set, then it should close that ResultSet itself before closing the statement, + * moving to the next result, or whatever. This is the recommended practice with JDBC. */ final void clearLastResult() { // Clear any update count result @@ -1335,18 +1354,17 @@ final void clearLastResult() { // it anyhow. try { resultSet.close(); - } - catch (SQLServerException e) { - stmtlogger.finest(this + " clearing last result; ignored error closing ResultSet: " + e.getErrorCode() + " " + e.getMessage()); - } - finally { + } catch (SQLServerException e) { + stmtlogger.finest(this + " clearing last result; ignored error closing ResultSet: " + e.getErrorCode() + + " " + e.getMessage()); + } finally { resultSet = null; } } } /** - * Get the next result in the TDS response token stream, which may be a result set, update count or exception. + * Returns the next result in the TDS response token stream, which may be a result set, update count or exception. * * @return true if another result (ResultSet or update count) was available; false if there were no more results. */ @@ -1423,8 +1441,8 @@ boolean onDone(TDSReader tdsReader) throws SQLServerException { // status (Statement.SUCCESS_NO_INFO) if (-1 == doneToken.getUpdateCount() && EXECUTE_BATCH != executeMethod) return true; - - if ( -1 != doneToken.getUpdateCount() && EXECUTE_QUERY == executeMethod ) + + if (-1 != doneToken.getUpdateCount() && EXECUTE_QUERY == executeMethod) return true; // Otherwise, the update count is valid. Now determine whether we should @@ -1521,7 +1539,8 @@ boolean onRetValue(TDSReader tdsReader) throws SQLServerException { // A RETVALUE token appearing in the execution results, but before any RETSTATUS // token, is a TEXTPTR return value that should be ignored. if (moreResults && null == procedureRetStatToken) { - Parameter p = new Parameter(Util.shouldHonorAEForParameters(stmtColumnEncriptionSetting, connection)); + Parameter p = new Parameter( + Util.shouldHonorAEForParameters(stmtColumnEncriptionSetting, connection)); p.skipRetValStatus(tdsReader); p.skipValue(tdsReader, true); return true; @@ -1549,14 +1568,14 @@ boolean onInfo(TDSReader tdsReader) throws SQLServerException { if (16954 == infoToken.msg.getErrorNumber()) executedSqlDirectly = true; - SQLWarning warning = new SQLWarning(infoToken.msg.getMessage(), - SQLServerException.generateStateCode(connection, infoToken.msg.getErrorNumber(), infoToken.msg.getErrorState()), + SQLWarning warning = new SQLWarning( + infoToken.msg.getMessage(), SQLServerException.generateStateCode(connection, + infoToken.msg.getErrorNumber(), infoToken.msg.getErrorState()), infoToken.msg.getErrorNumber()); if (sqlWarnings == null) { sqlWarnings = new Vector<>(); - } - else { + } else { int n = sqlWarnings.size(); SQLWarning w = sqlWarnings.elementAt(n - 1); w.setNextWarning(warning); @@ -1586,8 +1605,8 @@ boolean onInfo(TDSReader tdsReader) throws SQLServerException { // Check for errors first. if (null != nextResult.getDatabaseError()) { - SQLServerException.makeFromDatabaseError(connection, null, nextResult.getDatabaseError().getMessage(), nextResult.getDatabaseError(), - false); + SQLServerException.makeFromDatabaseError(connection, null, nextResult.getDatabaseError().getMessage(), + nextResult.getDatabaseError(), false); } // Not an error. Is it a result set? @@ -1627,10 +1646,10 @@ else if (nextResult.isUpdateCount()) { } /** - * Consume the OUT parameter for the statement object itself. + * Consumes the OUT parameter for the statement object itself. * - * Normal Statement objects consume the server cursor OUT params when present. PreparedStatement and CallableStatement objects override this - * method to consume the prepared statement handle as well. + * Normal Statement objects consume the server cursor OUT params when present. PreparedStatement and + * CallableStatement objects override this method to consume the prepared statement handle as well. */ boolean consumeExecOutParam(TDSReader tdsReader) throws SQLServerException { if (expectCursorOutParams) { @@ -1675,7 +1694,8 @@ public final void setFetchSize(int rows) throws SQLServerException { loggerExternal.entering(getClassNameLogging(), "setFetchSize", rows); checkClosed(); if (rows < 0) - SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_invalidFetchSize"), null, false); + SQLServerException.makeFromDriverError(connection, this, + SQLServerException.getErrString("R_invalidFetchSize"), null, false); nFetchSize = (0 == rows) ? defaultFetchSize : rows; loggerExternal.exiting(getClassNameLogging(), "setFetchSize"); @@ -1728,7 +1748,7 @@ public void clearBatch() throws SQLServerException { } /** - * Send a batch of statements to the database. + * Sends a batch of statements to the database. */ @Override public int[] executeBatch() throws SQLServerException, BatchUpdateException, SQLTimeoutException { @@ -1761,8 +1781,7 @@ public int[] executeBatch() throws SQLServerException, BatchUpdateException, SQL if (0 == batchNum) { // First time through, execute the entire set of batches and return the first result executeStatement(new StmtBatchExecCmd(this)); - } - else { + } else { // Subsequent times through, just get the result from the next batch. // If there are not enough results (update counts) to satisfy the number of batches, // then bail, leaving EXECUTE_FAILED in the remaining slots of the update count array. @@ -1772,14 +1791,13 @@ public int[] executeBatch() throws SQLServerException, BatchUpdateException, SQL } if (null != resultSet) { - SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_resultsetGeneratedForUpdate"), - null, true); - } - else { - updateCounts[batchNum] = (-1 != (int) updateCount) ? (int) updateCount : Statement.SUCCESS_NO_INFO; + SQLServerException.makeFromDriverError(connection, this, + SQLServerException.getErrString("R_resultsetGeneratedForUpdate"), null, true); + } else { + updateCounts[batchNum] = (-1 != (int) updateCount) ? (int) updateCount + : Statement.SUCCESS_NO_INFO; } - } - catch (SQLServerException e) { + } catch (SQLServerException e) { // If the failure was severe enough to close the connection or roll back a // manual transaction, then propagate the error up as a SQLServerException // now, rather than continue with the batch. @@ -1794,13 +1812,13 @@ public int[] executeBatch() throws SQLServerException, BatchUpdateException, SQL // If we had any errors then throw a BatchUpdateException with the partial results. if (null != lastError) { - throw new BatchUpdateException(lastError.getMessage(), lastError.getSQLState(), lastError.getErrorCode(), updateCounts); + throw new BatchUpdateException(lastError.getMessage(), lastError.getSQLState(), + lastError.getErrorCode(), updateCounts); } loggerExternal.exiting(getClassNameLogging(), "executeBatch", updateCounts); return updateCounts; - } - finally { + } finally { // Regardless what happens, always clear out the batch after execution. // Note: Don't use the clearBatch API as it checks that the statement is // not closed, which it might be in the event of a severe error. @@ -1840,8 +1858,7 @@ public long[] executeLargeBatch() throws SQLServerException, BatchUpdateExceptio if (0 == batchNum) { // First time through, execute the entire set of batches and return the first result executeStatement(new StmtBatchExecCmd(this)); - } - else { + } else { // Subsequent times through, just get the result from the next batch. // If there are not enough results (update counts) to satisfy the number of batches, // then bail, leaving EXECUTE_FAILED in the remaining slots of the update count array. @@ -1851,14 +1868,12 @@ public long[] executeLargeBatch() throws SQLServerException, BatchUpdateExceptio } if (null != resultSet) { - SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_resultsetGeneratedForUpdate"), - null, true); - } - else { + SQLServerException.makeFromDriverError(connection, this, + SQLServerException.getErrString("R_resultsetGeneratedForUpdate"), null, true); + } else { updateCounts[batchNum] = (-1 != updateCount) ? updateCount : Statement.SUCCESS_NO_INFO; } - } - catch (SQLServerException e) { + } catch (SQLServerException e) { // If the failure was severe enough to close the connection or roll back a // manual transaction, then propagate the error up as a SQLServerException // now, rather than continue with the batch. @@ -1878,8 +1893,7 @@ public long[] executeLargeBatch() throws SQLServerException, BatchUpdateExceptio loggerExternal.exiting(getClassNameLogging(), "executeLargeBatch", updateCounts); return updateCounts; - } - finally { + } finally { // Regardless what happens, always clear out the batch after execution. // Note: Don't use the clearBatch API as it checks that the statement is // not closed, which it might be in the event of a severe error. @@ -1888,17 +1902,18 @@ public long[] executeLargeBatch() throws SQLServerException, BatchUpdateExceptio } // executeLargeBatch /** - * Return the statement's connection + * Returns the statement's connection. * * @throws SQLServerException - * when an error occurs + * when an error occurs * @return the connection */ @Override public final java.sql.Connection getConnection() throws SQLServerException { loggerExternal.entering(getClassNameLogging(), "getConnection"); if (bIsClosed) { - SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_statementIsClosed"), null, false); + SQLServerException.makeFromDriverError(connection, this, + SQLServerException.getErrString("R_statementIsClosed"), null, false); } java.sql.Connection con = connection.getConnection(); loggerExternal.exiting(getClassNameLogging(), "getConnection", con); @@ -1907,21 +1922,13 @@ public final java.sql.Connection getConnection() throws SQLServerException { /* ----------------- Server side cursor support -------------------------- */ - /** - * Open a server side cursor. - * - * @param sql - * The SQL query. - * @exception SQLServerException - * The SQL query was invalid. - */ - final int getResultSetScrollOpt() { int scrollOpt = (null == inOutParam) ? 0 : TDS.SCROLLOPT_PARAMETERIZED_STMT; switch (resultSetType) { case SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY: - return scrollOpt | ((ResultSet.CONCUR_READ_ONLY == resultSetConcurrency) ? TDS.SCROLLOPT_FAST_FORWARD : TDS.SCROLLOPT_FORWARD_ONLY); + return scrollOpt | ((ResultSet.CONCUR_READ_ONLY == resultSetConcurrency) ? TDS.SCROLLOPT_FAST_FORWARD + : TDS.SCROLLOPT_FORWARD_ONLY); case SQLServerResultSet.TYPE_SS_SCROLL_DYNAMIC: return scrollOpt | TDS.SCROLLOPT_DYNAMIC; @@ -1959,11 +1966,10 @@ final int getResultSetCCOpt() { return 0; } - private void doExecuteCursored(StmtExecCmd execCmd, - String sql) throws SQLServerException { + private void doExecuteCursored(StmtExecCmd execCmd, String sql) throws SQLServerException { if (stmtlogger.isLoggable(java.util.logging.Level.FINER)) { - stmtlogger.finer(toString() + " Execute for cursor open" + " SQL:" + sql + " Scrollability:" + getResultSetScrollOpt() + " Concurrency:" - + getResultSetCCOpt()); + stmtlogger.finer(toString() + " Execute for cursor open" + " SQL:" + sql + " Scrollability:" + + getResultSetScrollOpt() + " Concurrency:" + getResultSetCCOpt()); } executedSqlDirectly = false; @@ -1971,8 +1977,8 @@ private void doExecuteCursored(StmtExecCmd execCmd, TDSWriter tdsWriter = execCmd.startRequest(TDS.PKT_RPC); tdsWriter.writeShort((short) 0xFFFF); // procedure name length -> use ProcIDs tdsWriter.writeShort(TDS.PROCID_SP_CURSOROPEN); - tdsWriter.writeByte((byte) 0); // RPC procedure option 1 - tdsWriter.writeByte((byte) 0); // RPC procedure option 2 + tdsWriter.writeByte((byte) 0); // RPC procedure option 1 + tdsWriter.writeByte((byte) 0); // RPC procedure option 2 // OUT tdsWriter.writeRPCInt(null, 0, true); @@ -2033,7 +2039,8 @@ public final boolean execute(java.lang.String sql, loggerExternal.entering(getClassNameLogging(), "execute", new Object[] {sql, columnIndexes}); checkClosed(); if (columnIndexes == null || columnIndexes.length != 1) { - SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_invalidColumnArrayLength"), null, false); + SQLServerException.makeFromDriverError(connection, this, + SQLServerException.getErrString("R_invalidColumnArrayLength"), null, false); } boolean fSuccess = execute(sql, Statement.RETURN_GENERATED_KEYS); loggerExternal.exiting(getClassNameLogging(), "execute", fSuccess); @@ -2047,7 +2054,8 @@ public final boolean execute(java.lang.String sql, loggerExternal.entering(getClassNameLogging(), "execute", new Object[] {sql, columnNames}); checkClosed(); if (columnNames == null || columnNames.length != 1) { - SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_invalidColumnArrayLength"), null, false); + SQLServerException.makeFromDriverError(connection, this, + SQLServerException.getErrString("R_invalidColumnArrayLength"), null, false); } boolean fSuccess = execute(sql, Statement.RETURN_GENERATED_KEYS); loggerExternal.exiting(getClassNameLogging(), "execute", fSuccess); @@ -2055,8 +2063,7 @@ public final boolean execute(java.lang.String sql, } @Override - public final int executeUpdate(String sql, - int autoGeneratedKeys) throws SQLServerException, SQLTimeoutException { + public final int executeUpdate(String sql, int autoGeneratedKeys) throws SQLServerException, SQLTimeoutException { if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) { loggerExternal.entering(getClassNameLogging(), "executeUpdate", new Object[] {sql, autoGeneratedKeys}); if (Util.IsActivityTraceOn()) { @@ -2073,7 +2080,8 @@ public final int executeUpdate(String sql, // this shouldn't happen, caller probably meant to call executeLargeUpdate if (updateCount < Integer.MIN_VALUE || updateCount > Integer.MAX_VALUE) - SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_updateCountOutofRange"), null, true); + SQLServerException.makeFromDriverError(connection, this, + SQLServerException.getErrString("R_updateCountOutofRange"), null, true); loggerExternal.exiting(getClassNameLogging(), "executeUpdate", updateCount); @@ -2108,7 +2116,8 @@ public final int executeUpdate(java.lang.String sql, loggerExternal.entering(getClassNameLogging(), "executeUpdate", new Object[] {sql, columnIndexes}); checkClosed(); if (columnIndexes == null || columnIndexes.length != 1) { - SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_invalidColumnArrayLength"), null, false); + SQLServerException.makeFromDriverError(connection, this, + SQLServerException.getErrString("R_invalidColumnArrayLength"), null, false); } int count = executeUpdate(sql, Statement.RETURN_GENERATED_KEYS); loggerExternal.exiting(getClassNameLogging(), "executeUpdate", count); @@ -2123,7 +2132,8 @@ public final long executeLargeUpdate(java.lang.String sql, loggerExternal.entering(getClassNameLogging(), "executeLargeUpdate", new Object[] {sql, columnIndexes}); checkClosed(); if (columnIndexes == null || columnIndexes.length != 1) { - SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_invalidColumnArrayLength"), null, false); + SQLServerException.makeFromDriverError(connection, this, + SQLServerException.getErrString("R_invalidColumnArrayLength"), null, false); } long count = executeLargeUpdate(sql, Statement.RETURN_GENERATED_KEYS); loggerExternal.exiting(getClassNameLogging(), "executeLargeUpdate", count); @@ -2137,7 +2147,8 @@ public final int executeUpdate(java.lang.String sql, loggerExternal.entering(getClassNameLogging(), "executeUpdate", new Object[] {sql, columnNames}); checkClosed(); if (columnNames == null || columnNames.length != 1) { - SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_invalidColumnArrayLength"), null, false); + SQLServerException.makeFromDriverError(connection, this, + SQLServerException.getErrString("R_invalidColumnArrayLength"), null, false); } int count = executeUpdate(sql, Statement.RETURN_GENERATED_KEYS); loggerExternal.exiting(getClassNameLogging(), "executeUpdate", count); @@ -2152,7 +2163,8 @@ public final long executeLargeUpdate(java.lang.String sql, loggerExternal.entering(getClassNameLogging(), "executeLargeUpdate", new Object[] {sql, columnNames}); checkClosed(); if (columnNames == null || columnNames.length != 1) { - SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_invalidColumnArrayLength"), null, false); + SQLServerException.makeFromDriverError(connection, this, + SQLServerException.getErrString("R_invalidColumnArrayLength"), null, false); } long count = executeLargeUpdate(sql, Statement.RETURN_GENERATED_KEYS); loggerExternal.exiting(getClassNameLogging(), "executeLargeUpdate", count); @@ -2171,7 +2183,8 @@ public final ResultSet getGeneratedKeys() throws SQLServerException { // Try to get that ResultSet. If there are no more results after the update count, // or if the next result isn't a ResultSet, then something is wrong. if (!getNextResult() || null == resultSet) { - SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_statementMustBeExecuted"), null, false); + SQLServerException.makeFromDriverError(connection, this, + SQLServerException.getErrString("R_statementMustBeExecuted"), null, false); } autoGeneratedKeys = resultSet; @@ -2191,15 +2204,15 @@ public final boolean getMoreResults(int mode) throws SQLException { } if (CLOSE_CURRENT_RESULT != mode && CLOSE_ALL_RESULTS != mode) - SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_modeSuppliedNotValid"), null, true); + SQLServerException.makeFromDriverError(connection, this, + SQLServerException.getErrString("R_modeSuppliedNotValid"), null, true); ResultSet rsPrevious = resultSet; boolean fResults = getMoreResults(); if (rsPrevious != null) { try { rsPrevious.close(); - } - catch (SQLException e) { + } catch (SQLException e) { throw new SQLServerException(e.getMessage(), null, 0, e); } } @@ -2254,8 +2267,7 @@ public T unwrap(Class iface) throws SQLException { T t; try { t = iface.cast(this); - } - catch (ClassCastException e) { + } catch (ClassCastException e) { throw new SQLServerException(e.getMessage(), e); } loggerExternal.exiting(getClassNameLogging(), "unwrap", t); @@ -2288,12 +2300,10 @@ public final void setResponseBuffering(String value) throws SQLServerException { if ("full".equalsIgnoreCase(value)) { isResponseBufferingAdaptive = false; wasResponseBufferingSet = true; - } - else if ("adaptive".equalsIgnoreCase(value)) { + } else if ("adaptive".equalsIgnoreCase(value)) { isResponseBufferingAdaptive = true; wasResponseBufferingSet = true; - } - else { + } else { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidresponseBuffering")); Object[] msgArgs = {value}; SQLServerException.makeFromDriverError(connection, this, form.format(msgArgs), null, false); @@ -2311,8 +2321,7 @@ public final String getResponseBuffering() throws SQLServerException { responseBuff = "adaptive"; else responseBuff = "full"; - } - else { + } else { responseBuff = connection.getResponseBuffering(); } loggerExternal.exiting(getClassNameLogging(), "getResponseBuffering", responseBuff); @@ -2320,13 +2329,15 @@ public final String getResponseBuffering() throws SQLServerException { } } + /** - * Helper class that does some basic parsing work for SQL statements that are stored procedure calls. + * Provides a helper class that does some basic parsing work for SQL statements that are stored procedure calls. * - * - Determines whether the SQL uses JDBC call syntax ("{[? =] call procedure_name...}") or T-SQL EXECUTE syntax ("EXEC [@p0 =] procedure_name..."). - * If JDBC call syntax is present, it gets rewritten as T-SQL EXECUTE syntax. + * - Determines whether the SQL uses JDBC call syntax ("{[? =] call procedure_name...}") or T-SQL EXECUTE syntax ("EXEC + * [@p0 =] procedure_name..."). If JDBC call syntax is present, it gets rewritten as T-SQL EXECUTE syntax. * - * - Determines whether the caller expects a return value from the stored procedure (see the optional return value syntax in [] above). + * - Determines whether the caller expects a return value from the stored procedure (see the optional return value + * syntax in [] above). * * - Extracts the stored procedure name from the call. * @@ -2346,16 +2357,17 @@ boolean hasReturnValueSyntax() { } /* - * SQL Identifier regex - * - * Loosely follows the spec'd SQL identifier syntax: - anything between escape characters (square brackets or double quotes), including escaped - * escape characters, OR - any contiguous string of non-whitespace characters. - including multipart identifiers + * SQL Identifier regex Loosely follows the spec'd SQL identifier syntax: - anything between escape characters + * (square brackets or double quotes), including escaped escape characters, OR - any contiguous string of + * non-whitespace characters. - including multipart identifiers */ private final static String sqlIdentifierPart = "(?:(?:\\[(?:[^\\]]|(?:\\]\\]))+?\\])|(?:\"(?:[^\"]|(?:\"\"))+?\")|(?:\\S+?))"; - private final static String sqlIdentifierWithoutGroups = "(" + sqlIdentifierPart + "(?:\\." + sqlIdentifierPart + "){0,3}?)"; + private final static String sqlIdentifierWithoutGroups = "(" + sqlIdentifierPart + "(?:\\." + sqlIdentifierPart + + "){0,3}?)"; - private final static String sqlIdentifierWithGroups = "(" + sqlIdentifierPart + ")" + "(?:\\." + "(" + sqlIdentifierPart + "))?"; + private final static String sqlIdentifierWithGroups = "(" + sqlIdentifierPart + ")" + "(?:\\." + "(" + + sqlIdentifierPart + "))?"; // This is used in three part name matching. static String getSQLIdentifierWithGroups() { @@ -2363,30 +2375,23 @@ static String getSQLIdentifierWithGroups() { } /* - * JDBC call syntax regex - * - * From the JDBC spec: {call procedure_name} {call procedure_name(?, ?, ...)} {? = call procedure_name[(?, ?, ...)]} - * - * allowing for arbitrary amounts of whitespace in the obvious places. + * JDBC call syntax regex From the JDBC spec: {call procedure_name} {call procedure_name(?, ?, ...)} {? = call + * procedure_name[(?, ?, ...)]} allowing for arbitrary amounts of whitespace in the obvious places. */ private final static Pattern jdbcCallSyntax = Pattern - .compile("(?s)\\s*?\\{\\s*?(\\?\\s*?=)?\\s*?[cC][aA][lL][lL]\\s+?" + sqlIdentifierWithoutGroups + "(?:\\s*?\\((.*)\\))?\\s*\\}.*+"); + .compile("(?s)\\s*?\\{\\s*?(\\?\\s*?=)?\\s*?[cC][aA][lL][lL]\\s+?" + sqlIdentifierWithoutGroups + + "(?:\\s*?\\((.*)\\))?\\s*\\}.*+"); /* - * T-SQL EXECUTE syntax regex - * - * EXEC | EXECUTE [@return_result =] procedure_name [parameters] - * - * allowing for arbitrary amounts of whitespace in the obvious places. + * T-SQL EXECUTE syntax regex EXEC | EXECUTE [@return_result =] procedure_name [parameters] allowing for arbitrary + * amounts of whitespace in the obvious places. */ - private final static Pattern sqlExecSyntax = Pattern.compile("\\s*?[eE][xX][eE][cC](?:[uU][tT][eE])??\\s+?(" + sqlIdentifierWithoutGroups - + "\\s*?=\\s+?)??" + sqlIdentifierWithoutGroups + "(?:$|(?:\\s+?.*+))"); + private final static Pattern sqlExecSyntax = Pattern.compile("\\s*?[eE][xX][eE][cC](?:[uU][tT][eE])??\\s+?(" + + sqlIdentifierWithoutGroups + "\\s*?=\\s+?)??" + sqlIdentifierWithoutGroups + "(?:$|(?:\\s+?.*+))"); /* - * JDBC limit escape syntax - * - * From the JDBC spec: {LIMIT [OFFSET ]} The driver currently does not support the OFFSET part. It will throw an exception if - * used. + * JDBC limit escape syntax From the JDBC spec: {LIMIT [OFFSET ]} The driver currently does not + * support the OFFSET part. It will throw an exception if used. */ enum State { START, @@ -2401,47 +2406,54 @@ enum State { PROCESS }; - // This pattern matches the LIMIT syntax with an OFFSET clause. The driver does not support OFFSET expression in the LIMIT clause. + // This pattern matches the LIMIT syntax with an OFFSET clause. The driver does not support OFFSET expression in the + // LIMIT clause. // It will throw an exception if OFFSET is present in the LIMIT escape syntax. private final static Pattern limitSyntaxWithOffset = Pattern .compile("\\{\\s*[lL][iI][mM][iI][tT]\\s+(.*)\\s+[oO][fF][fF][sS][eE][tT]\\s+(.*)\\}"); - // This pattern is used to determine if the query has LIMIT escape syntax. If so, then the query is further processed to translate the syntax. + // This pattern is used to determine if the query has LIMIT escape syntax. If so, then the query is further + // processed to translate the syntax. private final static Pattern limitSyntaxGeneric = Pattern .compile("\\{\\s*[lL][iI][mM][iI][tT]\\s+(.*)(\\s+[oO][fF][fF][sS][eE][tT](.*)\\}|\\s*\\})"); private final static Pattern selectPattern = Pattern.compile("([sS][eE][lL][eE][cC][tT])\\s+"); // OPENQUERY ( linked_server ,'query' ) - private final static Pattern openQueryPattern = Pattern.compile("[oO][pP][eE][nN][qQ][uU][eE][rR][yY]\\s*\\(.*,\\s*'(.*)'\\s*\\)"); + private final static Pattern openQueryPattern = Pattern + .compile("[oO][pP][eE][nN][qQ][uU][eE][rR][yY]\\s*\\(.*,\\s*'(.*)'\\s*\\)"); /* - * OPENROWSET ( 'provider_name', { 'datasource' ; 'user_id' ; 'password' | 'provider_string' }, { [ catalog. ] [ schema. ] object | 'query' } ) + * OPENROWSET ( 'provider_name', { 'datasource' ; 'user_id' ; 'password' | 'provider_string' }, { [ catalog. ] [ + * schema. ] object | 'query' } ) */ - private final static Pattern openRowsetPattern = Pattern.compile("[oO][pP][eE][nN][rR][oO][wW][sS][eE][tT]\\s*\\(.*,.*,\\s*'(.*)'\\s*\\)"); + private final static Pattern openRowsetPattern = Pattern + .compile("[oO][pP][eE][nN][rR][oO][wW][sS][eE][tT]\\s*\\(.*,.*,\\s*'(.*)'\\s*\\)"); /* * {limit 30} {limit ?} {limit (?)} */ - private final static Pattern limitOnlyPattern = Pattern.compile("\\{\\s*[lL][iI][mM][iI][tT]\\s+(((\\(|\\s)*)(\\d*|\\?)((\\)|\\s)*))\\s*\\}"); + private final static Pattern limitOnlyPattern = Pattern + .compile("\\{\\s*[lL][iI][mM][iI][tT]\\s+(((\\(|\\s)*)(\\d*|\\?)((\\)|\\s)*))\\s*\\}"); /** - * This function translates the LIMIT escape syntax, {LIMIT [OFFSET ]} SQL Server does not support LIMIT syntax, the LIMIT escape - * syntax is thus translated to use "TOP" syntax The OFFSET clause is not supported, and will throw an exception if used. + * Translates the LIMIT escape syntax, {LIMIT [OFFSET ]} SQL Server does not support LIMIT syntax, the + * LIMIT escape syntax is thus translated to use "TOP" syntax The OFFSET clause is not supported, and will throw an + * exception if used. * - * @param sql the SQL query + * @param sql + * the SQL query * - * @param indx Position in the query from where to start translation + * @param indx + * Position in the query from where to start translation * - * @param endChar The character that marks the end of translation + * @param endChar + * The character that marks the end of translation * * @throws SQLServerException * * @return the number of characters that have been translated * */ - - int translateLimit(StringBuffer sql, - int indx, - char endChar) throws SQLServerException { + int translateLimit(StringBuffer sql, int indx, char endChar) throws SQLServerException { Matcher selectMatcher = selectPattern.matcher(sql); Matcher openQueryMatcher = openQueryPattern.matcher(sql); Matcher openRowsetMatcher = openRowsetPattern.matcher(sql); @@ -2460,39 +2472,40 @@ int translateLimit(StringBuffer sql, nextState = State.PROCESS; break; case PROCESS: - // The search for endChar should come before the search for quote (') as openquery has quote(') as the endChar + // The search for endChar should come before the search for quote (') as openquery has quote(') as + // the endChar if (endChar == ch) { nextState = State.END; - } - else if ('\'' == ch) { + } else if ('\'' == ch) { nextState = State.QUOTE; - } - else if ('(' == ch) { + } else if ('(' == ch) { nextState = State.SUBQUERY; - } - else if (limitMatcher.find(indx) && indx == limitMatcher.start()) { + } else if (limitMatcher.find(indx) && indx == limitMatcher.start()) { nextState = State.LIMIT; - } - else if (offsetMatcher.find(indx) && indx == offsetMatcher.start()) { + } else if (offsetMatcher.find(indx) && indx == offsetMatcher.start()) { nextState = State.OFFSET; - } - else if (openQueryMatcher.find(indx) && indx == openQueryMatcher.start()) { + } else if (openQueryMatcher.find(indx) && indx == openQueryMatcher.start()) { nextState = State.OPENQUERY; - } - else if (openRowsetMatcher.find(indx) && indx == openRowsetMatcher.start()) { + } else if (openRowsetMatcher.find(indx) && indx == openRowsetMatcher.start()) { nextState = State.OPENROWSET; - } - else if (selectMatcher.find(indx) && indx == selectMatcher.start()) { + } else if (selectMatcher.find(indx) && indx == selectMatcher.start()) { nextState = State.SELECT; - } - else + } else indx++; break; case OFFSET: // throw exception as OFFSET is not supported - throw new SQLServerException(SQLServerException.getErrString("R_limitOffsetNotSupported"), null, // SQLState is null as this error - // is generated in the driver - 0, // Use 0 instead of DriverError.NOT_SET to use the correct constructor + // SQLState is null as this error is generated in the driver + throw new SQLServerException(SQLServerException.getErrString("R_limitOffsetNotSupported"), null, 0, // Use + // 0 + // instead + // of + // DriverError.NOT_SET + // to + // use + // the + // correct + // constructor null); case LIMIT: // Check if the number of opening/closing parentheses surrounding the digits or "?" in LIMIT match @@ -2509,17 +2522,17 @@ else if (selectMatcher.find(indx) && indx == selectMatcher.start()) { closingParentheses++; } if (openingParentheses != closingParentheses) { - throw new SQLServerException(SQLServerException.getErrString("R_limitEscapeSyntaxError"), null, // SQLState is null as this - // error is generated in the - // driver + // SQLState is null as this error is generated in the driver + throw new SQLServerException(SQLServerException.getErrString("R_limitEscapeSyntaxError"), null, 0, // Use 0 instead of DriverError.NOT_SET to use the correct constructor null); } /* - * 'topPosition' is a stack that keeps track of the positions where the next "TOP" should be inserted. The SELECT expressions are - * matched with the closest LIMIT expressions unless in a subquery with explicit parentheses, that's why it needs to be a stack. - * To translate, we add the clause after SELECT and delete the clause {LIMIT rows}. + * 'topPosition' is a stack that keeps track of the positions where the next "TOP" should be + * inserted. The SELECT expressions are matched with the closest LIMIT expressions unless in a + * subquery with explicit parentheses, that's why it needs to be a stack. To translate, we add the + * clause after SELECT and delete the clause {LIMIT rows}. */ if (!topPosition.empty()) { Integer top = topPosition.pop(); @@ -2530,16 +2543,15 @@ else if (selectMatcher.find(indx) && indx == selectMatcher.start()) { if ('?' == rows.charAt(0)) { // For parameterized queries the '?' needs to wrapped in parentheses. sql.insert(top, " TOP (" + rows + ")"); - // add the letters/spaces inserted with TOP, add the digits from LIMIT, subtract one because the + // add the letters/spaces inserted with TOP, add the digits from LIMIT, subtract one because + // the // current letter at the index is deleted. indx += 7 + rows.length() - 1; - } - else { + } else { sql.insert(top, " TOP " + rows); indx += 5 + rows.length() - 1; } - } - else { + } else { // Could not match LIMIT with a SELECT, should never occur. // But if it does, just ignore // Matcher.end() returns offset after the last character of matched string @@ -2562,12 +2574,10 @@ else if (selectMatcher.find(indx) && indx == selectMatcher.start()) { indx++; if (sql.length() > indx && '\'' == sql.charAt(indx)) { nextState = State.QUOTE; - } - else { + } else { nextState = State.PROCESS; } - } - else { + } else { nextState = State.QUOTE; } break; @@ -2599,7 +2609,7 @@ else if (selectMatcher.find(indx) && indx == selectMatcher.start()) { // throw break; } - }// end of while + } // end of while return indx - startIndx; } @@ -2615,8 +2625,7 @@ String translate(String sql) throws SQLServerException { procedureName = matcher.group(2); String args = matcher.group(3); sql = "EXEC " + (hasReturnValueSyntax ? "? = " : "") + procedureName + ((null != args) ? (" " + args) : ""); - } - else { + } else { matcher = sqlExecSyntax.matcher(sql); if (matcher.matches()) { diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerStatementColumnEncryptionSetting.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerStatementColumnEncryptionSetting.java index 078c4760c..b3bcb4a57 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerStatementColumnEncryptionSetting.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerStatementColumnEncryptionSetting.java @@ -1,37 +1,35 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -/** - * Specifies how data will be sent and received when reading and writing encrypted columns. Depending on your specific query, performance impact may - * be reduced by bypassing the Always Encrypted driver processing when non-encrypted columns are being used. Note that these settings cannot be used - * to bypass encryption and gain access to plaintext data. - */ -public enum SQLServerStatementColumnEncryptionSetting { - /** - * if "Column Encryption Setting=Enabled" in the connection string, use Enabled. Otherwise, maps to Disabled. - */ - UseConnectionSetting, - - /** - * Enables TCE for the command. Overrides the connection level setting for this command. - */ - Enabled, - - /** - * Parameters will not be encrypted, only the ResultSet will be decrypted. This is an optimization for queries that do not pass any encrypted - * input parameters. Overrides the connection level setting for this command. - */ - ResultSetOnly, - - /** - * Disables TCE for the command.Overrides the connection level setting for this command. - */ - Disabled, -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +/** + * Specifies how data will be sent and received when reading and writing encrypted columns. Depending on your specific + * query, performance impact may be reduced by bypassing the Always Encrypted driver processing when non-encrypted + * columns are being used. Note that these settings cannot be used to bypass encryption and gain access to plaintext + * data. + */ +public enum SQLServerStatementColumnEncryptionSetting { + /** + * if "Column Encryption Setting=Enabled" in the connection string, use Enabled. Otherwise, maps to Disabled. + */ + UseConnectionSetting, + + /** + * Enables TCE for the command. Overrides the connection level setting for this command. + */ + Enabled, + + /** + * Parameters will not be encrypted, only the ResultSet will be decrypted. This is an optimization for queries that + * do not pass any encrypted input parameters. Overrides the connection level setting for this command. + */ + ResultSetOnly, + + /** + * Disables TCE for the command.Overrides the connection level setting for this command. + */ + Disabled, +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSymmetricKey.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSymmetricKey.java index 12e20a56c..5552e9707 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSymmetricKey.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSymmetricKey.java @@ -1,42 +1,40 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -/** - * - * Base class which represents Symmetric key - * - */ -class SQLServerSymmetricKey { - private byte[] rootKey; - - SQLServerSymmetricKey(byte[] rootKey) throws SQLServerException { - if (null == rootKey) { - throw new SQLServerException(this, SQLServerException.getErrString("R_NullColumnEncryptionKey"), null, 0, false); - } - else if (0 == rootKey.length) { - throw new SQLServerException(this, SQLServerException.getErrString("R_EmptyColumnEncryptionKey"), null, 0, false); - } - this.rootKey = rootKey; - } - - byte[] getRootKey() { - return rootKey; - } - - int length() { - return rootKey.length; - } - - void zeroOutKey() { - for (int i = 0; i < rootKey.length; i++) { - rootKey[i] = (byte) 0; - } - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +/** + * + * Base class which represents Symmetric key + * + */ +class SQLServerSymmetricKey { + private byte[] rootKey; + + SQLServerSymmetricKey(byte[] rootKey) throws SQLServerException { + if (null == rootKey) { + throw new SQLServerException(this, SQLServerException.getErrString("R_NullColumnEncryptionKey"), null, 0, + false); + } else if (0 == rootKey.length) { + throw new SQLServerException(this, SQLServerException.getErrString("R_EmptyColumnEncryptionKey"), null, 0, + false); + } + this.rootKey = rootKey; + } + + byte[] getRootKey() { + return rootKey; + } + + int length() { + return rootKey.length; + } + + void zeroOutKey() { + for (int i = 0; i < rootKey.length; i++) { + rootKey[i] = (byte) 0; + } + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSymmetricKeyCache.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSymmetricKeyCache.java index 04f9335ff..80eb9a03a 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSymmetricKeyCache.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerSymmetricKeyCache.java @@ -1,173 +1,180 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static java.util.concurrent.TimeUnit.SECONDS; - -import java.text.MessageFormat; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ThreadFactory; - -import java.util.Base64;; - -class CacheClear implements Runnable { - - private String keylookupValue; - static private java.util.logging.Logger aeLogger = java.util.logging.Logger.getLogger("com.microsoft.sqlserver.jdbc.CacheClear"); - - CacheClear(String keylookupValue) { - this.keylookupValue = keylookupValue; - } - - @Override - public void run() { - // remove() is a no-op if the key is not in the map. - // It is a concurrentHashMap, update/remove operations are thread safe. - synchronized (SQLServerSymmetricKeyCache.lock) { - SQLServerSymmetricKeyCache instance = SQLServerSymmetricKeyCache.getInstance(); - if (instance.getCache().containsKey(keylookupValue)) { - instance.getCache().get(keylookupValue).zeroOutKey(); - instance.getCache().remove(keylookupValue); - if (aeLogger.isLoggable(java.util.logging.Level.FINE)) { - aeLogger.fine("Removed encryption key from cache..."); - } - } - } - } -} - -/** - * - * Cache for the Symmetric keys - * - */ -final class SQLServerSymmetricKeyCache { - static Object lock = new Object(); - private final ConcurrentHashMap cache; - private static final SQLServerSymmetricKeyCache instance = new SQLServerSymmetricKeyCache(); - private static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, new ThreadFactory() { - @Override - public Thread newThread(Runnable r) { - Thread t = Executors.defaultThreadFactory().newThread(r); - t.setDaemon(true); - return t; - } - }); - - static final private java.util.logging.Logger aeLogger = java.util.logging.Logger - .getLogger("com.microsoft.sqlserver.jdbc.SQLServerSymmetricKeyCache"); - - private SQLServerSymmetricKeyCache() { - cache = new ConcurrentHashMap<>(); - } - - static SQLServerSymmetricKeyCache getInstance() { - return instance; - } - - ConcurrentHashMap getCache() { - return cache; - } - - /** - * Retrieves key - * - * @param keyInfo - * contains encryption meta data information - * @param connection - * @return plain text key - */ - SQLServerSymmetricKey getKey(EncryptionKeyInfo keyInfo, - SQLServerConnection connection) throws SQLServerException { - SQLServerSymmetricKey encryptionKey = null; - synchronized (lock) { - String serverName = connection.getTrustedServerNameAE(); - assert null != serverName : "serverName should not be null in getKey."; - - StringBuilder keyLookupValuebuffer = new StringBuilder(serverName); - String keyLookupValue; - keyLookupValuebuffer.append(":"); - - keyLookupValuebuffer.append(Base64.getEncoder().encodeToString((new String(keyInfo.encryptedKey, UTF_8)).getBytes())); - - keyLookupValuebuffer.append(":"); - keyLookupValuebuffer.append(keyInfo.keyStoreName); - keyLookupValue = keyLookupValuebuffer.toString(); - keyLookupValuebuffer.setLength(0); // Get rid of the buffer, will be garbage collected. - - if (aeLogger.isLoggable(java.util.logging.Level.FINE)) { - aeLogger.fine("Checking trusted master key path..."); - } - Boolean[] hasEntry = new Boolean[1]; - List trustedKeyPaths = SQLServerConnection.getColumnEncryptionTrustedMasterKeyPaths(serverName, hasEntry); - if (hasEntry[0]) { - if ((null == trustedKeyPaths) || (0 == trustedKeyPaths.size()) || (!trustedKeyPaths.contains(keyInfo.keyPath))) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_UntrustedKeyPath")); - Object[] msgArgs = {keyInfo.keyPath, serverName}; - throw new SQLServerException(this, form.format(msgArgs), null, 0, false); - } - } - - if (aeLogger.isLoggable(java.util.logging.Level.FINE)) { - aeLogger.fine("Checking Symmetric key cache..."); - } - - // if ColumnEncryptionKeyCacheTtl is 0 no caching at all - if (!cache.containsKey(keyLookupValue)) { - - // Check for the connection provider first. - SQLServerColumnEncryptionKeyStoreProvider provider = connection.getSystemColumnEncryptionKeyStoreProvider(keyInfo.keyStoreName); - - // There is no connection provider of this name, check for the global system providers. - if (null == provider) { - provider = SQLServerConnection.getGlobalSystemColumnEncryptionKeyStoreProvider(keyInfo.keyStoreName); - } - - // There is no global system provider of this name, check for the global custom providers. - if (null == provider) { - provider = SQLServerConnection.getGlobalCustomColumnEncryptionKeyStoreProvider(keyInfo.keyStoreName); - } - - // No provider was found of this name. - if (null == provider) { - String systemProviders = connection.getAllSystemColumnEncryptionKeyStoreProviders(); - String customProviders = SQLServerConnection.getAllGlobalCustomSystemColumnEncryptionKeyStoreProviders(); - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_UnrecognizedKeyStoreProviderName")); - Object[] msgArgs = {keyInfo.keyStoreName, systemProviders, customProviders}; - throw new SQLServerException(this, form.format(msgArgs), null, 0, false); - } - - byte[] plaintextKey; - plaintextKey = provider.decryptColumnEncryptionKey(keyInfo.keyPath, keyInfo.algorithmName, keyInfo.encryptedKey); - encryptionKey = new SQLServerSymmetricKey(plaintextKey); - - /* - * a ColumnEncryptionKeyCacheTtl value of '0' means no caching at all. The expected use case is to have the application set it once. - * The application could set it multiple times, in which case a key gets the TTL defined at the time of its entry into the cache. - */ - long columnEncryptionKeyCacheTtl = SQLServerConnection.getColumnEncryptionKeyCacheTtl(); - if (0 != columnEncryptionKeyCacheTtl) { - cache.putIfAbsent(keyLookupValue, encryptionKey); - if (aeLogger.isLoggable(java.util.logging.Level.FINE)) { - aeLogger.fine("Adding encryption key to cache..."); - } - scheduler.schedule(new CacheClear(keyLookupValue), columnEncryptionKeyCacheTtl, SECONDS); - } - } - else { - encryptionKey = cache.get(keyLookupValue); - } - } - return encryptionKey; - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static java.util.concurrent.TimeUnit.SECONDS; + +import java.text.MessageFormat; +import java.util.Base64; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadFactory;; + + +class CacheClear implements Runnable { + + private String keylookupValue; + static private java.util.logging.Logger aeLogger = java.util.logging.Logger + .getLogger("com.microsoft.sqlserver.jdbc.CacheClear"); + + CacheClear(String keylookupValue) { + this.keylookupValue = keylookupValue; + } + + @Override + public void run() { + // remove() is a no-op if the key is not in the map. + // It is a concurrentHashMap, update/remove operations are thread safe. + synchronized (SQLServerSymmetricKeyCache.lock) { + SQLServerSymmetricKeyCache instance = SQLServerSymmetricKeyCache.getInstance(); + if (instance.getCache().containsKey(keylookupValue)) { + instance.getCache().get(keylookupValue).zeroOutKey(); + instance.getCache().remove(keylookupValue); + if (aeLogger.isLoggable(java.util.logging.Level.FINE)) { + aeLogger.fine("Removed encryption key from cache..."); + } + } + } + } +} + + +/** + * + * Cache for the Symmetric keys + * + */ +final class SQLServerSymmetricKeyCache { + static Object lock = new Object(); + private final ConcurrentHashMap cache; + private static final SQLServerSymmetricKeyCache instance = new SQLServerSymmetricKeyCache(); + private static ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1, new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + Thread t = Executors.defaultThreadFactory().newThread(r); + t.setDaemon(true); + return t; + } + }); + + static final private java.util.logging.Logger aeLogger = java.util.logging.Logger + .getLogger("com.microsoft.sqlserver.jdbc.SQLServerSymmetricKeyCache"); + + private SQLServerSymmetricKeyCache() { + cache = new ConcurrentHashMap<>(); + } + + static SQLServerSymmetricKeyCache getInstance() { + return instance; + } + + ConcurrentHashMap getCache() { + return cache; + } + + /** + * Returns key + * + * @param keyInfo + * contains encryption meta data information + * @param connection + * @return plain text key + */ + SQLServerSymmetricKey getKey(EncryptionKeyInfo keyInfo, SQLServerConnection connection) throws SQLServerException { + SQLServerSymmetricKey encryptionKey = null; + synchronized (lock) { + String serverName = connection.getTrustedServerNameAE(); + assert null != serverName : "serverName should not be null in getKey."; + + StringBuilder keyLookupValuebuffer = new StringBuilder(serverName); + String keyLookupValue; + keyLookupValuebuffer.append(":"); + + keyLookupValuebuffer + .append(Base64.getEncoder().encodeToString((new String(keyInfo.encryptedKey, UTF_8)).getBytes())); + + keyLookupValuebuffer.append(":"); + keyLookupValuebuffer.append(keyInfo.keyStoreName); + keyLookupValue = keyLookupValuebuffer.toString(); + keyLookupValuebuffer.setLength(0); // Get rid of the buffer, will be garbage collected. + + if (aeLogger.isLoggable(java.util.logging.Level.FINE)) { + aeLogger.fine("Checking trusted master key path..."); + } + Boolean[] hasEntry = new Boolean[1]; + List trustedKeyPaths = SQLServerConnection.getColumnEncryptionTrustedMasterKeyPaths(serverName, + hasEntry); + if (hasEntry[0]) { + if ((null == trustedKeyPaths) || (0 == trustedKeyPaths.size()) + || (!trustedKeyPaths.contains(keyInfo.keyPath))) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_UntrustedKeyPath")); + Object[] msgArgs = {keyInfo.keyPath, serverName}; + throw new SQLServerException(this, form.format(msgArgs), null, 0, false); + } + } + + if (aeLogger.isLoggable(java.util.logging.Level.FINE)) { + aeLogger.fine("Checking Symmetric key cache..."); + } + + // if ColumnEncryptionKeyCacheTtl is 0 no caching at all + if (!cache.containsKey(keyLookupValue)) { + + // Check for the connection provider first. + SQLServerColumnEncryptionKeyStoreProvider provider = connection + .getSystemColumnEncryptionKeyStoreProvider(keyInfo.keyStoreName); + + // There is no connection provider of this name, check for the global system providers. + if (null == provider) { + provider = SQLServerConnection + .getGlobalSystemColumnEncryptionKeyStoreProvider(keyInfo.keyStoreName); + } + + // There is no global system provider of this name, check for the global custom providers. + if (null == provider) { + provider = SQLServerConnection + .getGlobalCustomColumnEncryptionKeyStoreProvider(keyInfo.keyStoreName); + } + + // No provider was found of this name. + if (null == provider) { + String systemProviders = connection.getAllSystemColumnEncryptionKeyStoreProviders(); + String customProviders = SQLServerConnection + .getAllGlobalCustomSystemColumnEncryptionKeyStoreProviders(); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_UnrecognizedKeyStoreProviderName")); + Object[] msgArgs = {keyInfo.keyStoreName, systemProviders, customProviders}; + throw new SQLServerException(this, form.format(msgArgs), null, 0, false); + } + + byte[] plaintextKey; + plaintextKey = provider.decryptColumnEncryptionKey(keyInfo.keyPath, keyInfo.algorithmName, + keyInfo.encryptedKey); + encryptionKey = new SQLServerSymmetricKey(plaintextKey); + + /* + * a ColumnEncryptionKeyCacheTtl value of '0' means no caching at all. The expected use case is to have + * the application set it once. The application could set it multiple times, in which case a key gets + * the TTL defined at the time of its entry into the cache. + */ + long columnEncryptionKeyCacheTtl = SQLServerConnection.getColumnEncryptionKeyCacheTtl(); + if (0 != columnEncryptionKeyCacheTtl) { + cache.putIfAbsent(keyLookupValue, encryptionKey); + if (aeLogger.isLoggable(java.util.logging.Level.FINE)) { + aeLogger.fine("Adding encryption key to cache..."); + } + scheduler.schedule(new CacheClear(keyLookupValue), columnEncryptionKeyCacheTtl, SECONDS); + } + } else { + encryptionKey = cache.get(keyLookupValue); + } + } + return encryptionKey; + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerXAConnection.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerXAConnection.java index ad7a73a4a..bfb18780c 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerXAConnection.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerXAConnection.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -16,8 +13,9 @@ import javax.sql.XAConnection; import javax.transaction.xa.XAResource; + /** - * SQLServerXAConnection provides JDBC connections that can participate in distributed (XA) transactions. + * Provides JDBC connections that can participate in distributed (XA) transactions. */ public final class SQLServerXAConnection extends SQLServerPooledConnection implements XAConnection { @@ -29,17 +27,17 @@ public final class SQLServerXAConnection extends SQLServerPooledConnection imple private SQLServerConnection physicalControlConnection; private Logger xaLogger; - SQLServerXAConnection(SQLServerDataSource ds, - String user, - String pwd) throws java.sql.SQLException { + SQLServerXAConnection(SQLServerDataSource ds, String user, String pwd) throws java.sql.SQLException { super(ds, user, pwd); // Grab SQLServerXADataSource's static XA logger instance. xaLogger = SQLServerXADataSource.xaLogger; SQLServerConnection con = getPhysicalConnection(); Properties controlConnectionProperties = (Properties) con.activeConnectionProperties.clone(); - // Arguments to be sent as unicode always to the server, as the stored procs always write unicode chars as out param. - controlConnectionProperties.setProperty(SQLServerDriverBooleanProperty.SEND_STRING_PARAMETERS_AS_UNICODE.toString(), "true"); + // Arguments to be sent as unicode always to the server, as the stored procs always write unicode chars as out + // param. + controlConnectionProperties + .setProperty(SQLServerDriverBooleanProperty.SEND_STRING_PARAMETERS_AS_UNICODE.toString(), "true"); controlConnectionProperties.remove(SQLServerDriverStringProperty.SELECT_METHOD.toString()); if (xaLogger.isLoggable(Level.FINER)) @@ -47,14 +45,13 @@ public final class SQLServerXAConnection extends SQLServerPooledConnection imple physicalControlConnection = null; if (Util.use43Wrapper()) { physicalControlConnection = new SQLServerConnection43(toString()); - } - else { + } else { physicalControlConnection = new SQLServerConnection(toString()); } physicalControlConnection.connect(controlConnectionProperties, null); if (xaLogger.isLoggable(Level.FINER)) - xaLogger.finer("Created an internal control connection" + physicalControlConnection.toString() + " for " + toString() - + " Physical connection:" + getPhysicalConnection().toString()); + xaLogger.finer("Created an internal control connection" + physicalControlConnection.toString() + " for " + + toString() + " Physical connection:" + getPhysicalConnection().toString()); if (xaLogger.isLoggable(Level.FINER)) xaLogger.finer(ds.toString() + " user:" + user); diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerXADataSource.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerXADataSource.java index baaa331ef..6ba0504b7 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerXADataSource.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerXADataSource.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -16,47 +13,50 @@ import javax.sql.XAConnection; import javax.sql.XADataSource; + /** - * SQLServerXADataSource provides database connections for use in distributed (XA) transactions. SQLServerXADataSource also supports connection - * pooling of physical connections. + * Provides database connections for use in distributed (XA) transactions. SQLServerXADataSource also supports + * connection pooling of physical connections. * - * The XADataSource and XAConnection interfaces, which are defined in the package javax.sql, are implemented by sqlserver. An XAConnection object is a - * pooled connection that can participate in a distributed transaction. More precisely, XAConnection extends the PooledConnection interface by adding - * the method getXAResource. This method produces an XAResource object that can be used by a transaction manager to coordinate the work done on this + * The XADataSource and XAConnection interfaces, which are defined in the package javax.sql, are implemented by + * sqlserver. An XAConnection object is a pooled connection that can participate in a distributed transaction. More + * precisely, XAConnection extends the PooledConnection interface by adding the method getXAResource. This method + * produces an XAResource object that can be used by a transaction manager to coordinate the work done on this * connection with the other participants in the distributed transaction. * *

- * Because they extend the PooledConnection interface, XAConnection objects support all the methods of PooledConnection objects. They are reusable - * physical connections to an underlying data source and produce logical connection handles that can be passed back to a JDBC application. + * Because they extend the PooledConnection interface, XAConnection objects support all the methods of PooledConnection + * objects. They are reusable physical connections to an underlying data source and produce logical connection handles + * that can be passed back to a JDBC application. * *

- * XAConnection objects are produced by an XADataSource object. There is some similarity between ConnectionPoolDataSource objects and XADataSource - * objects in that they are both implemented below a DataSource layer that is visible to the JDBC application. This architecture allows sqlserver to - * support distributed transactions in a way that is transparent to the application. + * XAConnection objects are produced by an XADataSource object. There is some similarity between + * ConnectionPoolDataSource objects and XADataSource objects in that they are both implemented below a DataSource layer + * that is visible to the JDBC application. This architecture allows sqlserver to support distributed transactions in a + * way that is transparent to the application. * *
*
- * SQLServerXADataSource can be configured to integrate with Microsoft Distributed Transaction Coordinator (DTC) to provide true, distributed - * transaction processing. + * SQLServerXADataSource can be configured to integrate with Microsoft Distributed Transaction Coordinator (DTC) to + * provide true, distributed transaction processing. */ - public final class SQLServerXADataSource extends SQLServerConnectionPoolDataSource implements XADataSource { static Logger xaLogger = Logger.getLogger("com.microsoft.sqlserver.jdbc.internals.XA"); /** - * Obtain a physical database connection to particate in an XA transaction with the specified user and password. This API should only be called by - * XA connection pool implementations, not regular JDBC application code. + * Returns a physical database connection to particate in an XA transaction with the specified user and password. + * This API should only be called by XA connection pool implementations, not regular JDBC application code. * * @return A new XAConnection * @exception SQLException - * The database connection failed. + * The database connection failed. */ @Override - public XAConnection getXAConnection(String user, - String password) throws SQLException { + public XAConnection getXAConnection(String user, String password) throws SQLException { if (loggerExternal.isLoggable(Level.FINER)) - loggerExternal.entering(getClassNameLogging(), "getXAConnection", new Object[] {user, "Password not traced"}); + loggerExternal.entering(getClassNameLogging(), "getXAConnection", + new Object[] {user, "Password not traced"}); SQLServerXAConnection pooledXAConnection = new SQLServerXAConnection(this, user, password); if (xaLogger.isLoggable(Level.FINER)) @@ -78,12 +78,12 @@ public XAConnection getXAConnection(String user, } /** - * Obtain a physical database connection to particate in an XA transaction. This API should only be called by XA connection pool implementations, - * not regular JDBC application code. + * Returns a physical database connection to particate in an XA transaction. This API should only be called by XA + * connection pool implementations, not regular JDBC application code. * * @return A new XAConnection * @exception SQLException - * The database connection failed. + * The database connection failed. */ @Override public XAConnection getXAConnection() throws SQLException { @@ -114,8 +114,9 @@ private void readObject(java.io.ObjectInputStream stream) throws java.io.Invalid throw new java.io.InvalidObjectException(""); } - // This is 90% duplicate from the SQLServerDataSource, the serialization proxy pattern does not lend itself to inheritance - // so the duplication is necessary + /** + * Implements java.io.Serializable the same way as {@link SQLServerDataSource} + */ private static class SerializationProxy implements java.io.Serializable { private final Reference ref; private static final long serialVersionUID = 454661379842314126L; diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerXAResource.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerXAResource.java index 7ba25de95..224996a90 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerXAResource.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerXAResource.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -20,14 +17,15 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.logging.Logger; + import javax.transaction.xa.XAException; import javax.transaction.xa.XAResource; import javax.transaction.xa.Xid; + /** - * Transaction id implementation used to recover transactions. + * Impelments Transaction id used to recover transactions. */ - final class XidImpl implements Xid { private final int formatId; private final byte gtrid[]; @@ -35,25 +33,24 @@ final class XidImpl implements Xid { private final String traceID; /* - * XA Flags public static final int TMENDRSCAN = 8388608; public static final int TMFAIL = 536870912; public static final int TMJOIN = 2097152; - * public static final int TMNOFLAGS = 0; public static final int TMONEPHASE = 1073741824; public static final int TMRESUME = 134217728; public - * static final int TMSTARTRSCAN = 16777216; public static final int TMSUCCESS = 67108864; public static final int TMSUSPEND = 33554432; public - * static final int XA_RDONLY = 3; public static final int XA_OK = 0; + * XA Flags public static final int TMENDRSCAN = 8388608; public static final int TMFAIL = 536870912; public static + * final int TMJOIN = 2097152; public static final int TMNOFLAGS = 0; public static final int TMONEPHASE = + * 1073741824; public static final int TMRESUME = 134217728; public static final int TMSTARTRSCAN = 16777216; public + * static final int TMSUCCESS = 67108864; public static final int TMSUSPEND = 33554432; public static final int + * XA_RDONLY = 3; public static final int XA_OK = 0; */ /** - * Create a new XID + * Constructs a XidImpl. * * @param formatId - * format id + * format id * @param gtrid - * global id + * global id * @param bqual - * branch id + * branch id */ - public XidImpl(int formatId, - byte gtrid[], - byte bqual[]) { + public XidImpl(int formatId, byte gtrid[], byte bqual[]) { this.formatId = formatId; this.gtrid = gtrid; this.bqual = bqual; @@ -73,7 +70,7 @@ public int getFormatId() { } /** - * Used for tracing + * Returns trace id used for tracing. * * @return traceID string */ @@ -97,38 +94,43 @@ static String xidDisplay(Xid xid) { } + final class XAReturnValue { int nStatus; byte bData[]; } + /** - * SQLServerXAResource provides an XAResource for XA distributed transaction management. XA transactions are implemented over SQL Server using - * Microsoft Distributed Transaction Manager (DTC). SQLServerXAResource makes calls to a SQL Server extended dll called SQLServer_XA.dll which - * interfaces with DTC. + * Provides an XAResource for XA distributed transaction management. XA transactions are implemented over SQL Server + * using Microsoft Distributed Transaction Manager (DTC). SQLServerXAResource makes calls to a SQL Server extended dll + * called SQLServer_XA.dll which interfaces with DTC. * - * XA calls received by SQLServerXAResource (XA_START, XA_END, XA_PREPARE etc) are mapped to the corresponding calls to DTC functions. + * XA calls received by SQLServerXAResource (XA_START, XA_END, XA_PREPARE etc) are mapped to the corresponding calls to + * DTC functions. * - * SQLServerXAResource may also be configured not to use DTC. In this case distributed transactions are simply implemented as local transactions. + * SQLServerXAResource may also be configured not to use DTC. In this case distributed transactions are simply + * implemented as local transactions. */ - public final class SQLServerXAResource implements javax.transaction.xa.XAResource { /* - * In the Java transaction API doc a 'resource manager' appears to be (for JDBC) a 'particular DBMS server that participates in distributed - * transaction'. More accurately an instance of a connection to a database since commit/rollback is done at the DB connection level. A resource - * adapter is the implementation below + * In the Java transaction API doc a 'resource manager' appears to be (for JDBC) a 'particular DBMS server that + * participates in distributed transaction'. More accurately an instance of a connection to a database since + * commit/rollback is done at the DB connection level. A resource adapter is the implementation below */ /* - * In the JDBC XA spec the 'middle tier server' is the application server. We assume that this module implements the pooling of connections since - * it must also pass the XAResouce obtained when a connection is handed to an application to the transaction manager. IE JPoolingDataSource is not - * used - the JConnectionPoolDataSource and JPoolied connections are managed for pooling by the app server. + * In the JDBC XA spec the 'middle tier server' is the application server. We assume that this module implements the + * pooling of connections since it must also pass the XAResouce obtained when a connection is handed to an + * application to the transaction manager. IE JPoolingDataSource is not used - the JConnectionPoolDataSource and + * JPoolied connections are managed for pooling by the app server. */ /* Examples http://oradoc.photo.net/ora816/java.816/a81354/xadistr1.htm#1064452 */ /* - * Note that EJB componenents performing getConnection() may be using the same XAConnection/XAResource since it is a pooled connection + * Note that EJB componenents performing getConnection() may be using the same XAConnection/XAResource since it is a + * pooled connection */ private int timeoutSeconds; @@ -157,9 +159,10 @@ public final class SQLServerXAResource implements javax.transaction.xa.XAResourc private String sResourceManagerId; private int enlistedTransactionCount; final private Logger xaLogger; - static private final AtomicInteger baseResourceID = new AtomicInteger(0); // Unique id generator for each instance (used for logging). + static private final AtomicInteger baseResourceID = new AtomicInteger(0); // Unique id generator for each instance + // (used for logging). private int tightlyCoupled = 0; - private int isTransacrionTimeoutSet = 0; // set to 1 if setTransactionTimeout() is called + private int isTransacrionTimeoutSet = 0; // set to 1 if setTransactionTimeout() is called public static final int SSTRANSTIGHTLYCPLD = 0x8000; private SQLServerCallableStatement[] xaStatements = {null, null, null, null, null, null, null, null, null, null}; @@ -177,9 +180,7 @@ public String toString() { return traceID; } - SQLServerXAResource(SQLServerConnection original, - SQLServerConnection control, - String loginfo) { + SQLServerXAResource(SQLServerConnection original, SQLServerConnection control, String loginfo) { traceID = " XAResourceID:" + nextResourceID(); // Grab SQLServerXADataSource's static XA logger instance. xaLogger = SQLServerXADataSource.xaLogger; @@ -215,7 +216,8 @@ private synchronized SQLServerCallableStatement getXACallableStatementHandle(int switch (number) { case SQLServerXAResource.XA_START: - CS = controlConnection.prepareCall("{call master..xp_sqljdbc_xa_start(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)}"); + CS = controlConnection.prepareCall( + "{call master..xp_sqljdbc_xa_start(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)}"); break; case SQLServerXAResource.XA_END: CS = controlConnection.prepareCall("{call master..xp_sqljdbc_xa_end(?, ?, ?, ?, ?, ?, ?)}"); @@ -264,8 +266,7 @@ private synchronized void closeXAStatements() throws SQLServerException { final synchronized void close() throws SQLServerException { try { closeXAStatements(); - } - catch (Exception e) { + } catch (Exception e) { if (xaLogger.isLoggable(Level.WARNING)) xaLogger.warning(toString() + "Closing exception ignored: " + e); } @@ -359,13 +360,11 @@ private String typeDisplay(int type) { } - private XAReturnValue DTC_XA_Interface(int nType, - Xid xid, - int xaFlags) throws XAException { + private XAReturnValue DTC_XA_Interface(int nType, Xid xid, int xaFlags) throws XAException { if (xaLogger.isLoggable(Level.FINER)) - xaLogger.finer(toString() + " Calling XA function for type:" + typeDisplay(nType) + " flags:" + flagsDisplay(xaFlags) + " xid:" - + XidImpl.xidDisplay(xid)); + xaLogger.finer(toString() + " Calling XA function for type:" + typeDisplay(nType) + " flags:" + + flagsDisplay(xaFlags) + " xid:" + XidImpl.xidDisplay(xid)); int formatId = 0; byte gid[] = null; @@ -384,28 +383,28 @@ private XAReturnValue DTC_XA_Interface(int nType, SQLServerCallableStatement cs = null; try { synchronized (this) { - if (!xaInitDone) { + if (!xaInitDone) { try { synchronized (xaInitLock) { SQLServerCallableStatement initCS = null; - initCS = (SQLServerCallableStatement) controlConnection.prepareCall("{call master..xp_sqljdbc_xa_init_ex(?, ?,?)}"); + initCS = (SQLServerCallableStatement) controlConnection + .prepareCall("{call master..xp_sqljdbc_xa_init_ex(?, ?,?)}"); initCS.registerOutParameter(1, Types.INTEGER); // Return status - initCS.registerOutParameter(2, Types.CHAR); // Return error message - initCS.registerOutParameter(3, Types.CHAR); // Return version number + initCS.registerOutParameter(2, Types.CHAR); // Return error message + initCS.registerOutParameter(3, Types.CHAR); // Return version number try { initCS.execute(); - } - catch (SQLServerException eX) { + } catch (SQLServerException eX) { try { initCS.close(); // Mapping between control connection and xaresource is 1:1 controlConnection.close(); - } - catch (SQLException e3) { + } catch (SQLException e3) { // we really want to ignore this failue if (xaLogger.isLoggable(Level.FINER)) - xaLogger.finer(toString() + " Ignoring exception when closing failed execution. exception:" + e3); + xaLogger.finer(toString() + + " Ignoring exception when closing failed execution. exception:" + e3); } if (xaLogger.isLoggable(Level.FINER)) xaLogger.finer(toString() + " exception:" + eX); @@ -413,8 +412,9 @@ private XAReturnValue DTC_XA_Interface(int nType, } catch (SQLTimeoutException e4) { if (xaLogger.isLoggable(Level.FINER)) xaLogger.finer(toString() + " exception:" + e4); - throw new SQLServerException(e4.getMessage(), SQLState.STATEMENT_CANCELED, DriverError.NOT_SET, null); - } + throw new SQLServerException(e4.getMessage(), SQLState.STATEMENT_CANCELED, + DriverError.NOT_SET, null); + } // Check for error response from xp_sqljdbc_xa_init. int initStatus = initCS.getInt(1); @@ -427,7 +427,8 @@ private XAReturnValue DTC_XA_Interface(int nType, assert null != initErr && initErr.length() > 1; controlConnection.close(); - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_failedToInitializeXA")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_failedToInitializeXA")); Object[] msgArgs = {String.valueOf(initStatus), initErr}; XAException xex = new XAException(form.format(msgArgs)); xex.errorCode = initStatus; @@ -436,9 +437,9 @@ private XAReturnValue DTC_XA_Interface(int nType, throw xex; } } - } - catch (SQLServerException e1) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_failedToCreateXAConnection")); + } catch (SQLServerException e1) { + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_failedToCreateXAConnection")); Object[] msgArgs = {e1.getMessage()}; if (xaLogger.isLoggable(Level.FINER)) xaLogger.finer(toString() + " exception:" + form.format(msgArgs)); @@ -455,7 +456,8 @@ private XAReturnValue DTC_XA_Interface(int nType, Statement stmt = null; try { serverInfoRetrieved = true; - // data are converted to varchar as type variant returned by SERVERPROPERTY is not supported by driver + // data are converted to varchar as type variant returned by SERVERPROPERTY is not supported + // by driver String query = "select convert(varchar(100), SERVERPROPERTY('Edition'))as edition, " + " convert(varchar(100), SERVERPROPERTY('InstanceName'))as instance," + " convert(varchar(100), SERVERPROPERTY('ProductVersion')) as version," @@ -473,12 +475,12 @@ private XAReturnValue DTC_XA_Interface(int nType, version = rs.getString(3); if (null == version) { version = "0"; - } - else if (-1 != version.indexOf('.')) { + } else if (-1 != version.indexOf('.')) { version = version.substring(0, version.indexOf('.')); } - // @@VERSION returns single nvarchar string with SQL version, architecture, build date, edition and OS version + // @@VERSION returns single nvarchar string with SQL version, architecture, build date, + // edition and OS version // Version of the OS running MS SQL is retrieved as substring ArchitectureOS = Integer.parseInt(rs.getString(4)); @@ -488,14 +490,13 @@ else if (-1 != version.indexOf('.')) { // run time exceptions. catch (Exception e) { if (xaLogger.isLoggable(Level.WARNING)) - xaLogger.warning(toString() + " Cannot retrieve server information: :" + e.getMessage()); - } - finally { + xaLogger.warning( + toString() + " Cannot retrieve server information: :" + e.getMessage()); + } finally { if (null != stmt) try { stmt.close(); - } - catch (SQLException e) { + } catch (SQLException e) { if (xaLogger.isLoggable(Level.FINER)) xaLogger.finer(toString()); } @@ -504,22 +505,22 @@ else if (-1 != version.indexOf('.')) { sContext = "START:"; cs = getXACallableStatementHandle(XA_START); - cs.registerOutParameter(n++, Types.INTEGER); // Return status - cs.registerOutParameter(n++, Types.CHAR); // Return error message - cs.setBytes(n++, gid); // Global XID - cs.setBytes(n++, bid); // Branch ID - cs.setInt(n++, xaFlags); // XA transaction flags - cs.registerOutParameter(n++, Types.BINARY); // Returned OLE transaction cookie - cs.setInt(n++, timeoutSeconds); // Transaction timeout in seconds. - cs.setInt(n++, formatId); // Format ID - cs.registerOutParameter(n++, Types.CHAR); // DLL Version number - cs.setInt(n++, Integer.parseInt(version)); // Version of SQL Server - cs.setInt(n++, instanceName.length()); // Length of SQL Server instance name - cs.setBytes(n++, instanceName.getBytes()); // SQL Server instance name - cs.setInt(n++, ArchitectureMSSQL); // Architecture of SQL Server - cs.setInt(n++, ArchitectureOS); // Architecture of OS running SQL Server - cs.setInt(n++, isTransacrionTimeoutSet); // pass 1 if setTransactionTimeout() is called - cs.registerOutParameter(n++, Types.BINARY); // Return UoW + cs.registerOutParameter(n++, Types.INTEGER); // Return status + cs.registerOutParameter(n++, Types.CHAR); // Return error message + cs.setBytes(n++, gid); // Global XID + cs.setBytes(n++, bid); // Branch ID + cs.setInt(n++, xaFlags); // XA transaction flags + cs.registerOutParameter(n++, Types.BINARY); // Returned OLE transaction cookie + cs.setInt(n++, timeoutSeconds); // Transaction timeout in seconds. + cs.setInt(n++, formatId); // Format ID + cs.registerOutParameter(n++, Types.CHAR); // DLL Version number + cs.setInt(n++, Integer.parseInt(version)); // Version of SQL Server + cs.setInt(n++, instanceName.length()); // Length of SQL Server instance name + cs.setBytes(n++, instanceName.getBytes()); // SQL Server instance name + cs.setInt(n++, ArchitectureMSSQL); // Architecture of SQL Server + cs.setInt(n++, ArchitectureOS); // Architecture of OS running SQL Server + cs.setInt(n++, isTransacrionTimeoutSet); // pass 1 if setTransactionTimeout() is called + cs.registerOutParameter(n++, Types.BINARY); // Return UoW break; @@ -532,7 +533,7 @@ else if (-1 != version.indexOf('.')) { cs.setBytes(n++, bid); cs.setInt(n++, xaFlags); cs.setInt(n++, formatId); - cs.registerOutParameter(n++, Types.BINARY); // Return UoW + cs.registerOutParameter(n++, Types.BINARY); // Return UoW break; case XA_PREPARE: @@ -547,8 +548,8 @@ else if (-1 != version.indexOf('.')) { cs.setBytes(n++, gid); cs.setBytes(n++, bid); if ((SSTRANSTIGHTLYCPLD & xaFlags) == SSTRANSTIGHTLYCPLD) - cs.setInt(n++, xaFlags); // XA transaction flags - cs.setInt(n++, formatId); // Format ID n=5 for loosely coupled, n=6 for tightly coupled + cs.setInt(n++, xaFlags); // XA transaction flags + cs.setInt(n++, formatId); // Format ID n=5 for loosely coupled, n=6 for tightly coupled break; case XA_COMMIT: @@ -574,8 +575,8 @@ else if (-1 != version.indexOf('.')) { cs.setBytes(n++, gid); cs.setBytes(n++, bid); if ((SSTRANSTIGHTLYCPLD & xaFlags) == SSTRANSTIGHTLYCPLD) - cs.setInt(n++, xaFlags); // XA transaction flags - cs.setInt(n++, formatId); // Format ID n=5 for loosely coupled, n=6 for tightly coupled + cs.setInt(n++, xaFlags); // XA transaction flags + cs.setInt(n++, formatId); // Format ID n=5 for loosely coupled, n=6 for tightly coupled break; case XA_FORGET: @@ -589,8 +590,8 @@ else if (-1 != version.indexOf('.')) { cs.setBytes(n++, gid); cs.setBytes(n++, bid); if ((SSTRANSTIGHTLYCPLD & xaFlags) == SSTRANSTIGHTLYCPLD) - cs.setInt(n++, xaFlags); // XA transaction flags - cs.setInt(n++, formatId); // Format ID n=5 for loosely coupled, n=6 for tightly coupled + cs.setInt(n++, xaFlags); // XA transaction flags + cs.setInt(n++, formatId); // Format ID n=5 for loosely coupled, n=6 for tightly coupled break; case XA_RECOVER: @@ -623,8 +624,8 @@ else if (-1 != version.indexOf('.')) { strBuf.insert(16, '-'); strBuf.insert(12, '-'); strBuf.insert(8, '-'); - xaLogger.fine(toString() + " XID to UoW mapping for XA type:XA_START XID: " + XidImpl.xidDisplay(xid) + " UoW: " - + strBuf.toString()); + xaLogger.fine(toString() + " XID to UoW mapping for XA type:XA_START XID: " + + XidImpl.xidDisplay(xid) + " UoW: " + strBuf.toString()); } } } @@ -636,22 +637,25 @@ else if (-1 != version.indexOf('.')) { strBuf.insert(16, '-'); strBuf.insert(12, '-'); strBuf.insert(8, '-'); - xaLogger.fine( - toString() + " XID to UoW mapping for XA type:XA_END XID: " + XidImpl.xidDisplay(xid) + " UoW: " + strBuf.toString()); + xaLogger.fine(toString() + " XID to UoW mapping for XA type:XA_END XID: " + + XidImpl.xidDisplay(xid) + " UoW: " + strBuf.toString()); } } } if (XA_RECOVER == nType && XA_OK != nStatus && recoveryAttempt < 1) { - // if recover failed, attempt to start again - adding the variable to check to attempt only once otherwise throw exception that recovery fails - // this is added since before this change, if we restart the MSDTC and attempt to do recovery, driver will throw exception - //"The function RECOVER: failed. The status is: -3" + // if recover failed, attempt to start again - adding the variable to check to attempt only once + // otherwise throw exception that recovery fails + // this is added since before this change, if we restart the MSDTC and attempt to do recovery, driver + // will throw exception + // "The function RECOVER: failed. The status is: -3" recoveryAttempt++; DTC_XA_Interface(XA_START, xid, TMNOFLAGS); return DTC_XA_Interface(XA_RECOVER, xid, xaFlags); } // prepare and end can return XA_RDONLY // Think should we just check for nStatus to be greater than or equal to zero instead of this check - if (((XA_RDONLY == nStatus) && (XA_END != nType && XA_PREPARE != nType)) || (XA_OK != nStatus && XA_RDONLY != nStatus)) { + if (((XA_RDONLY == nStatus) && (XA_END != nType && XA_PREPARE != nType)) + || (XA_OK != nStatus && XA_RDONLY != nStatus)) { assert (null != sErr) && (sErr.length() > 1); MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_failedFunctionXA")); Object[] msgArgs = {sContext, String.valueOf(nStatus), sErr}; @@ -666,37 +670,35 @@ else if (-1 != version.indexOf('.')) { enlistedTransactionCount--; if (xaLogger.isLoggable(Level.FINER)) xaLogger.finer(toString() + " End un-enlist, enlisted count:" + enlistedTransactionCount); - } - catch (SQLServerException e1) { + } catch (SQLServerException e1) { // ignore this message as the previous error message is more important. if (xaLogger.isLoggable(Level.FINER)) xaLogger.finer(toString() + " Ignoring exception:" + e1); } } throw e; - } - else { + } else { if (nType == XA_START) { // A physical connection may not have been enlisted yet so always enlist. byte transactionCookie[] = cs.getBytes(6); if (transactionCookie == null) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_noTransactionCookie")); + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_noTransactionCookie")); Object[] msgArgs = {sContext}; SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), null, true); - } - else { + } else { try { if (xaLogger.isLoggable(Level.FINER)) - xaLogger.finer(toString() + " Begin enlisting, cookie:" + cookieDisplay(transactionCookie) + " enlisted count:" - + enlistedTransactionCount); + xaLogger.finer( + toString() + " Begin enlisting, cookie:" + cookieDisplay(transactionCookie) + + " enlisted count:" + enlistedTransactionCount); con.JTAEnlistConnection(transactionCookie); enlistedTransactionCount++; if (xaLogger.isLoggable(Level.FINER)) - xaLogger.finer(toString() + " End enlisting, cookie:" + cookieDisplay(transactionCookie) + " enlisted count:" - + enlistedTransactionCount); - } - catch (SQLServerException e1) { + xaLogger.finer(toString() + " End enlisting, cookie:" + cookieDisplay(transactionCookie) + + " enlisted count:" + enlistedTransactionCount); + } catch (SQLServerException e1) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_failedToEnlist")); Object[] msgArgs = {e1.getMessage()}; SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), null, true); @@ -711,8 +713,7 @@ else if (-1 != version.indexOf('.')) { enlistedTransactionCount--; if (xaLogger.isLoggable(Level.FINER)) xaLogger.finer(toString() + " End un-enlist, enlisted count:" + enlistedTransactionCount); - } - catch (SQLServerException e1) { + } catch (SQLServerException e1) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_failedToUnEnlist")); Object[] msgArgs = {e1.getMessage()}; SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), null, true); @@ -723,16 +724,15 @@ else if (-1 != version.indexOf('.')) { { try { returnStatus.bData = cs.getBytes(4); - } - catch (SQLServerException e1) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_failedToReadRecoveryXIDs")); + } catch (SQLServerException e1) { + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_failedToReadRecoveryXIDs")); Object[] msgArgs = {e1.getMessage()}; SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), null, true); } } } - } - catch (SQLServerException | SQLTimeoutException ex) { + } catch (SQLServerException | SQLTimeoutException ex) { if (xaLogger.isLoggable(Level.FINER)) xaLogger.finer(toString() + " exception:" + ex); XAException e = new XAException(ex.toString()); @@ -748,21 +748,20 @@ else if (-1 != version.indexOf('.')) { } @Override - public void start(Xid xid, - int flags) throws XAException { + public void start(Xid xid, int flags) throws XAException { /* - * Transaction mgr will use this resource in the global transaction. After this call the app server will call getConnection() to get a - * connection to give the application - * - * The xid holds the global transaction id + the transaction branch id. The getGlobalTransactionId should be the same for each call until the - * transaction is committed + * Transaction mgr will use this resource in the global transaction. After this call the app server will call + * getConnection() to get a connection to give the application The xid holds the global transaction id + the + * transaction branch id. The getGlobalTransactionId should be the same for each call until the transaction is + * committed */ /* - * XA API DOC : Start work on behalf of a transaction branch specified in xid If TMJOIN is specified, the start is for joining a transaction - * previously seen by the resource manager. If TMRESUME is specified, the start is to resume a suspended transaction specified in the - * parameter xid. If neither TMJOIN nor TMRESUME is specified and the transaction specified by xid has previously been seen by the resource - * manager, the resource manager throws the XAException exception with XAER_DUPID error code. + * XA API DOC : Start work on behalf of a transaction branch specified in xid If TMJOIN is specified, the start + * is for joining a transaction previously seen by the resource manager. If TMRESUME is specified, the start is + * to resume a suspended transaction specified in the parameter xid. If neither TMJOIN nor TMRESUME is specified + * and the transaction specified by xid has previously been seen by the resource manager, the resource manager + * throws the XAException exception with XAER_DUPID error code. */ // TMNOFLAGS indicates this is the first time this physical connection has seen the transaction. @@ -774,16 +773,16 @@ public void start(Xid xid, } @Override - public void end(Xid xid, - int flags) throws XAException { + public void end(Xid xid, int flags) throws XAException { // Called by the transaction mgr after the app closes the connection it was given from this physical // connection /* - * Ends the work performed on behalf of a transaction branch. The resource manager disassociates the XA resource from the transaction branch - * specified and let the transaction be completed. If TMSUSPEND is specified in flags, the transaction branch is temporarily suspended in - * incomplete state. The transaction context is in suspened state and must be resumed via start with TMRESUME specified. If TMFAIL is - * specified, the portion of work has failed. The resource manager may mark the transaction as rollback-only. If TMSUCCESS is specified, the - * portion of work has completed successfully. + * Ends the work performed on behalf of a transaction branch. The resource manager disassociates the XA resource + * from the transaction branch specified and let the transaction be completed. If TMSUSPEND is specified in + * flags, the transaction branch is temporarily suspended in incomplete state. The transaction context is in + * suspened state and must be resumed via start with TMRESUME specified. If TMFAIL is specified, the portion of + * work has failed. The resource manager may mark the transaction as rollback-only. If TMSUCCESS is specified, + * the portion of work has completed successfully. */ DTC_XA_Interface(XA_END, xid, flags | tightlyCoupled); } @@ -791,10 +790,10 @@ public void end(Xid xid, @Override public int prepare(Xid xid) throws XAException { /* - * Ask the resource manager to prepare for a transaction commit of the transaction specified in xid. Parameters: xid - A global transaction - * identifier Returns: A value indicating the resource manager's vote on the outcome of the transaction. The possible values are: XA_RDONLY or - * XA_OK. If the resource manager wants to roll back the transaction, it should do so by raising an appropriate XAException in the prepare - * method. + * Ask the resource manager to prepare for a transaction commit of the transaction specified in xid. Parameters: + * xid - A global transaction identifier Returns: A value indicating the resource manager's vote on the outcome + * of the transaction. The possible values are: XA_RDONLY or XA_OK. If the resource manager wants to roll back + * the transaction, it should do so by raising an appropriate XAException in the prepare method. */ int nStatus = XA_OK; XAReturnValue r = DTC_XA_Interface(XA_PREPARE, xid, tightlyCoupled); @@ -804,8 +803,7 @@ public int prepare(Xid xid) throws XAException { } @Override - public void commit(Xid xid, - boolean onePhase) throws XAException { + public void commit(Xid xid, boolean onePhase) throws XAException { DTC_XA_Interface(XA_COMMIT, xid, ((onePhase) ? TMONEPHASE : TMNOFLAGS) | tightlyCoupled); } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SSPIAuthentication.java b/src/main/java/com/microsoft/sqlserver/jdbc/SSPIAuthentication.java index db1a41d76..1fb0f34d3 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SSPIAuthentication.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SSPIAuthentication.java @@ -1,20 +1,16 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -/** - * Integrated Authentication master file. Common items for kerb and JNI auth are in this interface. - */ - -abstract class SSPIAuthentication { - abstract byte[] GenerateClientContext(byte[] pin, - boolean[] done) throws SQLServerException; - - abstract int ReleaseClientContext() throws SQLServerException; -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +/** + * Integrated Authentication master file. Common items for kerb and JNI auth are in this interface. + */ + +abstract class SSPIAuthentication { + abstract byte[] GenerateClientContext(byte[] pin, boolean[] done) throws SQLServerException; + + abstract int ReleaseClientContext() throws SQLServerException; +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ScrollWindow.java b/src/main/java/com/microsoft/sqlserver/jdbc/ScrollWindow.java index 9ede34c68..3ae4f6053 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ScrollWindow.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ScrollWindow.java @@ -1,208 +1,206 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -/** - * ScrollWindow provides an efficient way to scroll around within a limited number of rows, typically the ResultSet fetch size, by saving and - * restoring row state, such as starting point in the response and updated/deleted status, on movement within the window. - * - * Without a scroll window, scrolling backward through a result set would be very costly, requiring reindexing the fetch buffer up to row N-1 for each - * move to the previous row. - */ -final class ScrollWindow { - /** Set of marks for the rows in the window */ - private TDSReaderMark[] rowMark; - - /** Set of flags indicating which rows have been updated through the ResultSet */ - private boolean[] updatedRow; - - /** Set of flags indicating which rows have been deleted through the ResultSet */ - private boolean[] deletedRow; - - /** Set of enums indicating the types of rows in a ResultSet */ - private RowType[] rowType; - - /** Size (in rows) of this scroll window */ - private int size = 0; - - /** Max number of rows in the window (less than or equal to size) */ - private int maxRows = 0; - - final int getMaxRows() { - return maxRows; - } - - /** Current row in the window (1-indexed) */ - private int currentRow; - - final int getRow() { - return currentRow; - } - - ScrollWindow(int size) { - setSize(size); - reset(); - } - - private void setSize(int size) { - assert this.size != size; - this.size = size; - this.maxRows = size; - this.rowMark = new TDSReaderMark[size]; - this.updatedRow = new boolean[size]; - this.deletedRow = new boolean[size]; - this.rowType = new RowType[size]; - for (int i = 0; i < size; i++) { - rowType[i] = RowType.UNKNOWN; - } - } - - final void clear() { - for (int i = 0; i < rowMark.length; ++i) { - rowMark[i] = null; - updatedRow[i] = false; - deletedRow[i] = false; - rowType[i] = RowType.UNKNOWN; - } - - assert size > 0; - maxRows = size; - reset(); - } - - final void reset() { - currentRow = 0; - } - - final void resize(int newSize) { - assert newSize > 0; - if (newSize != size) - setSize(newSize); - } - - final String logCursorState() { - return " currentRow:" + currentRow + " maxRows:" + maxRows; - } - - final boolean next(SQLServerResultSet rs) throws SQLServerException { - if (SQLServerResultSet.logger.isLoggable(java.util.logging.Level.FINER)) - SQLServerResultSet.logger.finer(rs.toString() + logCursorState()); - - // Precondition: - // Current position should always be on a row in the window or - // just before the first row or just after the last row. - assert 0 <= currentRow && currentRow <= maxRows + 1; - - // If the position is already beyond the end of the window, - // then it can move no farther forward. - if (maxRows + 1 == currentRow) - return false; - - // Otherwise, we are going to attempt to move the current - // position to the next row. First, save off the row - // updated/deleted status for the current row so it - // can be restored later if we ever move to this row again. - if (currentRow >= 1) { - updatedRow[currentRow - 1] = rs.getUpdatedCurrentRow(); - deletedRow[currentRow - 1] = rs.getDeletedCurrentRow(); - rowType[currentRow - 1] = rs.getCurrentRowType(); - } - - // Start on the next row - ++currentRow; - - // If we were on the last row of the window then make sure - // the move past the last row consumes the remainder of that - // row from the fetch buffer. The fetch buffer should be - // left pointing beyond the last row of the window, which - // is most likely the end of the fetch buffer as well. - if (maxRows + 1 == currentRow) { - rs.fetchBufferNext(); - return false; - } - - // We weren't on the last row of the window. If we already - // know that there was another row in the fetch buffer, - // then restore the response buffer position and updated/deleted - // status for the new row. - if (null != rowMark[currentRow - 1]) { - rs.fetchBufferReset(rowMark[currentRow - 1]); - rs.setCurrentRowType(rowType[currentRow - 1]); - rs.setUpdatedCurrentRow(updatedRow[currentRow - 1]); - rs.setDeletedCurrentRow(deletedRow[currentRow - 1]); - return true; - } - - // We weren't on the last row of the window and we don't - // know whether there are additional rows in the fetch - // buffer, so try to read another row now. If we find - // one then keep track of its position in the response - // buffer. - if (rs.fetchBufferNext()) { - rowMark[currentRow - 1] = rs.fetchBufferMark(); - rowType[currentRow - 1] = rs.getCurrentRowType(); - - if (SQLServerResultSet.logger.isLoggable(java.util.logging.Level.FINEST)) - SQLServerResultSet.logger.finest( - rs.toString() + " Set mark " + rowMark[currentRow - 1] + " for row " + currentRow + " of type " + rowType[currentRow - 1]); - - return true; - } - - // We weren't on the last row of the window and we now - // know that there are no more rows in the fetch buffer, - // so adjust maxRows down accordingly. - maxRows = currentRow - 1; - return false; - } - - final void previous(SQLServerResultSet rs) throws SQLServerException { - if (SQLServerResultSet.logger.isLoggable(java.util.logging.Level.FINER)) - SQLServerResultSet.logger.finer(rs.toString() + logCursorState()); - - // Precondition: - // Current position should always be on a row in the window or - // just before the first row or just after the last row. - assert 0 <= currentRow && currentRow <= maxRows + 1; - - // If the position is already before the start of the window, - // then it can move no farther back. - if (0 == currentRow) - return; - - // Otherwise, we are going to attempt to move the current - // position to the previous row. First, save off the row - // updated/deleted status for the current row so it - // can be restored later if we ever move to this row again. - if (currentRow <= maxRows) { - assert currentRow >= 1; - updatedRow[currentRow - 1] = rs.getUpdatedCurrentRow(); - deletedRow[currentRow - 1] = rs.getDeletedCurrentRow(); - rowType[currentRow - 1] = rs.getCurrentRowType(); - } - - // Start on the previous row - --currentRow; - - // If we were on the first row of the window before moving, - // then we're now before the first row and we're done. - if (0 == currentRow) - return; - - // If we weren't on the first row before moving then we - // are now on the previous row. Restore the saved - // position in the response buffer and updated/deleted - // state for the now current row. - assert null != rowMark[currentRow - 1]; - rs.fetchBufferReset(rowMark[currentRow - 1]); - rs.setCurrentRowType(rowType[currentRow - 1]); - rs.setUpdatedCurrentRow(updatedRow[currentRow - 1]); - rs.setDeletedCurrentRow(deletedRow[currentRow - 1]); - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +/** + * ScrollWindow provides an efficient way to scroll around within a limited number of rows, typically the ResultSet + * fetch size, by saving and restoring row state, such as starting point in the response and updated/deleted status, on + * movement within the window. + * + * Without a scroll window, scrolling backward through a result set would be very costly, requiring reindexing the fetch + * buffer up to row N-1 for each move to the previous row. + */ +final class ScrollWindow { + /** Set of marks for the rows in the window */ + private TDSReaderMark[] rowMark; + + /** Set of flags indicating which rows have been updated through the ResultSet */ + private boolean[] updatedRow; + + /** Set of flags indicating which rows have been deleted through the ResultSet */ + private boolean[] deletedRow; + + /** Set of enums indicating the types of rows in a ResultSet */ + private RowType[] rowType; + + /** Size (in rows) of this scroll window */ + private int size = 0; + + /** Max number of rows in the window (less than or equal to size) */ + private int maxRows = 0; + + final int getMaxRows() { + return maxRows; + } + + /** Current row in the window (1-indexed) */ + private int currentRow; + + final int getRow() { + return currentRow; + } + + ScrollWindow(int size) { + setSize(size); + reset(); + } + + private void setSize(int size) { + assert this.size != size; + this.size = size; + this.maxRows = size; + this.rowMark = new TDSReaderMark[size]; + this.updatedRow = new boolean[size]; + this.deletedRow = new boolean[size]; + this.rowType = new RowType[size]; + for (int i = 0; i < size; i++) { + rowType[i] = RowType.UNKNOWN; + } + } + + final void clear() { + for (int i = 0; i < rowMark.length; ++i) { + rowMark[i] = null; + updatedRow[i] = false; + deletedRow[i] = false; + rowType[i] = RowType.UNKNOWN; + } + + assert size > 0; + maxRows = size; + reset(); + } + + final void reset() { + currentRow = 0; + } + + final void resize(int newSize) { + assert newSize > 0; + if (newSize != size) + setSize(newSize); + } + + final String logCursorState() { + return " currentRow:" + currentRow + " maxRows:" + maxRows; + } + + final boolean next(SQLServerResultSet rs) throws SQLServerException { + if (SQLServerResultSet.logger.isLoggable(java.util.logging.Level.FINER)) + SQLServerResultSet.logger.finer(rs.toString() + logCursorState()); + + // Precondition: + // Current position should always be on a row in the window or + // just before the first row or just after the last row. + assert 0 <= currentRow && currentRow <= maxRows + 1; + + // If the position is already beyond the end of the window, + // then it can move no farther forward. + if (maxRows + 1 == currentRow) + return false; + + // Otherwise, we are going to attempt to move the current + // position to the next row. First, save off the row + // updated/deleted status for the current row so it + // can be restored later if we ever move to this row again. + if (currentRow >= 1) { + updatedRow[currentRow - 1] = rs.getUpdatedCurrentRow(); + deletedRow[currentRow - 1] = rs.getDeletedCurrentRow(); + rowType[currentRow - 1] = rs.getCurrentRowType(); + } + + // Start on the next row + ++currentRow; + + // If we were on the last row of the window then make sure + // the move past the last row consumes the remainder of that + // row from the fetch buffer. The fetch buffer should be + // left pointing beyond the last row of the window, which + // is most likely the end of the fetch buffer as well. + if (maxRows + 1 == currentRow) { + rs.fetchBufferNext(); + return false; + } + + // We weren't on the last row of the window. If we already + // know that there was another row in the fetch buffer, + // then restore the response buffer position and updated/deleted + // status for the new row. + if (null != rowMark[currentRow - 1]) { + rs.fetchBufferReset(rowMark[currentRow - 1]); + rs.setCurrentRowType(rowType[currentRow - 1]); + rs.setUpdatedCurrentRow(updatedRow[currentRow - 1]); + rs.setDeletedCurrentRow(deletedRow[currentRow - 1]); + return true; + } + + // We weren't on the last row of the window and we don't + // know whether there are additional rows in the fetch + // buffer, so try to read another row now. If we find + // one then keep track of its position in the response + // buffer. + if (rs.fetchBufferNext()) { + rowMark[currentRow - 1] = rs.fetchBufferMark(); + rowType[currentRow - 1] = rs.getCurrentRowType(); + + if (SQLServerResultSet.logger.isLoggable(java.util.logging.Level.FINEST)) + SQLServerResultSet.logger.finest(rs.toString() + " Set mark " + rowMark[currentRow - 1] + " for row " + + currentRow + " of type " + rowType[currentRow - 1]); + + return true; + } + + // We weren't on the last row of the window and we now + // know that there are no more rows in the fetch buffer, + // so adjust maxRows down accordingly. + maxRows = currentRow - 1; + return false; + } + + final void previous(SQLServerResultSet rs) throws SQLServerException { + if (SQLServerResultSet.logger.isLoggable(java.util.logging.Level.FINER)) + SQLServerResultSet.logger.finer(rs.toString() + logCursorState()); + + // Precondition: + // Current position should always be on a row in the window or + // just before the first row or just after the last row. + assert 0 <= currentRow && currentRow <= maxRows + 1; + + // If the position is already before the start of the window, + // then it can move no farther back. + if (0 == currentRow) + return; + + // Otherwise, we are going to attempt to move the current + // position to the previous row. First, save off the row + // updated/deleted status for the current row so it + // can be restored later if we ever move to this row again. + if (currentRow <= maxRows) { + assert currentRow >= 1; + updatedRow[currentRow - 1] = rs.getUpdatedCurrentRow(); + deletedRow[currentRow - 1] = rs.getDeletedCurrentRow(); + rowType[currentRow - 1] = rs.getCurrentRowType(); + } + + // Start on the previous row + --currentRow; + + // If we were on the first row of the window before moving, + // then we're now before the first row and we're done. + if (0 == currentRow) + return; + + // If we weren't on the first row before moving then we + // are now on the previous row. Restore the saved + // position in the response buffer and updated/deleted + // state for the now current row. + assert null != rowMark[currentRow - 1]; + rs.fetchBufferReset(rowMark[currentRow - 1]); + rs.setCurrentRowType(rowType[currentRow - 1]); + rs.setUpdatedCurrentRow(updatedRow[currentRow - 1]); + rs.setDeletedCurrentRow(deletedRow[currentRow - 1]); + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SimpleInputStream.java b/src/main/java/com/microsoft/sqlserver/jdbc/SimpleInputStream.java index 917ebca00..2135858c1 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SimpleInputStream.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SimpleInputStream.java @@ -1,372 +1,361 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -import java.io.IOException; -import java.io.InputStream; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * SimpleInputStream is an InputStream implementation that reads from TDS. - * - * This class is to support adaptive streaming of non plp aka simple byte types char, byte etc. - * - */ -abstract class BaseInputStream extends InputStream { - abstract byte[] getBytes() throws SQLServerException; - - // Flag indicating whether the stream conforms to adaptive response buffering API restrictions - final boolean isAdaptive; - - // Flag indicating whether the stream consumes and discards data as it reads it - final boolean isStreaming; - - /** Generate the logging ID */ - private String parentLoggingInfo = ""; - private static final AtomicInteger lastLoggingID = new AtomicInteger(0); - - private static int nextLoggingID() { - return lastLoggingID.incrementAndGet(); - } - - static final java.util.logging.Logger logger = java.util.logging.Logger.getLogger("com.microsoft.sqlserver.jdbc.internals.InputStream");; - private String traceID; - - final public String toString() { - if (traceID == null) - traceID = getClass().getName() + "ID:" + nextLoggingID(); - return traceID; - } - - final void setLoggingInfo(String info) { - parentLoggingInfo = info; - if (logger.isLoggable(java.util.logging.Level.FINER)) - logger.finer(toString()); - } - - int streamPos = 0; - int markedStreamPos = 0; - TDSReaderMark currentMark; - private ServerDTVImpl dtv; - TDSReader tdsReader; - int readLimit = 0; - boolean isReadLimitSet = false; - - BaseInputStream(TDSReader tdsReader, - boolean isAdaptive, - boolean isStreaming, - ServerDTVImpl dtv) { - this.tdsReader = tdsReader; - this.isAdaptive = isAdaptive; - this.isStreaming = isStreaming; - - if (isAdaptive) - clearCurrentMark(); - else - currentMark = tdsReader.mark(); - this.dtv = dtv; - } - - final void clearCurrentMark() { - currentMark = null; - isReadLimitSet = false; - if (isAdaptive && isStreaming) - tdsReader.stream(); - } - - void closeHelper() throws IOException { - if (isAdaptive && null != dtv) { - if (logger.isLoggable(java.util.logging.Level.FINER)) - logger.finer(toString() + " closing the adaptive stream."); - dtv.setPositionAfterStreamed(tdsReader); - } - currentMark = null; - tdsReader = null; - dtv = null; - } - - /** - * Verifies stream is open and throws IOException if otherwise. - */ - final void checkClosed() throws IOException { - if (null == tdsReader) - throw new IOException(SQLServerException.getErrString("R_streamIsClosed")); - } - - /** - * Tests if this input stream supports the mark and reset methods. - * - * @return true if mark and reset are supported. - */ - public boolean markSupported() { - return true; - } - - void setReadLimit(int readLimit) { - // we buffer the whole stream in the full case so readlimit is meaningless. - // spec does not say what to do with -ve values. - if (isAdaptive && readLimit > 0) { - this.readLimit = readLimit; - isReadLimitSet = true; - } - } - - /** - * Resets stream to saved mark position. - * - * @exception IOException - * if an I/O error occurs. - */ - void resetHelper() throws IOException { - checkClosed(); - // if no mark set already throw - if (null == currentMark) - throw new IOException(SQLServerException.getErrString("R_streamWasNotMarkedBefore")); - tdsReader.reset(currentMark); - } -} - -final class SimpleInputStream extends BaseInputStream { - - // Stated length of the payload - private final int payloadLength; - - /** - * Initializes the input stream. - */ - SimpleInputStream(TDSReader tdsReader, - int payLoadLength, - InputStreamGetterArgs getterArgs, - ServerDTVImpl dtv) throws SQLServerException { - super(tdsReader, getterArgs.isAdaptive, getterArgs.isStreaming, dtv); - setLoggingInfo(getterArgs.logContext); - this.payloadLength = payLoadLength; - } - - /** - * Closes the stream releasing all resources held. - * - * @exception IOException - * if an I/O error occurs. - */ - public void close() throws IOException { - if (null == tdsReader) - return; - if (logger.isLoggable(java.util.logging.Level.FINER)) - logger.finer(toString() + "Enter Closing SimpleInputStream."); - - // Discard the remainder of the stream, positioning the TDSReader - // at the next item in the TDS response. Once the stream is closed, - // it can no longer access the discarded response data. - skip(payloadLength - streamPos); - - closeHelper(); - if (logger.isLoggable(java.util.logging.Level.FINER)) - logger.finer(toString() + "Exit Closing SimpleInputStream."); - } - - /** - * Checks if we have EOS state. - * - * @exception IOException - * if an I/O error occurs. - */ - private boolean isEOS() throws IOException { - assert streamPos <= payloadLength; - return (streamPos == payloadLength); - } - - // java.io.InputStream interface methods. - - /** - * Skips over and discards n bytes of data from this input stream. - * - * @param n - * the number of bytes to be skipped. - * @return the actual number of bytes skipped. - * @exception IOException - * if an I/O error occurs. - */ - public long skip(long n) throws IOException { - checkClosed(); - if (logger.isLoggable(java.util.logging.Level.FINER)) - logger.finer(toString() + " Skipping :" + n); - if (n < 0) - return 0L; - if (isEOS()) - return 0; - - int skipAmount; - if (streamPos + n > payloadLength) { - skipAmount = payloadLength - streamPos; - } - else { - skipAmount = (int) n; - } - try { - tdsReader.skip(skipAmount); - } - catch (SQLServerException e) { - throw new IOException(e.getMessage()); - } - streamPos += skipAmount; - if (isReadLimitSet && ((streamPos - markedStreamPos) > readLimit)) - clearCurrentMark(); - - return skipAmount; - - } - - /** - * Returns the number of bytes that can be read (or skipped over) from this input stream without blocking by the next caller of a method for this - * input stream. - * - * @return the actual number of bytes available. - * @exception IOException - * if an I/O error occurs. - */ - public int available() throws IOException { - checkClosed(); - assert streamPos <= payloadLength; - - int available = payloadLength - streamPos; - if (tdsReader.available() < available) - available = tdsReader.available(); - return available; - } - - private byte[] bSingleByte; - - /** - * Reads the next byte of data from the input stream. - * - * @return the byte read or -1 meaning no more bytes. - * @exception IOException - * if an I/O error occurs. - */ - public int read() throws IOException { - checkClosed(); - if (null == bSingleByte) - bSingleByte = new byte[1]; - if (isEOS()) - return -1; - int bytesRead = read(bSingleByte, 0, 1); - return (0 == bytesRead) ? -1 : (bSingleByte[0] & 0xFF); - } - - /** - * Reads available data into supplied byte array. - * - * @param b - * array of bytes to fill. - * @return the number of bytes read or -1 meaning no bytes read. - * @exception IOException - * if an I/O error occurs. - */ - public int read(byte[] b) throws IOException { - checkClosed(); - return read(b, 0, b.length); - } - - /** - * Reads available data into supplied byte array. - * - * @param b - * array of bytes to fill. - * @param offset - * the offset into array b where to start writing. - * @param maxBytes - * the max number of bytes to write into b. - * @return the number of bytes read or -1 meaning no bytes read. - * @exception IOException - * if an I/O error occurs. - */ - public int read(byte b[], - int offset, - int maxBytes) throws IOException { - checkClosed(); - if (logger.isLoggable(java.util.logging.Level.FINER)) - logger.finer(toString() + " Reading " + maxBytes + " from stream offset " + streamPos + " payload length " + payloadLength); - - if (offset < 0 || maxBytes < 0 || offset + maxBytes > b.length) - throw new IndexOutOfBoundsException(); - - if (0 == maxBytes) - return 0; - if (isEOS()) - return -1; - - int readAmount; - if (streamPos + maxBytes > payloadLength) { - readAmount = payloadLength - streamPos; - } - else { - readAmount = maxBytes; - } - - try { - tdsReader.readBytes(b, offset, readAmount); - } - catch (SQLServerException e) { - throw new IOException(e.getMessage()); - } - streamPos += readAmount; - - if (isReadLimitSet && ((streamPos - markedStreamPos) > readLimit)) - clearCurrentMark(); - - return readAmount; - } - - /** - * Marks the current position in this input stream. - * - * @param readLimit - * the number of bytes to hold - */ - public void mark(int readLimit) { - if (null != tdsReader && readLimit > 0) { - currentMark = tdsReader.mark(); - markedStreamPos = streamPos; - setReadLimit(readLimit); - } - } - - /** - * Resets stream to saved mark position. - * - * @exception IOException - * if an I/O error occurs. - */ - public void reset() throws IOException { - resetHelper(); - streamPos = markedStreamPos; - } - - /** - * Helper function to convert the entire PLP stream into a contiguous byte array. This call is inefficient (in terms of memory usage and run time) - * for very large PLPs. Use it only if a contiguous byte array is required. - */ - final byte[] getBytes() throws SQLServerException { - // We should always retrieve the entire stream, and only once. - assert 0 == streamPos; - - byte[] value = new byte[payloadLength]; - try { - read(value); - close(); - } - catch (IOException e) { - SQLServerException.makeFromDriverError(null, null, e.getMessage(), null, true); - } - - return value; - } - -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +import java.io.IOException; +import java.io.InputStream; +import java.util.concurrent.atomic.AtomicInteger; + + +/** + * SimpleInputStream is an InputStream implementation that reads from TDS. + * + * This class is to support adaptive streaming of non plp aka simple byte types char, byte etc. + * + */ +abstract class BaseInputStream extends InputStream { + abstract byte[] getBytes() throws SQLServerException; + + // Flag indicating whether the stream conforms to adaptive response buffering API restrictions + final boolean isAdaptive; + + // Flag indicating whether the stream consumes and discards data as it reads it + final boolean isStreaming; + + /** Generate the logging ID */ + private String parentLoggingInfo = ""; + private static final AtomicInteger lastLoggingID = new AtomicInteger(0); + + private static int nextLoggingID() { + return lastLoggingID.incrementAndGet(); + } + + static final java.util.logging.Logger logger = java.util.logging.Logger + .getLogger("com.microsoft.sqlserver.jdbc.internals.InputStream");; + private String traceID; + + final public String toString() { + if (traceID == null) + traceID = getClass().getName() + "ID:" + nextLoggingID(); + return traceID; + } + + final void setLoggingInfo(String info) { + parentLoggingInfo = info; + if (logger.isLoggable(java.util.logging.Level.FINER)) + logger.finer(toString()); + } + + int streamPos = 0; + int markedStreamPos = 0; + TDSReaderMark currentMark; + private ServerDTVImpl dtv; + TDSReader tdsReader; + int readLimit = 0; + boolean isReadLimitSet = false; + + BaseInputStream(TDSReader tdsReader, boolean isAdaptive, boolean isStreaming, ServerDTVImpl dtv) { + this.tdsReader = tdsReader; + this.isAdaptive = isAdaptive; + this.isStreaming = isStreaming; + + if (isAdaptive) + clearCurrentMark(); + else + currentMark = tdsReader.mark(); + this.dtv = dtv; + } + + final void clearCurrentMark() { + currentMark = null; + isReadLimitSet = false; + if (isAdaptive && isStreaming) + tdsReader.stream(); + } + + void closeHelper() throws IOException { + if (isAdaptive && null != dtv) { + if (logger.isLoggable(java.util.logging.Level.FINER)) + logger.finer(toString() + " closing the adaptive stream."); + dtv.setPositionAfterStreamed(tdsReader); + } + currentMark = null; + tdsReader = null; + dtv = null; + } + + /** + * Verifies stream is open and throws IOException if otherwise. + */ + final void checkClosed() throws IOException { + if (null == tdsReader) + throw new IOException(SQLServerException.getErrString("R_streamIsClosed")); + } + + /** + * Tests if this input stream supports the mark and reset methods. + * + * @return true if mark and reset are supported. + */ + public boolean markSupported() { + return true; + } + + void setReadLimit(int readLimit) { + // we buffer the whole stream in the full case so readlimit is meaningless. + // spec does not say what to do with -ve values. + if (isAdaptive && readLimit > 0) { + this.readLimit = readLimit; + isReadLimitSet = true; + } + } + + /** + * Resets stream to saved mark position. + * + * @exception IOException + * if an I/O error occurs. + */ + void resetHelper() throws IOException { + checkClosed(); + // if no mark set already throw + if (null == currentMark) + throw new IOException(SQLServerException.getErrString("R_streamWasNotMarkedBefore")); + tdsReader.reset(currentMark); + } +} + + +final class SimpleInputStream extends BaseInputStream { + + // Stated length of the payload + private final int payloadLength; + + /** + * Initializes the input stream. + */ + SimpleInputStream(TDSReader tdsReader, int payLoadLength, InputStreamGetterArgs getterArgs, + ServerDTVImpl dtv) throws SQLServerException { + super(tdsReader, getterArgs.isAdaptive, getterArgs.isStreaming, dtv); + setLoggingInfo(getterArgs.logContext); + this.payloadLength = payLoadLength; + } + + /** + * Closes the stream releasing all resources held. + * + * @exception IOException + * if an I/O error occurs. + */ + public void close() throws IOException { + if (null == tdsReader) + return; + if (logger.isLoggable(java.util.logging.Level.FINER)) + logger.finer(toString() + "Enter Closing SimpleInputStream."); + + // Discard the remainder of the stream, positioning the TDSReader + // at the next item in the TDS response. Once the stream is closed, + // it can no longer access the discarded response data. + skip(payloadLength - streamPos); + + closeHelper(); + if (logger.isLoggable(java.util.logging.Level.FINER)) + logger.finer(toString() + "Exit Closing SimpleInputStream."); + } + + /** + * Checks if we have EOS state. + * + * @exception IOException + * if an I/O error occurs. + */ + private boolean isEOS() throws IOException { + assert streamPos <= payloadLength; + return (streamPos == payloadLength); + } + + // java.io.InputStream interface methods. + + /** + * Skips over and discards n bytes of data from this input stream. + * + * @param n + * the number of bytes to be skipped. + * @return the actual number of bytes skipped. + * @exception IOException + * if an I/O error occurs. + */ + public long skip(long n) throws IOException { + checkClosed(); + if (logger.isLoggable(java.util.logging.Level.FINER)) + logger.finer(toString() + " Skipping :" + n); + if (n < 0) + return 0L; + if (isEOS()) + return 0; + + int skipAmount; + if (streamPos + n > payloadLength) { + skipAmount = payloadLength - streamPos; + } else { + skipAmount = (int) n; + } + try { + tdsReader.skip(skipAmount); + } catch (SQLServerException e) { + throw new IOException(e.getMessage()); + } + streamPos += skipAmount; + if (isReadLimitSet && ((streamPos - markedStreamPos) > readLimit)) + clearCurrentMark(); + + return skipAmount; + + } + + /** + * Returns the number of bytes that can be read (or skipped over) from this input stream without blocking by the + * next caller of a method for this input stream. + * + * @return the actual number of bytes available. + * @exception IOException + * if an I/O error occurs. + */ + public int available() throws IOException { + checkClosed(); + assert streamPos <= payloadLength; + + int available = payloadLength - streamPos; + if (tdsReader.available() < available) + available = tdsReader.available(); + return available; + } + + private byte[] bSingleByte; + + /** + * Reads the next byte of data from the input stream. + * + * @return the byte read or -1 meaning no more bytes. + * @exception IOException + * if an I/O error occurs. + */ + public int read() throws IOException { + checkClosed(); + if (null == bSingleByte) + bSingleByte = new byte[1]; + if (isEOS()) + return -1; + int bytesRead = read(bSingleByte, 0, 1); + return (0 == bytesRead) ? -1 : (bSingleByte[0] & 0xFF); + } + + /** + * Reads available data into supplied byte array. + * + * @param b + * array of bytes to fill. + * @return the number of bytes read or -1 meaning no bytes read. + * @exception IOException + * if an I/O error occurs. + */ + public int read(byte[] b) throws IOException { + checkClosed(); + return read(b, 0, b.length); + } + + /** + * Reads available data into supplied byte array. + * + * @param b + * array of bytes to fill. + * @param offset + * the offset into array b where to start writing. + * @param maxBytes + * the max number of bytes to write into b. + * @return the number of bytes read or -1 meaning no bytes read. + * @exception IOException + * if an I/O error occurs. + */ + public int read(byte b[], int offset, int maxBytes) throws IOException { + checkClosed(); + if (logger.isLoggable(java.util.logging.Level.FINER)) + logger.finer(toString() + " Reading " + maxBytes + " from stream offset " + streamPos + " payload length " + + payloadLength); + + if (offset < 0 || maxBytes < 0 || offset + maxBytes > b.length) + throw new IndexOutOfBoundsException(); + + if (0 == maxBytes) + return 0; + if (isEOS()) + return -1; + + int readAmount; + if (streamPos + maxBytes > payloadLength) { + readAmount = payloadLength - streamPos; + } else { + readAmount = maxBytes; + } + + try { + tdsReader.readBytes(b, offset, readAmount); + } catch (SQLServerException e) { + throw new IOException(e.getMessage()); + } + streamPos += readAmount; + + if (isReadLimitSet && ((streamPos - markedStreamPos) > readLimit)) + clearCurrentMark(); + + return readAmount; + } + + /** + * Marks the current position in this input stream. + * + * @param readLimit + * the number of bytes to hold + */ + public void mark(int readLimit) { + if (null != tdsReader && readLimit > 0) { + currentMark = tdsReader.mark(); + markedStreamPos = streamPos; + setReadLimit(readLimit); + } + } + + /** + * Resets stream to saved mark position. + * + * @exception IOException + * if an I/O error occurs. + */ + public void reset() throws IOException { + resetHelper(); + streamPos = markedStreamPos; + } + + /** + * Helper function to convert the entire PLP stream into a contiguous byte array. This call is inefficient (in terms + * of memory usage and run time) for very large PLPs. Use it only if a contiguous byte array is required. + */ + final byte[] getBytes() throws SQLServerException { + // We should always retrieve the entire stream, and only once. + assert 0 == streamPos; + + byte[] value = new byte[payloadLength]; + try { + read(value); + close(); + } catch (IOException e) { + SQLServerException.makeFromDriverError(null, null, e.getMessage(), null, true); + } + + return value; + } + +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SqlFedAuthToken.java b/src/main/java/com/microsoft/sqlserver/jdbc/SqlFedAuthToken.java index 99cb4888a..01adb70a1 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SqlFedAuthToken.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SqlFedAuthToken.java @@ -1,30 +1,26 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; import java.util.Date; + class SqlFedAuthToken { - final Date expiresOn; - final String accessToken; + final Date expiresOn; + final String accessToken; - SqlFedAuthToken(final String accessToken, - final long expiresIn) { + SqlFedAuthToken(final String accessToken, final long expiresIn) { this.accessToken = accessToken; Date now = new Date(); now.setTime(now.getTime() + (expiresIn * 1000)); this.expiresOn = now; } - - SqlFedAuthToken(final String accessToken, - final Date expiresOn) { + + SqlFedAuthToken(final String accessToken, final Date expiresOn) { this.accessToken = accessToken; this.expiresOn = expiresOn; } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SqlVariant.java b/src/main/java/com/microsoft/sqlserver/jdbc/SqlVariant.java index 868db7102..caceb334b 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SqlVariant.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SqlVariant.java @@ -1,211 +1,209 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ -package com.microsoft.sqlserver.jdbc; - -import java.text.MessageFormat; - -/** - * This class holds information regarding the basetype of a sql_variant data. - * - */ - -/** - * Enum for valid probBytes for different TDSTypes - * - */ -enum sqlVariantProbBytes { - INTN(0), - INT8(0), - INT4(0), - INT2(0), - INT1(0), - FLOAT4(0), - FLOAT8(0), - DATETIME4(0), - DATETIME8(0), - MONEY4(0), - MONEY8(0), - BITN(0), - GUID(0), - DATEN(0), - TIMEN(1), - DATETIME2N(1), - DECIMALN(2), - NUMERICN(2), - BIGBINARY(2), - BIGVARBINARY(2), - BIGCHAR(7), - BIGVARCHAR(7), - NCHAR(7), - NVARCHAR(7); - - private final int intValue; - - private static final int MAXELEMENTS = 23; - private static final sqlVariantProbBytes valuesTypes[] = new sqlVariantProbBytes[MAXELEMENTS]; - - private sqlVariantProbBytes(int intValue) { - this.intValue = intValue; - } - - int getIntValue() { - return intValue; - } - - static sqlVariantProbBytes valueOf(int intValue) { - sqlVariantProbBytes tdsType; - - if (!(0 <= intValue && intValue < valuesTypes.length) || null == (tdsType = valuesTypes[intValue])) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_unknownSSType")); - Object[] msgArgs = {Integer.valueOf(intValue)}; - throw new IllegalArgumentException(form.format(msgArgs)); - } - - return tdsType; - } - -} - -public class SqlVariant { - - private int baseType; - private int precision; - private int scale; - private int maxLength; // for Character basetypes in sqlVariant - private SQLCollation collation; // for Character basetypes in sqlVariant - private boolean isBaseTypeTime = false; // we need this when we need to read time as timestamp (for instance in bulkcopy) - private JDBCType baseJDBCType; - - /** - * Constructor for sqlVariant - */ - SqlVariant(int baseType) { - this.baseType = baseType; - } - - /** - * Check if the basetype for variant is of time value - * - * @return - */ - boolean isBaseTypeTimeValue() { - return this.isBaseTypeTime; - } - - void setIsBaseTypeTimeValue(boolean isBaseTypeTime) { - this.isBaseTypeTime = isBaseTypeTime; - } - - /** - * store the base type for sql-variant - * - * @param baseType - */ - void setBaseType(int baseType) { - this.baseType = baseType; - } - - /** - * retrieves the base type for sql-variant - * - * @return - */ - int getBaseType() { - return this.baseType; - } - - /** - * Store the basetype as jdbc type - * - * @param baseJDBCType - */ - void setBaseJDBCType(JDBCType baseJDBCType) { - this.baseJDBCType = baseJDBCType; - } - - /** - * retrieves the base type as jdbc type - * - * @return - */ - JDBCType getBaseJDBCType() { - return this.baseJDBCType; - } - - /** - * stores the scale if applicable - * - * @param scale - */ - void setScale(int scale) { - this.scale = scale; - } - - /** - * retrieves the scale - * - * @return - */ - int getScale() { - return this.scale; - } - - /** - * stores the precision if applicable - * - * @param precision - */ - void setPrecision(int precision) { - this.precision = precision; - } - - /** - * retrieves the precision - * - * @return - */ - int getPrecision() { - return this.precision; - } - - /** - * stores the collation if applicable - * - * @param collation - */ - void setCollation(SQLCollation collation) { - this.collation = collation; - } - - /** - * Retrieves the collation - * - * @return - */ - SQLCollation getCollation() { - return this.collation; - } - - /** - * stores the maximum length - * - * @param maxLength - */ - void setMaxLength(int maxLength) { - this.maxLength = maxLength; - } - - /** - * retrieves the maximum length - * - * @return - */ - int getMaxLength() { - return this.maxLength; - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package com.microsoft.sqlserver.jdbc; + +import java.text.MessageFormat; + + +/** + * Enum for valid probBytes for different TDSTypes + * + */ +enum sqlVariantProbBytes { + INTN(0), + INT8(0), + INT4(0), + INT2(0), + INT1(0), + FLOAT4(0), + FLOAT8(0), + DATETIME4(0), + DATETIME8(0), + MONEY4(0), + MONEY8(0), + BITN(0), + GUID(0), + DATEN(0), + TIMEN(1), + DATETIME2N(1), + DECIMALN(2), + NUMERICN(2), + BIGBINARY(2), + BIGVARBINARY(2), + BIGCHAR(7), + BIGVARCHAR(7), + NCHAR(7), + NVARCHAR(7); + + private final int intValue; + + private static final int MAXELEMENTS = 23; + private static final sqlVariantProbBytes valuesTypes[] = new sqlVariantProbBytes[MAXELEMENTS]; + + private sqlVariantProbBytes(int intValue) { + this.intValue = intValue; + } + + int getIntValue() { + return intValue; + } + + static sqlVariantProbBytes valueOf(int intValue) { + sqlVariantProbBytes tdsType; + + if (!(0 <= intValue && intValue < valuesTypes.length) || null == (tdsType = valuesTypes[intValue])) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_unknownSSType")); + Object[] msgArgs = {Integer.valueOf(intValue)}; + throw new IllegalArgumentException(form.format(msgArgs)); + } + + return tdsType; + } + +} + + +/** + * Holds information regarding the basetype of a sql_variant data. + * + */ +class SqlVariant { + private int baseType; + private int precision; + private int scale; + private int maxLength; // for Character basetypes in sqlVariant + private SQLCollation collation; // for Character basetypes in sqlVariant + private boolean isBaseTypeTime = false; // we need this when we need to read time as timestamp (for instance in + // bulkcopy) + private JDBCType baseJDBCType; + + /** + * Constructs a SqlVariant. + */ + SqlVariant(int baseType) { + this.baseType = baseType; + } + + /** + * Returns if the basetype for variant is of time value. + * + * @return + */ + boolean isBaseTypeTimeValue() { + return this.isBaseTypeTime; + } + + void setIsBaseTypeTimeValue(boolean isBaseTypeTime) { + this.isBaseTypeTime = isBaseTypeTime; + } + + /** + * Sets the base type for sql-variant. + * + * @param baseType + */ + void setBaseType(int baseType) { + this.baseType = baseType; + } + + /** + * Returns the base type for sql-variant. + * + * @return + */ + int getBaseType() { + return this.baseType; + } + + /** + * Stores the basetype as JDBC type. + * + * @param baseJDBCType + */ + void setBaseJDBCType(JDBCType baseJDBCType) { + this.baseJDBCType = baseJDBCType; + } + + /** + * Returns the base type as JDBC type. + * + * @return + */ + JDBCType getBaseJDBCType() { + return this.baseJDBCType; + } + + /** + * Sets the scale if applicable. + * + * @param scale + */ + void setScale(int scale) { + this.scale = scale; + } + + /** + * Returns the scale. + * + * @return + */ + int getScale() { + return this.scale; + } + + /** + * Sets the precision if applicable. + * + * @param precision + */ + void setPrecision(int precision) { + this.precision = precision; + } + + /** + * Returns the precision. + * + * @return + */ + int getPrecision() { + return this.precision; + } + + /** + * Sets the collation if applicable. + * + * @param collation + */ + void setCollation(SQLCollation collation) { + this.collation = collation; + } + + /** + * Returns the collation. + * + * @return + */ + SQLCollation getCollation() { + return this.collation; + } + + /** + * Sets the maximum length. + * + * @param maxLength + */ + void setMaxLength(int maxLength) { + this.maxLength = maxLength; + } + + /** + * Returns the maximum length. + * + * @return + */ + int getMaxLength() { + return this.maxLength; + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/StreamColInfo.java b/src/main/java/com/microsoft/sqlserver/jdbc/StreamColInfo.java index e0d7eaeb5..be7152339 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/StreamColInfo.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/StreamColInfo.java @@ -1,60 +1,57 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -/** - * StreamColInfo interprets the data stream from a COLINFO TDS token - */ - -final class StreamColInfo extends StreamPacket { - private TDSReader tdsReader; - private TDSReaderMark colInfoMark; - - StreamColInfo() { - super(TDS.TDS_COLINFO); - } - - void setFromTDS(TDSReader tdsReader) throws SQLServerException { - if (TDS.TDS_COLINFO != tdsReader.readUnsignedByte()) - assert false : "Not a COLINFO token"; - - this.tdsReader = tdsReader; - int tokenLength = tdsReader.readUnsignedShort(); - colInfoMark = tdsReader.mark(); - tdsReader.skip(tokenLength); - } - - int applyTo(Column[] columns) throws SQLServerException { - int numTables = 0; - - // Read and apply the column info for each column - TDSReaderMark currentMark = tdsReader.mark(); - tdsReader.reset(colInfoMark); - for (Column col : columns) { - // Ignore the column number, per TDS spec. - // Column info is returned for each column, ascending by column index, - // so iterating through the column info is sufficient. - tdsReader.readUnsignedByte(); - - // Set the column's table number, keeping track of the maximum table number - // representing the number of tables encountered. - col.setTableNum(tdsReader.readUnsignedByte()); - if (col.getTableNum() > numTables) - numTables = col.getTableNum(); - - // Set the other column info - col.setInfoStatus(tdsReader.readUnsignedByte()); - if (col.hasDifferentName()) - col.setBaseColumnName(tdsReader.readUnicodeString(tdsReader.readUnsignedByte())); - } - - tdsReader.reset(currentMark); - return numTables; - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +/** + * StreamColInfo interprets the data stream from a COLINFO TDS token + */ + +final class StreamColInfo extends StreamPacket { + private TDSReader tdsReader; + private TDSReaderMark colInfoMark; + + StreamColInfo() { + super(TDS.TDS_COLINFO); + } + + void setFromTDS(TDSReader tdsReader) throws SQLServerException { + if (TDS.TDS_COLINFO != tdsReader.readUnsignedByte()) + assert false : "Not a COLINFO token"; + + this.tdsReader = tdsReader; + int tokenLength = tdsReader.readUnsignedShort(); + colInfoMark = tdsReader.mark(); + tdsReader.skip(tokenLength); + } + + int applyTo(Column[] columns) throws SQLServerException { + int numTables = 0; + + // Read and apply the column info for each column + TDSReaderMark currentMark = tdsReader.mark(); + tdsReader.reset(colInfoMark); + for (Column col : columns) { + // Ignore the column number, per TDS spec. + // Column info is returned for each column, ascending by column index, + // so iterating through the column info is sufficient. + tdsReader.readUnsignedByte(); + + // Set the column's table number, keeping track of the maximum table number + // representing the number of tables encountered. + col.setTableNum(tdsReader.readUnsignedByte()); + if (col.getTableNum() > numTables) + numTables = col.getTableNum(); + + // Set the other column info + col.setInfoStatus(tdsReader.readUnsignedByte()); + if (col.hasDifferentName()) + col.setBaseColumnName(tdsReader.readUnicodeString(tdsReader.readUnsignedByte())); + } + + tdsReader.reset(currentMark); + return numTables; + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/StreamColumns.java b/src/main/java/com/microsoft/sqlserver/jdbc/StreamColumns.java index e0f5342d9..df8b031fd 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/StreamColumns.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/StreamColumns.java @@ -1,13 +1,11 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; +import java.util.ArrayList; import java.util.List; import com.microsoft.sqlserver.jdbc.dataclassification.ColumnSensitivity; @@ -16,10 +14,10 @@ import com.microsoft.sqlserver.jdbc.dataclassification.SensitivityClassification; import com.microsoft.sqlserver.jdbc.dataclassification.SensitivityProperty; -import java.util.ArrayList; /** - * StreamColumns stores the column meta data for a result set. StreamColumns parses the inbound TDS packet stream to determine column meta data. + * StreamColumns stores the column meta data for a result set. StreamColumns parses the inbound TDS packet stream to + * determine column meta data. */ final class StreamColumns extends StreamPacket { @@ -31,7 +29,7 @@ final class StreamColumns extends StreamPacket { private boolean shouldHonorAEForRead = false; - /* Gets the CekTable */ + /* Returns the CekTable */ CekTable getCekTable() { return cekTable; } @@ -103,7 +101,8 @@ CekTableEntry readCEKTableEntry(TDSReader tdsReader) throws SQLServerException { String algorithmName = tdsReader.readUnicodeString(algorithmLength); // Add this encrypted CEK blob to our list of encrypted values for the CEK - cekTableEntry.add(encryptedCek, databaseId, cekId, cekVersion, cekMdVersion, keyPath, keyStoreName, algorithmName); + cekTableEntry.add(encryptedCek, databaseId, cekId, cekVersion, cekMdVersion, keyPath, keyStoreName, + algorithmName); } return cekTableEntry; } @@ -160,8 +159,8 @@ CryptoMetadata readCryptoMetadata(TDSReader tdsReader) throws SQLServerException // Read Normalization Rule Version. byte normalizationRuleVersion = (byte) tdsReader.readUnsignedByte(); - CryptoMetadata cryptoMeta = new CryptoMetadata((cekTable == null) ? null : cekTable.getCekTableEntry(ordinal), ordinal, algorithmId, - algorithmName, encryptionType, normalizationRuleVersion); + CryptoMetadata cryptoMeta = new CryptoMetadata((cekTable == null) ? null : cekTable.getCekTableEntry(ordinal), + ordinal, algorithmId, algorithmName, encryptionType, normalizationRuleVersion); cryptoMeta.setBaseTypeInfo(typeInfo); return cryptoMeta; @@ -197,7 +196,8 @@ void setFromTDS(TDSReader tdsReader) throws SQLServerException { // Table name is set at this point for TEXT/NTEXT/IMAGE columns only. // For other columns, table name may be set via COLUMNINFO and TABNAME tokens. SQLIdentifier tableName = new SQLIdentifier(); - if (SSType.TEXT == typeInfo.getSSType() || SSType.NTEXT == typeInfo.getSSType() || SSType.IMAGE == typeInfo.getSSType()) { + if (SSType.TEXT == typeInfo.getSSType() || SSType.NTEXT == typeInfo.getSSType() + || SSType.IMAGE == typeInfo.getSSType()) { // Yukon and later, table names are returned as multi-part SQL identifiers. tableName = tdsReader.readSQLIdentifier(); } @@ -214,15 +214,16 @@ void setFromTDS(TDSReader tdsReader) throws SQLServerException { if (shouldHonorAEForRead) { this.columns[numColumns] = new Column(typeInfo, columnName, tableName, cryptoMeta); - } - else { - // Set null for crypto metadata if column encryption setting is off at the connection or at the statement level. + } else { + // Set null for crypto metadata if column encryption setting is off at the connection or at the + // statement level. this.columns[numColumns] = new Column(typeInfo, columnName, tableName, null); } } // Data Classification - if (tdsReader.getServerSupportsDataClassification() && tdsReader.peekTokenType() == TDS.TDS_SQLDATACLASSIFICATION) { + if (tdsReader.getServerSupportsDataClassification() + && tdsReader.peekTokenType() == TDS.TDS_SQLDATACLASSIFICATION) { // Read and parse tdsReader.trySetSensitivityClassification(processDataClassification(tdsReader)); } @@ -298,8 +299,7 @@ private SensitivityClassification processDataClassification(TDSReader tdsReader) int informationTypeIndex = tdsReader.readUnsignedShort(); InformationType informationType = null; if (informationTypeIndex != Integer.MAX_VALUE) { - if (informationTypeIndex >= informationTypes.size()) { - } + if (informationTypeIndex >= informationTypes.size()) {} informationType = informationTypes.get(informationTypeIndex); } // add sensitivity properties for the source @@ -312,11 +312,10 @@ private SensitivityClassification processDataClassification(TDSReader tdsReader) } /** - * Applies per-column table information derived from COLINFO and TABNAME tokens to the set of columns defined by this COLMETADATA token to produce - * the complete set of column information. + * Applies per-column table information derived from COLINFO and TABNAME tokens to the set of columns defined by + * this COLMETADATA token to produce the complete set of column information. */ - Column[] buildColumns(StreamColInfo colInfoToken, - StreamTabName tabNameToken) throws SQLServerException { + Column[] buildColumns(StreamColInfo colInfoToken, StreamTabName tabNameToken) throws SQLServerException { if (null != colInfoToken && null != tabNameToken) tabNameToken.applyTo(columns, colInfoToken.applyTo(columns)); diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/StreamDone.java b/src/main/java/com/microsoft/sqlserver/jdbc/StreamDone.java index d6d3e52de..282f9f11e 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/StreamDone.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/StreamDone.java @@ -1,366 +1,363 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -/** - * StreamDone/StreamDoneInProc/StreamDoneProc stores a TDS Done packet that denotes the completion of a database operation. - */ - -class StreamDone extends StreamPacket { - /** the done completion status */ - private short status; - /** the row update count */ - private long rowCount; - - /** - * the current command (See Appendix A of TDS spec) - */ - static final short CMD_SELECT = 0xC1; - static final short CMD_SELECTINTO = 0xC2; - static final short CMD_INSERT = 0xC3; - static final short CMD_DELETE = 0xC4; - static final short CMD_UPDATE = 0xC5; - static final short CMD_EXECUTE = 0xE0; - static final short CMD_BULKINSERT = 0xF0; - static final short CMD_MERGE = 0x117; - - // DDL commands - static final short CMD_CNST_CREATE = 0x2e; - static final short CMD_DENY = 0x99; - static final short CMD_DROPSCHEMA = 0xb0; - static final short CMD_FUNCCREATE = 0xb2; - static final short CMD_FUNCDESTROY = 0xb3; - static final short CMD_ASMCREATE = 0xb5; - static final short CMD_CMD = 0xb6; - static final short CMD_TABCREATE = 0xc6; - static final short CMD_TABDESTROY = 0xc7; - static final short CMD_INDCREATE = 0xc8; - static final short CMD_INDDESTROY = 0xc9; - static final short CMD_DBCREATE = 0xcb; - static final short CMD_DBDESTROY = 0xcc; - static final short CMD_GRANT = 0xcd; - static final short CMD_REVOKE = 0xce; - static final short CMD_VIEWCREATE = 0xcf; - static final short CMD_VIEWDESTROY = 0xd0; - static final short CMD_DBEXTEND = 0xd7; - static final short CMD_ALTERTAB = 0xd8; - static final short CMD_TRIGCREATE = 0xdd; - static final short CMD_PROCCREATE = 0xde; - static final short CMD_PROCDESTROY = 0xdf; - static final short CMD_TRIGDESTROY = 0xe1; - static final short CMD_DBCC_CMD = 0xe6; - static final short CMD_DEFAULTCREATE = 0xe9; - static final short CMD_RULECREATE = 0xec; - static final short CMD_RULEDESTROY = 0xed; - static final short CMD_DEFAULTDESTROY = 0xee; - static final short CMD_STATSDESTROY = 0x100; - static final short CMD_ASMDESTROY = 0x10e; - static final short CMD_ASMALTER = 0x10f; - static final short CMD_TYPEDESTROY = 0x110; - static final short CMD_TYPECREATE = 0x111; - static final short CMD_CLRPROCEDURECREATE = 0x112; - static final short CMD_CLRFUNCTIONCREATE = 0x113; - static final short CMD_SERVICEALTER = 0x114; - static final short CMD_MSGTYPECREATE = 0x115; - static final short CMD_MSGTYPEDESTROY = 0x116; - static final short CMD_CONTRACTCREATE = 0x119; - static final short CMD_CONTRACTDESTROY = 0x11a; - static final short CMD_SERVICECREATE = 0x11b; - static final short CMD_SERVICEDESTROY = 0x11c; - static final short CMD_QUEUECREATE = 0x11d; - static final short CMD_QUEUEDESTROY = 0x11e; - static final short CMD_QUEUEALTER = 0x11f; - static final short CMD_FTXTINDEX_CREATE = 0x126; - static final short CMD_FTXTINDEX_ALTER = 0x127; - static final short CMD_FTXTINDEX_DROP = 0x128; - static final short CMD_PRTFUNCTIONCREATE = 0x129; - static final short CMD_PRTFUNCTIONDROP = 0x12a; - static final short CMD_PRTSCHEMECREATE = 0x12b; - static final short CMD_PRTSCHEMEDROP = 0x12c; - static final short CMD_FTXTCATALOG_CREATE = 0x130; - static final short CMD_FTXTCATALOG_ALTER = 0x131; - static final short CMD_FTXTCATALOG_DROP = 0x132; - static final short CMD_XMLSCHEMACREATE = 0x135; - static final short CMD_XMLSCHEMAALTER = 0x136; - static final short CMD_XMLSCHEMADROP = 0x137; - static final short CMD_ENDPOINTCREATE = 0x138; - static final short CMD_ENDPOINTALTER = 0x139; - static final short CMD_ENDPOINTDROP = 0x13a; - static final short CMD_USERCREATE = 0x13b; - static final short CMD_USERALTER = 0x13c; - static final short CMD_USERDROP = 0x13d; - static final short CMD_ROLECREATE = 0x13f; - static final short CMD_ROLEALTER = 0x140; - static final short CMD_ROLEDROP = 0x141; - static final short CMD_APPROLECREATE = 0x142; - static final short CMD_APPROLEALTER = 0x143; - static final short CMD_APPROLEDROP = 0x144; - static final short CMD_LOGINCREATE = 0x145; - static final short CMD_LOGINALTER = 0x146; - static final short CMD_LOGINDROP = 0x147; - static final short CMD_SYNONYMCREATE = 0x148; - static final short CMD_SYNONYMDROP = 0x149; - static final short CMD_CREATESCHEMA = 0x14a; - static final short CMD_ALTERSCHEMA = 0x14b; - static final short CMD_AGGCREATE = 0x14c; - static final short CMD_AGGDESTROY = 0x14d; - static final short CMD_CLRTRIGGERCREATE = 0x14e; - static final short CMD_PRTFUNCTIONALTER = 0x14f; - static final short CMD_PRTSCHEMEALTER = 0x150; - static final short CMD_INDALTER = 0x151; - static final short CMD_ROUTECREATE = 0x157; - static final short CMD_ROUTEALTER = 0x158; - static final short CMD_ROUTEDESTROY = 0x15a; - static final short CMD_EVENTNOTIFICATIONCREATE = 0x160; - static final short CMD_EVENTNOTIFICATIONDROP = 0x161; - static final short CMD_XMLINDEXCREATE = 0x162; - static final short CMD_BINDINGCREATE = 0x166; - static final short CMD_BINDINGALTER = 0x167; - static final short CMD_BINDINGDESTROY = 0x168; - static final short CMD_MSGTYPEALTER = 0x16e; - static final short CMD_CERTCREATE = 0x170; - static final short CMD_CERTDROP = 0x171; - static final short CMD_CERTALTER = 0x172; - static final short CMD_SECDESCCREATE = 0x17d; - static final short CMD_SECDESCDROP = 0x17e; - static final short CMD_SECDESCALTER = 0x17f; - static final short CMD_OBFUSKEYCREATE = 0x182; - static final short CMD_OBFUSKEYALTER = 0x183; - static final short CMD_OBFUSKEYDROP = 0x184; - static final short CMD_ALTERAUTHORIZATION = 0x18c; - static final short CMD_CREDENTIALCREATE = 0x198; - static final short CMD_CREDENTIALALTER = 0x199; - static final short CMD_CREDENTIALDROP = 0x19a; - static final short CMD_MASTERKEYCREATE = 0x19b; - static final short CMD_MASTERKEYDROP = 0x19c; - static final short CMD_MASTERKEYALTER = 0x1a1; - static final short CMD_ASYMKEYCREATE = 0x1a3; - static final short CMD_ASYMKEYDROP = 0x1a4; - static final short CMD_ASYMKEYALTER = 0x1a9; - - private short curCmd; - - /** - * Set the packet contents - */ - void setFromTDS(TDSReader tdsReader) throws SQLServerException { - packetType = tdsReader.readUnsignedByte(); // token type - assert TDS.TDS_DONE == packetType || TDS.TDS_DONEPROC == packetType || TDS.TDS_DONEINPROC == packetType; - - status = tdsReader.readShort(); - curCmd = tdsReader.readShort(); - rowCount = tdsReader.readLong(); - - if (isAttnAck()) - tdsReader.getCommand().onAttentionAck(); - } - - /** - * Return the packet's current command - */ - /* L0 */ final short getCurCmd() { - return curCmd; - } - - /** - * Check if this done packet is the final done packet (top nesting) - * - * @return true if final - */ - /* L0 */ final boolean isFinal() { - return (status & 0x0001) == 0; - } - - /** - * Check if a error state was indicated. - * - * @return true if error - */ - /* L0 */ final boolean isError() { - return (status & 0x0002) != 0; - } - - /** - * Determine if a done packet has a row count - * - * @return true if the row count is present - */ - /* L0 */ final boolean updateCountIsValid() { - return (status & 0x0010) != 0; - } - - /** - * Check if a cancelled state was indicated. - * - * @return true if cancelled - */ - /* L0 */ final boolean isAttnAck() { - return (status & 0x0020) != 0; - } - - /** - * Check if a RPC in batch was indicated - * - * @return true if RPC in batch - */ - /* L0 */ final boolean wasRPCInBatch() { - return (status & 0x0080) != 0; - } - - /** - * Return the update count - */ - final long getUpdateCount() { - assert cmdIsDMLOrDDL(); - - switch (curCmd) { - case CMD_INSERT: - case CMD_BULKINSERT: - case CMD_DELETE: - case CMD_UPDATE: - case CMD_MERGE: - case CMD_SELECTINTO: - return updateCountIsValid() ? rowCount : -1; - - default: // DDL assumed - return 0; - } - } - - final boolean cmdIsDMLOrDDL() { - switch (curCmd) { - case CMD_INSERT: - case CMD_BULKINSERT: - case CMD_DELETE: - case CMD_UPDATE: - case CMD_MERGE: - case CMD_SELECTINTO: - - // DDL - // Lifted from SQL Server 2005 Books Online at: - // http://msdn2.microsoft.com/en-us/library/ms180824.aspx - case CMD_CNST_CREATE: - case CMD_DENY: - case CMD_DROPSCHEMA: - case CMD_FUNCCREATE: - case CMD_FUNCDESTROY: - case CMD_ASMCREATE: - case CMD_CMD: - case CMD_TABCREATE: - case CMD_TABDESTROY: - case CMD_INDCREATE: - case CMD_INDDESTROY: - case CMD_DBCREATE: - case CMD_DBDESTROY: - case CMD_GRANT: - case CMD_REVOKE: - case CMD_VIEWCREATE: - case CMD_VIEWDESTROY: - case CMD_DBEXTEND: - case CMD_ALTERTAB: - case CMD_TRIGCREATE: - case CMD_PROCCREATE: - case CMD_PROCDESTROY: - case CMD_TRIGDESTROY: - case CMD_DBCC_CMD: - case CMD_DEFAULTCREATE: - case CMD_RULECREATE: - case CMD_RULEDESTROY: - case CMD_DEFAULTDESTROY: - case CMD_STATSDESTROY: - case CMD_ASMDESTROY: - case CMD_ASMALTER: - case CMD_TYPEDESTROY: - case CMD_TYPECREATE: - case CMD_CLRPROCEDURECREATE: - case CMD_CLRFUNCTIONCREATE: - case CMD_SERVICEALTER: - case CMD_MSGTYPECREATE: - case CMD_MSGTYPEDESTROY: - case CMD_CONTRACTCREATE: - case CMD_CONTRACTDESTROY: - case CMD_SERVICECREATE: - case CMD_SERVICEDESTROY: - case CMD_QUEUECREATE: - case CMD_QUEUEDESTROY: - case CMD_QUEUEALTER: - case CMD_FTXTINDEX_CREATE: - case CMD_FTXTINDEX_ALTER: - case CMD_FTXTINDEX_DROP: - case CMD_PRTFUNCTIONCREATE: - case CMD_PRTFUNCTIONDROP: - case CMD_PRTSCHEMECREATE: - case CMD_PRTSCHEMEDROP: - case CMD_FTXTCATALOG_CREATE: - case CMD_FTXTCATALOG_ALTER: - case CMD_FTXTCATALOG_DROP: - case CMD_XMLSCHEMACREATE: - case CMD_XMLSCHEMAALTER: - case CMD_XMLSCHEMADROP: - case CMD_ENDPOINTCREATE: - case CMD_ENDPOINTALTER: - case CMD_ENDPOINTDROP: - case CMD_USERCREATE: - case CMD_USERALTER: - case CMD_USERDROP: - case CMD_ROLECREATE: - case CMD_ROLEALTER: - case CMD_ROLEDROP: - case CMD_APPROLECREATE: - case CMD_APPROLEALTER: - case CMD_APPROLEDROP: - case CMD_LOGINCREATE: - case CMD_LOGINALTER: - case CMD_LOGINDROP: - case CMD_SYNONYMCREATE: - case CMD_SYNONYMDROP: - case CMD_CREATESCHEMA: - case CMD_ALTERSCHEMA: - case CMD_AGGCREATE: - case CMD_AGGDESTROY: - case CMD_CLRTRIGGERCREATE: - case CMD_PRTFUNCTIONALTER: - case CMD_PRTSCHEMEALTER: - case CMD_INDALTER: - case CMD_ROUTECREATE: - case CMD_ROUTEALTER: - case CMD_ROUTEDESTROY: - case CMD_EVENTNOTIFICATIONCREATE: - case CMD_EVENTNOTIFICATIONDROP: - case CMD_XMLINDEXCREATE: - case CMD_BINDINGCREATE: - case CMD_BINDINGALTER: - case CMD_BINDINGDESTROY: - case CMD_MSGTYPEALTER: - case CMD_CERTCREATE: - case CMD_CERTDROP: - case CMD_CERTALTER: - case CMD_SECDESCCREATE: - case CMD_SECDESCDROP: - case CMD_SECDESCALTER: - case CMD_OBFUSKEYCREATE: - case CMD_OBFUSKEYALTER: - case CMD_OBFUSKEYDROP: - case CMD_ALTERAUTHORIZATION: - case CMD_CREDENTIALCREATE: - case CMD_CREDENTIALALTER: - case CMD_CREDENTIALDROP: - case CMD_MASTERKEYCREATE: - case CMD_MASTERKEYDROP: - case CMD_MASTERKEYALTER: - case CMD_ASYMKEYCREATE: - case CMD_ASYMKEYDROP: - case CMD_ASYMKEYALTER: - return true; - - default: - return false; - } - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +/** + * StreamDone/StreamDoneInProc/StreamDoneProc stores a TDS Done packet that denotes the completion of a database + * operation. + */ + +class StreamDone extends StreamPacket { + /** the done completion status */ + private short status; + /** the row update count */ + private long rowCount; + + /** + * the current command (See Appendix A of TDS spec) + */ + static final short CMD_SELECT = 0xC1; + static final short CMD_SELECTINTO = 0xC2; + static final short CMD_INSERT = 0xC3; + static final short CMD_DELETE = 0xC4; + static final short CMD_UPDATE = 0xC5; + static final short CMD_EXECUTE = 0xE0; + static final short CMD_BULKINSERT = 0xF0; + static final short CMD_MERGE = 0x117; + + // DDL commands + static final short CMD_CNST_CREATE = 0x2e; + static final short CMD_DENY = 0x99; + static final short CMD_DROPSCHEMA = 0xb0; + static final short CMD_FUNCCREATE = 0xb2; + static final short CMD_FUNCDESTROY = 0xb3; + static final short CMD_ASMCREATE = 0xb5; + static final short CMD_CMD = 0xb6; + static final short CMD_TABCREATE = 0xc6; + static final short CMD_TABDESTROY = 0xc7; + static final short CMD_INDCREATE = 0xc8; + static final short CMD_INDDESTROY = 0xc9; + static final short CMD_DBCREATE = 0xcb; + static final short CMD_DBDESTROY = 0xcc; + static final short CMD_GRANT = 0xcd; + static final short CMD_REVOKE = 0xce; + static final short CMD_VIEWCREATE = 0xcf; + static final short CMD_VIEWDESTROY = 0xd0; + static final short CMD_DBEXTEND = 0xd7; + static final short CMD_ALTERTAB = 0xd8; + static final short CMD_TRIGCREATE = 0xdd; + static final short CMD_PROCCREATE = 0xde; + static final short CMD_PROCDESTROY = 0xdf; + static final short CMD_TRIGDESTROY = 0xe1; + static final short CMD_DBCC_CMD = 0xe6; + static final short CMD_DEFAULTCREATE = 0xe9; + static final short CMD_RULECREATE = 0xec; + static final short CMD_RULEDESTROY = 0xed; + static final short CMD_DEFAULTDESTROY = 0xee; + static final short CMD_STATSDESTROY = 0x100; + static final short CMD_ASMDESTROY = 0x10e; + static final short CMD_ASMALTER = 0x10f; + static final short CMD_TYPEDESTROY = 0x110; + static final short CMD_TYPECREATE = 0x111; + static final short CMD_CLRPROCEDURECREATE = 0x112; + static final short CMD_CLRFUNCTIONCREATE = 0x113; + static final short CMD_SERVICEALTER = 0x114; + static final short CMD_MSGTYPECREATE = 0x115; + static final short CMD_MSGTYPEDESTROY = 0x116; + static final short CMD_CONTRACTCREATE = 0x119; + static final short CMD_CONTRACTDESTROY = 0x11a; + static final short CMD_SERVICECREATE = 0x11b; + static final short CMD_SERVICEDESTROY = 0x11c; + static final short CMD_QUEUECREATE = 0x11d; + static final short CMD_QUEUEDESTROY = 0x11e; + static final short CMD_QUEUEALTER = 0x11f; + static final short CMD_FTXTINDEX_CREATE = 0x126; + static final short CMD_FTXTINDEX_ALTER = 0x127; + static final short CMD_FTXTINDEX_DROP = 0x128; + static final short CMD_PRTFUNCTIONCREATE = 0x129; + static final short CMD_PRTFUNCTIONDROP = 0x12a; + static final short CMD_PRTSCHEMECREATE = 0x12b; + static final short CMD_PRTSCHEMEDROP = 0x12c; + static final short CMD_FTXTCATALOG_CREATE = 0x130; + static final short CMD_FTXTCATALOG_ALTER = 0x131; + static final short CMD_FTXTCATALOG_DROP = 0x132; + static final short CMD_XMLSCHEMACREATE = 0x135; + static final short CMD_XMLSCHEMAALTER = 0x136; + static final short CMD_XMLSCHEMADROP = 0x137; + static final short CMD_ENDPOINTCREATE = 0x138; + static final short CMD_ENDPOINTALTER = 0x139; + static final short CMD_ENDPOINTDROP = 0x13a; + static final short CMD_USERCREATE = 0x13b; + static final short CMD_USERALTER = 0x13c; + static final short CMD_USERDROP = 0x13d; + static final short CMD_ROLECREATE = 0x13f; + static final short CMD_ROLEALTER = 0x140; + static final short CMD_ROLEDROP = 0x141; + static final short CMD_APPROLECREATE = 0x142; + static final short CMD_APPROLEALTER = 0x143; + static final short CMD_APPROLEDROP = 0x144; + static final short CMD_LOGINCREATE = 0x145; + static final short CMD_LOGINALTER = 0x146; + static final short CMD_LOGINDROP = 0x147; + static final short CMD_SYNONYMCREATE = 0x148; + static final short CMD_SYNONYMDROP = 0x149; + static final short CMD_CREATESCHEMA = 0x14a; + static final short CMD_ALTERSCHEMA = 0x14b; + static final short CMD_AGGCREATE = 0x14c; + static final short CMD_AGGDESTROY = 0x14d; + static final short CMD_CLRTRIGGERCREATE = 0x14e; + static final short CMD_PRTFUNCTIONALTER = 0x14f; + static final short CMD_PRTSCHEMEALTER = 0x150; + static final short CMD_INDALTER = 0x151; + static final short CMD_ROUTECREATE = 0x157; + static final short CMD_ROUTEALTER = 0x158; + static final short CMD_ROUTEDESTROY = 0x15a; + static final short CMD_EVENTNOTIFICATIONCREATE = 0x160; + static final short CMD_EVENTNOTIFICATIONDROP = 0x161; + static final short CMD_XMLINDEXCREATE = 0x162; + static final short CMD_BINDINGCREATE = 0x166; + static final short CMD_BINDINGALTER = 0x167; + static final short CMD_BINDINGDESTROY = 0x168; + static final short CMD_MSGTYPEALTER = 0x16e; + static final short CMD_CERTCREATE = 0x170; + static final short CMD_CERTDROP = 0x171; + static final short CMD_CERTALTER = 0x172; + static final short CMD_SECDESCCREATE = 0x17d; + static final short CMD_SECDESCDROP = 0x17e; + static final short CMD_SECDESCALTER = 0x17f; + static final short CMD_OBFUSKEYCREATE = 0x182; + static final short CMD_OBFUSKEYALTER = 0x183; + static final short CMD_OBFUSKEYDROP = 0x184; + static final short CMD_ALTERAUTHORIZATION = 0x18c; + static final short CMD_CREDENTIALCREATE = 0x198; + static final short CMD_CREDENTIALALTER = 0x199; + static final short CMD_CREDENTIALDROP = 0x19a; + static final short CMD_MASTERKEYCREATE = 0x19b; + static final short CMD_MASTERKEYDROP = 0x19c; + static final short CMD_MASTERKEYALTER = 0x1a1; + static final short CMD_ASYMKEYCREATE = 0x1a3; + static final short CMD_ASYMKEYDROP = 0x1a4; + static final short CMD_ASYMKEYALTER = 0x1a9; + + private short curCmd; + + /** + * Set the packet contents + */ + void setFromTDS(TDSReader tdsReader) throws SQLServerException { + packetType = tdsReader.readUnsignedByte(); // token type + assert TDS.TDS_DONE == packetType || TDS.TDS_DONEPROC == packetType || TDS.TDS_DONEINPROC == packetType; + + status = tdsReader.readShort(); + curCmd = tdsReader.readShort(); + rowCount = tdsReader.readLong(); + + if (isAttnAck()) + tdsReader.getCommand().onAttentionAck(); + } + + /** + * Return the packet's current command + */ + /* L0 */ final short getCurCmd() { + return curCmd; + } + + /** + * Check if this done packet is the final done packet (top nesting) + * + * @return true if final + */ + /* L0 */ final boolean isFinal() { + return (status & 0x0001) == 0; + } + + /** + * Check if a error state was indicated. + * + * @return true if error + */ + /* L0 */ final boolean isError() { + return (status & 0x0002) != 0; + } + + /** + * Determine if a done packet has a row count + * + * @return true if the row count is present + */ + /* L0 */ final boolean updateCountIsValid() { + return (status & 0x0010) != 0; + } + + /** + * Check if a cancelled state was indicated. + * + * @return true if cancelled + */ + /* L0 */ final boolean isAttnAck() { + return (status & 0x0020) != 0; + } + + /** + * Check if a RPC in batch was indicated + * + * @return true if RPC in batch + */ + /* L0 */ final boolean wasRPCInBatch() { + return (status & 0x0080) != 0; + } + + /** + * Return the update count + */ + final long getUpdateCount() { + assert cmdIsDMLOrDDL(); + + switch (curCmd) { + case CMD_INSERT: + case CMD_BULKINSERT: + case CMD_DELETE: + case CMD_UPDATE: + case CMD_MERGE: + case CMD_SELECTINTO: + return updateCountIsValid() ? rowCount : -1; + + default: // DDL assumed + return 0; + } + } + + final boolean cmdIsDMLOrDDL() { + switch (curCmd) { + case CMD_INSERT: + case CMD_BULKINSERT: + case CMD_DELETE: + case CMD_UPDATE: + case CMD_MERGE: + case CMD_SELECTINTO: + + // DDL + // http://msdn2.microsoft.com/en-us/library/ms180824.aspx + case CMD_CNST_CREATE: + case CMD_DENY: + case CMD_DROPSCHEMA: + case CMD_FUNCCREATE: + case CMD_FUNCDESTROY: + case CMD_ASMCREATE: + case CMD_CMD: + case CMD_TABCREATE: + case CMD_TABDESTROY: + case CMD_INDCREATE: + case CMD_INDDESTROY: + case CMD_DBCREATE: + case CMD_DBDESTROY: + case CMD_GRANT: + case CMD_REVOKE: + case CMD_VIEWCREATE: + case CMD_VIEWDESTROY: + case CMD_DBEXTEND: + case CMD_ALTERTAB: + case CMD_TRIGCREATE: + case CMD_PROCCREATE: + case CMD_PROCDESTROY: + case CMD_TRIGDESTROY: + case CMD_DBCC_CMD: + case CMD_DEFAULTCREATE: + case CMD_RULECREATE: + case CMD_RULEDESTROY: + case CMD_DEFAULTDESTROY: + case CMD_STATSDESTROY: + case CMD_ASMDESTROY: + case CMD_ASMALTER: + case CMD_TYPEDESTROY: + case CMD_TYPECREATE: + case CMD_CLRPROCEDURECREATE: + case CMD_CLRFUNCTIONCREATE: + case CMD_SERVICEALTER: + case CMD_MSGTYPECREATE: + case CMD_MSGTYPEDESTROY: + case CMD_CONTRACTCREATE: + case CMD_CONTRACTDESTROY: + case CMD_SERVICECREATE: + case CMD_SERVICEDESTROY: + case CMD_QUEUECREATE: + case CMD_QUEUEDESTROY: + case CMD_QUEUEALTER: + case CMD_FTXTINDEX_CREATE: + case CMD_FTXTINDEX_ALTER: + case CMD_FTXTINDEX_DROP: + case CMD_PRTFUNCTIONCREATE: + case CMD_PRTFUNCTIONDROP: + case CMD_PRTSCHEMECREATE: + case CMD_PRTSCHEMEDROP: + case CMD_FTXTCATALOG_CREATE: + case CMD_FTXTCATALOG_ALTER: + case CMD_FTXTCATALOG_DROP: + case CMD_XMLSCHEMACREATE: + case CMD_XMLSCHEMAALTER: + case CMD_XMLSCHEMADROP: + case CMD_ENDPOINTCREATE: + case CMD_ENDPOINTALTER: + case CMD_ENDPOINTDROP: + case CMD_USERCREATE: + case CMD_USERALTER: + case CMD_USERDROP: + case CMD_ROLECREATE: + case CMD_ROLEALTER: + case CMD_ROLEDROP: + case CMD_APPROLECREATE: + case CMD_APPROLEALTER: + case CMD_APPROLEDROP: + case CMD_LOGINCREATE: + case CMD_LOGINALTER: + case CMD_LOGINDROP: + case CMD_SYNONYMCREATE: + case CMD_SYNONYMDROP: + case CMD_CREATESCHEMA: + case CMD_ALTERSCHEMA: + case CMD_AGGCREATE: + case CMD_AGGDESTROY: + case CMD_CLRTRIGGERCREATE: + case CMD_PRTFUNCTIONALTER: + case CMD_PRTSCHEMEALTER: + case CMD_INDALTER: + case CMD_ROUTECREATE: + case CMD_ROUTEALTER: + case CMD_ROUTEDESTROY: + case CMD_EVENTNOTIFICATIONCREATE: + case CMD_EVENTNOTIFICATIONDROP: + case CMD_XMLINDEXCREATE: + case CMD_BINDINGCREATE: + case CMD_BINDINGALTER: + case CMD_BINDINGDESTROY: + case CMD_MSGTYPEALTER: + case CMD_CERTCREATE: + case CMD_CERTDROP: + case CMD_CERTALTER: + case CMD_SECDESCCREATE: + case CMD_SECDESCDROP: + case CMD_SECDESCALTER: + case CMD_OBFUSKEYCREATE: + case CMD_OBFUSKEYALTER: + case CMD_OBFUSKEYDROP: + case CMD_ALTERAUTHORIZATION: + case CMD_CREDENTIALCREATE: + case CMD_CREDENTIALALTER: + case CMD_CREDENTIALDROP: + case CMD_MASTERKEYCREATE: + case CMD_MASTERKEYDROP: + case CMD_MASTERKEYALTER: + case CMD_ASYMKEYCREATE: + case CMD_ASYMKEYDROP: + case CMD_ASYMKEYALTER: + return true; + + default: + return false; + } + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/StreamError.java b/src/main/java/com/microsoft/sqlserver/jdbc/StreamError.java index c7d2418db..d28b5a726 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/StreamError.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/StreamError.java @@ -1,66 +1,63 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -/** - * StreamError represents a TDS error or message event. - */ - -final class StreamError extends StreamPacket { - /** the error message */ - String errorMessage = ""; - /** the error number */ - int errorNumber; - /** the tds error state */ - int errorState; - /** the tds error severity */ - int errorSeverity; - - String serverName; - String procName; - long lineNumber; - - final String getMessage() { - return errorMessage; - } - - final int getErrorNumber() { - return errorNumber; - } - - final int getErrorState() { - return errorState; - } - - final int getErrorSeverity() { - return errorSeverity; - } - - StreamError() { - super(TDS.TDS_ERR); - } - - void setFromTDS(TDSReader tdsReader) throws SQLServerException { - if (TDS.TDS_ERR != tdsReader.readUnsignedByte()) - assert false; - setContentsFromTDS(tdsReader); - } - - void setContentsFromTDS(TDSReader tdsReader) throws SQLServerException { - tdsReader.readUnsignedShort(); // token length (ignored) - errorNumber = tdsReader.readInt(); - errorState = tdsReader.readUnsignedByte(); - errorSeverity = tdsReader.readUnsignedByte(); // matches master.dbo.sysmessages - errorMessage = tdsReader.readUnicodeString(tdsReader.readUnsignedShort()); - serverName = tdsReader.readUnicodeString(tdsReader.readUnsignedByte()); - procName = tdsReader.readUnicodeString(tdsReader.readUnsignedByte()); - lineNumber = tdsReader.readUnsignedInt(); - - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +/** + * StreamError represents a TDS error or message event. + */ + +final class StreamError extends StreamPacket { + /** the error message */ + String errorMessage = ""; + /** the error number */ + int errorNumber; + /** the tds error state */ + int errorState; + /** the tds error severity */ + int errorSeverity; + + String serverName; + String procName; + long lineNumber; + + final String getMessage() { + return errorMessage; + } + + final int getErrorNumber() { + return errorNumber; + } + + final int getErrorState() { + return errorState; + } + + final int getErrorSeverity() { + return errorSeverity; + } + + StreamError() { + super(TDS.TDS_ERR); + } + + void setFromTDS(TDSReader tdsReader) throws SQLServerException { + if (TDS.TDS_ERR != tdsReader.readUnsignedByte()) + assert false; + setContentsFromTDS(tdsReader); + } + + void setContentsFromTDS(TDSReader tdsReader) throws SQLServerException { + tdsReader.readUnsignedShort(); // token length (ignored) + errorNumber = tdsReader.readInt(); + errorState = tdsReader.readUnsignedByte(); + errorSeverity = tdsReader.readUnsignedByte(); // matches master.dbo.sysmessages + errorMessage = tdsReader.readUnicodeString(tdsReader.readUnsignedShort()); + serverName = tdsReader.readUnicodeString(tdsReader.readUnsignedByte()); + procName = tdsReader.readUnicodeString(tdsReader.readUnsignedByte()); + lineNumber = tdsReader.readUnsignedInt(); + + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/StreamInfo.java b/src/main/java/com/microsoft/sqlserver/jdbc/StreamInfo.java index ef32b463f..c4134ce61 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/StreamInfo.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/StreamInfo.java @@ -1,23 +1,20 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -final class StreamInfo extends StreamPacket { - final StreamError msg = new StreamError(); - - StreamInfo() { - super(TDS.TDS_MSG); - } - - void setFromTDS(TDSReader tdsReader) throws SQLServerException { - if (TDS.TDS_MSG != tdsReader.readUnsignedByte()) - assert false; - msg.setContentsFromTDS(tdsReader); - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +final class StreamInfo extends StreamPacket { + final StreamError msg = new StreamError(); + + StreamInfo() { + super(TDS.TDS_MSG); + } + + void setFromTDS(TDSReader tdsReader) throws SQLServerException { + if (TDS.TDS_MSG != tdsReader.readUnsignedByte()) + assert false; + msg.setContentsFromTDS(tdsReader); + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/StreamLoginAck.java b/src/main/java/com/microsoft/sqlserver/jdbc/StreamLoginAck.java index 1abe2a133..cb2c9cfda 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/StreamLoginAck.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/StreamLoginAck.java @@ -1,37 +1,35 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -/** - * StreamLoginAck represents a TDS login ack. - * - */ - -final class StreamLoginAck extends StreamPacket { - String sSQLServerVersion; - int tdsVersion; - - StreamLoginAck() { - super(TDS.TDS_LOGIN_ACK); - } - - void setFromTDS(TDSReader tdsReader) throws SQLServerException { - if (TDS.TDS_LOGIN_ACK != tdsReader.readUnsignedByte()) - assert false; - tdsReader.readUnsignedShort(); // length of this token stream - tdsReader.readUnsignedByte(); // SQL version accepted by the server - tdsVersion = tdsReader.readIntBigEndian(); // TDS version accepted by the server - tdsReader.readUnicodeString(tdsReader.readUnsignedByte()); // Program name - int serverMajorVersion = tdsReader.readUnsignedByte(); - int serverMinorVersion = tdsReader.readUnsignedByte(); - int serverBuildNumber = (tdsReader.readUnsignedByte() << 8) | tdsReader.readUnsignedByte(); - - sSQLServerVersion = serverMajorVersion + "." + ((serverMinorVersion <= 9) ? "0" : "") + serverMinorVersion + "." + serverBuildNumber; - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +/** + * StreamLoginAck represents a TDS login ack. + * + */ + +final class StreamLoginAck extends StreamPacket { + String sSQLServerVersion; + int tdsVersion; + + StreamLoginAck() { + super(TDS.TDS_LOGIN_ACK); + } + + void setFromTDS(TDSReader tdsReader) throws SQLServerException { + if (TDS.TDS_LOGIN_ACK != tdsReader.readUnsignedByte()) + assert false; + tdsReader.readUnsignedShort(); // length of this token stream + tdsReader.readUnsignedByte(); // SQL version accepted by the server + tdsVersion = tdsReader.readIntBigEndian(); // TDS version accepted by the server + tdsReader.readUnicodeString(tdsReader.readUnsignedByte()); // Program name + int serverMajorVersion = tdsReader.readUnsignedByte(); + int serverMinorVersion = tdsReader.readUnsignedByte(); + int serverBuildNumber = (tdsReader.readUnsignedByte() << 8) | tdsReader.readUnsignedByte(); + + sSQLServerVersion = serverMajorVersion + "." + ((serverMinorVersion <= 9) ? "0" : "") + serverMinorVersion + "." + + serverBuildNumber; + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/StreamPacket.java b/src/main/java/com/microsoft/sqlserver/jdbc/StreamPacket.java index 6b0eacc77..7d3136a03 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/StreamPacket.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/StreamPacket.java @@ -1,31 +1,28 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -/** - * Common interface for all TDS packet types - * - */ -abstract class StreamPacket { - int packetType; - - final int getTokenType() { - return packetType; - } - - StreamPacket() { - this.packetType = 0; - } - - StreamPacket(int packetType) { - this.packetType = packetType; - } - - abstract void setFromTDS(TDSReader tdsReader) throws SQLServerException; -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +/** + * Common interface for all TDS packet types + * + */ +abstract class StreamPacket { + int packetType; + + final int getTokenType() { + return packetType; + } + + StreamPacket() { + this.packetType = 0; + } + + StreamPacket(int packetType) { + this.packetType = packetType; + } + + abstract void setFromTDS(TDSReader tdsReader) throws SQLServerException; +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/StreamRetStatus.java b/src/main/java/com/microsoft/sqlserver/jdbc/StreamRetStatus.java index 51b44cde0..0a7658d65 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/StreamRetStatus.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/StreamRetStatus.java @@ -1,32 +1,29 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -/** - * StreamRetStatus represents a TDS return status. - * - */ -final class StreamRetStatus extends StreamPacket { - /** the returned status */ - private int status; - - final int getStatus() { - return status; - } - - StreamRetStatus() { - super(TDS.TDS_RET_STAT); - } - - void setFromTDS(TDSReader tdsReader) throws SQLServerException { - if (TDS.TDS_RET_STAT != tdsReader.readUnsignedByte()) - assert false; - status = tdsReader.readInt(); - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +/** + * StreamRetStatus represents a TDS return status. + * + */ +final class StreamRetStatus extends StreamPacket { + /** the returned status */ + private int status; + + final int getStatus() { + return status; + } + + StreamRetStatus() { + super(TDS.TDS_RET_STAT); + } + + void setFromTDS(TDSReader tdsReader) throws SQLServerException { + if (TDS.TDS_RET_STAT != tdsReader.readUnsignedByte()) + assert false; + status = tdsReader.readInt(); + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/StreamRetValue.java b/src/main/java/com/microsoft/sqlserver/jdbc/StreamRetValue.java index c2947dd56..095301d51 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/StreamRetValue.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/StreamRetValue.java @@ -1,48 +1,47 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -/** - * StreamRetValue represents a TDS return value. - */ -final class StreamRetValue extends StreamPacket { - private String paramName; - - /* - * TDS 7.2: Indicates ordinal position of the OUTPUT parameter in the original RPC call TDS 7.1: Indicates the length of the return value - */ - private int ordinalOrLength; - - final int getOrdinalOrLength() { - return ordinalOrLength; - } - - /* - * Status: 0x01 if the return value is an OUTPUT parameter of a stored procedure 0x02 if the return value is from a User Defined Function - */ - private int status; - - StreamRetValue() { - super(TDS.TDS_RETURN_VALUE); - } - - void setFromTDS(TDSReader tdsReader) throws SQLServerException { - if (TDS.TDS_RETURN_VALUE != tdsReader.readUnsignedByte()) - assert false; - ordinalOrLength = tdsReader.readUnsignedShort(); - paramName = tdsReader.readUnicodeString(tdsReader.readUnsignedByte()); - status = tdsReader.readUnsignedByte(); - } - - CryptoMetadata getCryptoMetadata(TDSReader tdsReader) throws SQLServerException { - CryptoMetadata cryptoMeta = (new StreamColumns()).readCryptoMetadata(tdsReader); - - return cryptoMeta; - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +/** + * StreamRetValue represents a TDS return value. + */ +final class StreamRetValue extends StreamPacket { + private String paramName; + + /* + * TDS 7.2: Indicates ordinal position of the OUTPUT parameter in the original RPC call TDS 7.1: Indicates the + * length of the return value + */ + private int ordinalOrLength; + + final int getOrdinalOrLength() { + return ordinalOrLength; + } + + /* + * Status: 0x01 if the return value is an OUTPUT parameter of a stored procedure 0x02 if the return value is from a + * User Defined Function + */ + private int status; + + StreamRetValue() { + super(TDS.TDS_RETURN_VALUE); + } + + void setFromTDS(TDSReader tdsReader) throws SQLServerException { + if (TDS.TDS_RETURN_VALUE != tdsReader.readUnsignedByte()) + assert false; + ordinalOrLength = tdsReader.readUnsignedShort(); + paramName = tdsReader.readUnicodeString(tdsReader.readUnsignedByte()); + status = tdsReader.readUnsignedByte(); + } + + CryptoMetadata getCryptoMetadata(TDSReader tdsReader) throws SQLServerException { + CryptoMetadata cryptoMeta = (new StreamColumns()).readCryptoMetadata(tdsReader); + + return cryptoMeta; + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/StreamSSPI.java b/src/main/java/com/microsoft/sqlserver/jdbc/StreamSSPI.java index 1a9b4d346..e56f60def 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/StreamSSPI.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/StreamSSPI.java @@ -1,30 +1,27 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -/** - * StreamSSPi represents a TDS SSPI processing. - * - */ - -final class StreamSSPI extends StreamPacket { - byte sspiBlob[]; - - StreamSSPI() { - super(TDS.TDS_SSPI); - } - - void setFromTDS(TDSReader tdsReader) throws SQLServerException { - if (TDS.TDS_SSPI != tdsReader.readUnsignedByte()) - assert false; - int blobLength = tdsReader.readUnsignedShort(); - sspiBlob = new byte[blobLength]; - tdsReader.readBytes(sspiBlob, 0, blobLength); - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +/** + * StreamSSPi represents a TDS SSPI processing. + * + */ + +final class StreamSSPI extends StreamPacket { + byte sspiBlob[]; + + StreamSSPI() { + super(TDS.TDS_SSPI); + } + + void setFromTDS(TDSReader tdsReader) throws SQLServerException { + if (TDS.TDS_SSPI != tdsReader.readUnsignedByte()) + assert false; + int blobLength = tdsReader.readUnsignedShort(); + sspiBlob = new byte[blobLength]; + tdsReader.readBytes(sspiBlob, 0, blobLength); + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/StreamTabName.java b/src/main/java/com/microsoft/sqlserver/jdbc/StreamTabName.java index 31acff46f..8d314b08e 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/StreamTabName.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/StreamTabName.java @@ -1,54 +1,50 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -/** - * StreamTabName interprets the data stream from a TABNAME TDS token - * - */ - -final class StreamTabName extends StreamPacket { - private TDSReader tdsReader; - private TDSReaderMark tableNamesMark; - - StreamTabName() { - super(TDS.TDS_TABNAME); - } - - void setFromTDS(TDSReader tdsReader) throws SQLServerException { - if (TDS.TDS_TABNAME != tdsReader.readUnsignedByte()) - assert false : "Not a TABNAME token"; - - this.tdsReader = tdsReader; - int tokenLength = tdsReader.readUnsignedShort(); - tableNamesMark = tdsReader.mark(); - tdsReader.skip(tokenLength); - } - - void applyTo(Column[] columns, - int numTables) throws SQLServerException { - TDSReaderMark currentMark = tdsReader.mark(); - tdsReader.reset(tableNamesMark); - - // Read in all of the multi-part table names. The number of table - // names to expect is determined in advance. It is computed as a side - // effect of processing the COLINFO token that preceeds this TABNAME token. - SQLIdentifier[] tableNames = new SQLIdentifier[numTables]; - for (int i = 0; i < numTables; i++) - tableNames[i] = tdsReader.readSQLIdentifier(); - - // Apply the table names to their appropriate columns - for (Column col : columns) { - if (col.getTableNum() > 0) - col.setTableName(tableNames[col.getTableNum() - 1]); - } - - tdsReader.reset(currentMark); - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +/** + * StreamTabName interprets the data stream from a TABNAME TDS token + * + */ + +final class StreamTabName extends StreamPacket { + private TDSReader tdsReader; + private TDSReaderMark tableNamesMark; + + StreamTabName() { + super(TDS.TDS_TABNAME); + } + + void setFromTDS(TDSReader tdsReader) throws SQLServerException { + if (TDS.TDS_TABNAME != tdsReader.readUnsignedByte()) + assert false : "Not a TABNAME token"; + + this.tdsReader = tdsReader; + int tokenLength = tdsReader.readUnsignedShort(); + tableNamesMark = tdsReader.mark(); + tdsReader.skip(tokenLength); + } + + void applyTo(Column[] columns, int numTables) throws SQLServerException { + TDSReaderMark currentMark = tdsReader.mark(); + tdsReader.reset(tableNamesMark); + + // Read in all of the multi-part table names. The number of table + // names to expect is determined in advance. It is computed as a side + // effect of processing the COLINFO token that preceeds this TABNAME token. + SQLIdentifier[] tableNames = new SQLIdentifier[numTables]; + for (int i = 0; i < numTables; i++) + tableNames[i] = tdsReader.readSQLIdentifier(); + + // Apply the table names to their appropriate columns + for (Column col : columns) { + if (col.getTableNum() > 0) + col.setTableName(tableNames[col.getTableNum() - 1]); + } + + tdsReader.reset(currentMark); + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/StringUtils.java b/src/main/java/com/microsoft/sqlserver/jdbc/StringUtils.java index 241a5e2ca..d481117d8 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/StringUtils.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/StringUtils.java @@ -1,67 +1,67 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -/** - * Utility class for Strings. - * - * @since 6.1.2 - */ -public class StringUtils { - - public static final String SPACE = " "; - - public static final String EMPTY = ""; - - /** - * Developer should not create {@code StringUtils} instance in standard programming. Instead, the class should be used as - * {@code StringUtils.isEmpty("String")} - */ - private StringUtils() { - // Hiding constructor. - } - - /** - * Checks if String is null - * - * @param charSequence - * {@link CharSequence} Can provide null - * @return {@link Boolean} if provided char sequence is null or empty / blank - * @since 6.1.2 - */ - public static boolean isEmpty(final CharSequence charSequence) { - return charSequence == null || charSequence.length() == 0; - } - - /** - * Check if String is numeric or not. - * @param str {@link String} - * @return {@link Boolean} if provided String is numeric or not. - */ - public static boolean isNumeric(final String str) { - return !isEmpty(str) && str.matches("\\d+(\\.\\d+)?"); - } - - /** - * Check if string is integer or not - * @param str {@link String} - * @return {@link Boolean} if provided String is Integer or not. - */ - public static boolean isInteger(final String str) { - try { - Integer.parseInt(str); - return true; - } - catch (NumberFormatException e) { - // Nothing. this is not integer. - } - return false; - } - -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +/** + * Provides a utility class for Strings. + * + * @since 6.1.2 + */ +public class StringUtils { + + public static final String SPACE = " "; + + public static final String EMPTY = ""; + + /** + * Developer should not create {@code StringUtils} instance in standard programming. Instead, the class should be + * used as {@code StringUtils.isEmpty("String")} + */ + private StringUtils() { + // Hiding constructor. + } + + /** + * Returns if String is null + * + * @param charSequence + * {@link CharSequence} Can provide null + * @return {@link Boolean} if provided char sequence is null or empty / blank + * @since 6.1.2 + */ + public static boolean isEmpty(final CharSequence charSequence) { + return charSequence == null || charSequence.length() == 0; + } + + /** + * Returns if String is numeric or not. + * + * @param str + * {@link String} + * @return {@link Boolean} if provided String is numeric or not. + */ + public static boolean isNumeric(final String str) { + return !isEmpty(str) && str.matches("\\d+(\\.\\d+)?"); + } + + /** + * Returns if string is integer or not + * + * @param str + * {@link String} + * @return {@link Boolean} if provided String is Integer or not. + */ + public static boolean isInteger(final String str) { + try { + Integer.parseInt(str); + return true; + } catch (NumberFormatException e) { + // Nothing. this is not integer. + } + return false; + } + +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/TVP.java b/src/main/java/com/microsoft/sqlserver/jdbc/TVP.java index fa3d07dd6..a9557c2c7 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/TVP.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/TVP.java @@ -1,477 +1,469 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.SQLException; -import java.text.MessageFormat; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -enum TVPType { - ResultSet, - ISQLServerDataRecord, - SQLServerDataTable, - Null -} - -/** - * - * Implementation of Table-valued parameters which provide an easy way to marshal multiple rows of data from a client application to SQL Server - * without requiring multiple round trips or special server-side logic for processing the data. - *

- * You can use table-valued parameters to encapsulate rows of data in a client application and send the data to the server in a single parameterized - * command. The incoming data rows are stored in a table variable that can then be operated on by using Transact-SQL. - *

- * Column values in table-valued parameters can be accessed using standard Transact-SQL SELECT statements. Table-valued parameters are strongly typed - * and their structure is automatically validated. The size of table-valued parameters is limited only by server memory. - *

- * You cannot return data in a table-valued parameter. Table-valued parameters are input-only; the OUTPUT keyword is not supported. - */ -class TVP { - - String TVPName; - String TVP_owningSchema; - String TVP_dbName; - ResultSet sourceResultSet = null; - SQLServerDataTable sourceDataTable = null; - Map columnMetadata = null; - Iterator> sourceDataTableRowIterator = null; - ISQLServerDataRecord sourceRecord = null; - TVPType tvpType = null; - Set columnNames = null; - - // MultiPartIdentifierState - enum MPIState { - MPI_Value, - MPI_ParseNonQuote, - MPI_LookForSeparator, - MPI_LookForNextCharOrSeparator, - MPI_ParseQuote, - MPI_RightQuote, - }; - - void initTVP(TVPType type, - String tvpPartName) throws SQLServerException { - tvpType = type; - columnMetadata = new LinkedHashMap<>(); - parseTypeName(tvpPartName); - } - - TVP(String tvpPartName) throws SQLServerException { - initTVP(TVPType.Null, tvpPartName); - } - - // Name used in CREATE TYPE - TVP(String tvpPartName, - SQLServerDataTable tvpDataTable) throws SQLServerException { - if (tvpPartName == null) { - tvpPartName = tvpDataTable.getTvpName(); - } - initTVP(TVPType.SQLServerDataTable, tvpPartName); - sourceDataTable = tvpDataTable; - sourceDataTableRowIterator = sourceDataTable.getIterator(); - populateMetadataFromDataTable(); - } - - TVP(String tvpPartName, - ResultSet tvpResultSet) throws SQLServerException { - initTVP(TVPType.ResultSet, tvpPartName); - sourceResultSet = tvpResultSet; - // Populate TVP metdata from ResultSetMetadta. - populateMetadataFromResultSet(); - } - - TVP(String tvpPartName, - ISQLServerDataRecord tvpRecord) throws SQLServerException { - initTVP(TVPType.ISQLServerDataRecord, tvpPartName); - sourceRecord = tvpRecord; - columnNames = new HashSet<>(); - // Populate TVP metdata from ISQLServerDataRecord. - populateMetadataFromDataRecord(); - - // validate sortOrdinal and throw all relavent exceptions before proceeding - validateOrderProperty(); - } - - boolean isNull() { - return (TVPType.Null == tvpType); - } - - Object[] getRowData() throws SQLServerException { - if (TVPType.ResultSet == tvpType) { - int colCount = columnMetadata.size(); - Object[] rowData = new Object[colCount]; - for (int i = 0; i < colCount; i++) { - try { - // for Time types, getting Timestamp instead of Time, because this value will be converted to String later on. If the value is a - // time object, the millisecond would be removed. - if (java.sql.Types.TIME == sourceResultSet.getMetaData().getColumnType(i + 1)) { - rowData[i] = sourceResultSet.getTimestamp(i + 1); - } - else { - rowData[i] = sourceResultSet.getObject(i + 1); - } - } - catch (SQLException e) { - throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveSourceData"), e); - } - } - return rowData; - } - else if (TVPType.SQLServerDataTable == tvpType) { - Map.Entry rowPair = sourceDataTableRowIterator.next(); - return rowPair.getValue(); - } - else - return sourceRecord.getRowData(); - } - - boolean next() throws SQLServerException { - if (TVPType.ResultSet == tvpType) { - try { - return sourceResultSet.next(); - } - catch (SQLException e) { - throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveSourceData"), e); - } - } - else if (TVPType.SQLServerDataTable == tvpType) { - return sourceDataTableRowIterator.hasNext(); - } - else - return sourceRecord.next(); - } - - void populateMetadataFromDataTable() throws SQLServerException { - assert null != sourceDataTable; - - Map dataTableMetaData = sourceDataTable.getColumnMetadata(); - if (null == dataTableMetaData || dataTableMetaData.isEmpty()) { - throw new SQLServerException(SQLServerException.getErrString("R_TVPEmptyMetadata"), null); - } - for (Entry pair : dataTableMetaData.entrySet()) { - // duplicate column names for the dataTable will be checked in the SQLServerDataTable. - columnMetadata.put(pair.getKey(), - new SQLServerMetaData(pair.getValue().columnName, pair.getValue().javaSqlType, pair.getValue().precision, pair.getValue().scale)); - } - } - - void populateMetadataFromResultSet() throws SQLServerException { - assert null != sourceResultSet; - try { - ResultSetMetaData rsmd = sourceResultSet.getMetaData(); - for (int i = 0; i < rsmd.getColumnCount(); i++) { - SQLServerMetaData columnMetaData = new SQLServerMetaData(rsmd.getColumnName(i + 1), rsmd.getColumnType(i + 1), - rsmd.getPrecision(i + 1), rsmd.getScale(i + 1)); - columnMetadata.put(i, columnMetaData); - } - } - catch (SQLException e) { - throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveColMeta"), e); - } - } - - void populateMetadataFromDataRecord() throws SQLServerException { - assert null != sourceRecord; - if (0 >= sourceRecord.getColumnCount()) { - throw new SQLServerException(SQLServerException.getErrString("R_TVPEmptyMetadata"), null); - } - for (int i = 0; i < sourceRecord.getColumnCount(); i++) { - Util.checkDuplicateColumnName(sourceRecord.getColumnMetaData(i + 1).columnName, columnNames); - - // Make a copy here as we do not want to change user's metadata. - SQLServerMetaData metaData = new SQLServerMetaData(sourceRecord.getColumnMetaData(i + 1)); - columnMetadata.put(i, metaData); - } - } - - void validateOrderProperty() throws SQLServerException { - int columnCount = columnMetadata.size(); - boolean[] sortOrdinalSpecified = new boolean[columnCount]; - - int maxSortOrdinal = -1; - int sortCount = 0; - for (Entry columnPair : columnMetadata.entrySet()) { - SQLServerSortOrder columnSortOrder = columnPair.getValue().sortOrder; - int columnSortOrdinal = columnPair.getValue().sortOrdinal; - - if (SQLServerSortOrder.Unspecified != columnSortOrder) { - // check if there's no way sort order could be monotonically increasing - if (columnCount <= columnSortOrdinal) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_TVPSortOrdinalGreaterThanFieldCount")); - throw new SQLServerException(form.format(new Object[]{columnSortOrdinal, columnPair.getKey()}), null, 0, null); - } - - // Check to make sure we haven't seen this ordinal before - if (sortOrdinalSpecified[columnSortOrdinal]) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_TVPDuplicateSortOrdinal")); - throw new SQLServerException(form.format(new Object[]{columnSortOrdinal}), null, 0, null); - } - - sortOrdinalSpecified[columnSortOrdinal] = true; - if (columnSortOrdinal > maxSortOrdinal) - maxSortOrdinal = columnSortOrdinal; - - sortCount++; - } - } - - if (0 < sortCount) { - // validate monotonically increasing sort order. watch for values outside of the sortCount range. - if (maxSortOrdinal >= sortCount) { - // there is at least one hole, find the first one - int i; - for (i = 0; i < sortCount; i++) { - if (!sortOrdinalSpecified[i]) - break; - } - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_TVPMissingSortOrdinal")); - throw new SQLServerException(form.format(new Object[] {i}), null, 0, null); - } - } - } - - void parseTypeName(String name) throws SQLServerException { - String leftQuote = "[\""; - String rightQuote = "]\""; - char separator = '.'; - int limit = 3; // DbName, SchemaName, table type name - String[] parsedNames = new String[limit]; - int stringCount = 0; // index of current string in the buffer - - if ((null == name) || (0 == name.length())) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidTVPName")); - Object[] msgArgs = {}; - throw new SQLServerException(null, form.format(msgArgs), null, 0, false); - } - - StringBuilder sb = new StringBuilder(name.length()); - - // String buffer to hold white space used when parsing nonquoted strings 'a b . c d' = 'a b' and 'c d' - StringBuilder whitespaceSB = null; - - // Right quote character to use given the left quote character found. - char rightQuoteChar = ' '; - MPIState state = MPIState.MPI_Value; - - for (int index = 0; index < name.length(); ++index) { - char testchar = name.charAt(index); - switch (state) { - case MPI_Value: - int quoteIndex; - if (Character.isWhitespace(testchar)) // skip the whitespace - continue; - else if (testchar == separator) { - // If separator was found,but no string was found, initialize the string we are parsing to Empty. - parsedNames[stringCount] = ""; - stringCount++; - } - else if (-1 != (quoteIndex = leftQuote.indexOf(testchar))) { - // If we are at left quote - rightQuoteChar = rightQuote.charAt(quoteIndex); // record the corresponding right quote for the left quote - sb.setLength(0); - state = MPIState.MPI_ParseQuote; - } - else if (-1 != rightQuote.indexOf(testchar)) { - // If we shouldn't see a right quote - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidThreePartName")); - throw new SQLServerException(null, form.format(new Object[] {}), null, 0, false); - } - else { - sb.setLength(0); - sb.append(testchar); - state = MPIState.MPI_ParseNonQuote; - } - break; - - case MPI_ParseNonQuote: - if (testchar == separator) { - parsedNames[stringCount] = sb.toString(); // set the currently parsed string - stringCount = incrementStringCount(parsedNames, stringCount); - state = MPIState.MPI_Value; - } - // Quotes are not valid inside a non-quoted name - else if ((-1 != rightQuote.indexOf(testchar)) || (-1 != leftQuote.indexOf(testchar))) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidThreePartName")); - throw new SQLServerException(null, form.format(new Object[] {}), null, 0, false); - } - else if (Character.isWhitespace(testchar)) { - // If it is Whitespace - parsedNames[stringCount] = sb.toString(); // Set the currently parsed string - if (null == whitespaceSB) - whitespaceSB = new StringBuilder(); - whitespaceSB.setLength(0); - // start to record the white space, if we are parsing a name like "foo bar" we should return "foo bar" - whitespaceSB.append(testchar); - state = MPIState.MPI_LookForNextCharOrSeparator; - } - else - sb.append(testchar); - - break; - - case MPI_LookForNextCharOrSeparator: - if (!Character.isWhitespace(testchar)) { - // If it is not whitespace - if (testchar == separator) { - stringCount = incrementStringCount(parsedNames, stringCount); - state = MPIState.MPI_Value; - } - else { - // If its not a separator and not whitespace - sb.append(whitespaceSB); - sb.append(testchar); - parsedNames[stringCount] = sb.toString(); // Need to set the name here in case the string ends here. - state = MPIState.MPI_ParseNonQuote; - } - } - else { - if (null == whitespaceSB) { - whitespaceSB = new StringBuilder(); - } - whitespaceSB.append(testchar); - } - break; - - case MPI_ParseQuote: - // if are on a right quote see if we are escapeing the right quote or ending the quoted string - if (testchar == rightQuoteChar) - state = MPIState.MPI_RightQuote; - else - sb.append(testchar); // Append what we are currently parsing - break; - - case MPI_RightQuote: - if (testchar == rightQuoteChar) { - // If the next char is a another right quote then we were escapeing the right quote - sb.append(testchar); - state = MPIState.MPI_ParseQuote; - } - else if (testchar == separator) { - // If its a separator then record what we've parsed - parsedNames[stringCount] = sb.toString(); - stringCount = incrementStringCount(parsedNames, stringCount); - state = MPIState.MPI_Value; - } - else if (!Character.isWhitespace(testchar)) { - // If it is not white space we got problems - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidThreePartName")); - throw new SQLServerException(null, form.format(new Object[] {}), null, 0, false); - } - else { - // It is a whitespace character - // the following char should be whitespace, separator, or end of string anything else is bad - parsedNames[stringCount] = sb.toString(); - state = MPIState.MPI_LookForSeparator; - } - break; - - case MPI_LookForSeparator: - if (!Character.isWhitespace(testchar)) { - // If it is not whitespace - if (testchar == separator) { - // If it is a separator - stringCount = incrementStringCount(parsedNames, stringCount); - state = MPIState.MPI_Value; - } - else { - // not a separator - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidThreePartName")); - throw new SQLServerException(null, form.format(new Object[] {}), null, 0, false); - } - } - break; - } - } - - if (stringCount > limit - 1) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidThreePartName")); - throw new SQLServerException(null, form.format(new Object[] {}), null, 0, false); - } - - // Resolve final states after parsing the string - switch (state) { - case MPI_Value: // These states require no extra action - case MPI_LookForSeparator: - case MPI_LookForNextCharOrSeparator: - break; - - case MPI_ParseNonQuote: // Dump what ever was parsed - case MPI_RightQuote: - parsedNames[stringCount] = sb.toString(); - break; - - case MPI_ParseQuote: // Invalid Ending States - default: - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidThreePartName")); - throw new SQLServerException(null, form.format(new Object[] {}), null, 0, false); - } - - if (parsedNames[0] == null) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidThreePartName")); - throw new SQLServerException(null, form.format(new Object[] {}), null, 0, false); - } - else { - // Shuffle the parsed name, from left justification to right justification, ie [a][b][null][null] goes to [null][null][a][b] - int offset = limit - stringCount - 1; - if (offset > 0) { - for (int x = limit - 1; x >= offset; --x) { - parsedNames[x] = parsedNames[x - offset]; - parsedNames[x - offset] = null; - } - } - } - this.TVPName = parsedNames[2]; - this.TVP_owningSchema = parsedNames[1]; - this.TVP_dbName = parsedNames[0]; - } - - /* - * parsing the multipart identifer string. paramaters: name - string to parse leftquote: set of characters which are valid quoteing characters to - * initiate a quote rightquote: set of characters which are valid to stop a quote, array index's correspond to the the leftquote array. separator: - * separator to use limit: number of names to parse out removequote:to remove the quotes on the returned string - */ - private int incrementStringCount(String[] ary, - int position) throws SQLServerException { - ++position; - int limit = ary.length; - if (position >= limit) { - MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidThreePartName")); - throw new SQLServerException(null, form.format(new Object[] {}), null, 0, false); - } - ary[position] = new String(); - return position; - } - - String getTVPName() { - return TVPName; - } - - String getDbNameTVP() { - return TVP_dbName; - } - - String getOwningSchemaNameTVP() { - return TVP_owningSchema; - } - - int getTVPColumnCount() { - return columnMetadata.size(); - } - - Map getColumnMetadata() { - return columnMetadata; - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.text.MessageFormat; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + + +enum TVPType { + ResultSet, + ISQLServerDataRecord, + SQLServerDataTable, + Null +} + + +/** + * + * Implementation of Table-valued parameters which provide an easy way to marshal multiple rows of data from a client + * application to SQL Server without requiring multiple round trips or special server-side logic for processing the + * data. + *

+ * You can use table-valued parameters to encapsulate rows of data in a client application and send the data to the + * server in a single parameterized command. The incoming data rows are stored in a table variable that can then be + * operated on by using Transact-SQL. + *

+ * Column values in table-valued parameters can be accessed using standard Transact-SQL SELECT statements. Table-valued + * parameters are strongly typed and their structure is automatically validated. The size of table-valued parameters is + * limited only by server memory. + *

+ * You cannot return data in a table-valued parameter. Table-valued parameters are input-only; the OUTPUT keyword is not + * supported. + */ +class TVP { + + String TVPName; + String TVP_owningSchema; + String TVP_dbName; + ResultSet sourceResultSet = null; + SQLServerDataTable sourceDataTable = null; + Map columnMetadata = null; + Iterator> sourceDataTableRowIterator = null; + ISQLServerDataRecord sourceRecord = null; + TVPType tvpType = null; + Set columnNames = null; + + // MultiPartIdentifierState + enum MPIState { + MPI_Value, + MPI_ParseNonQuote, + MPI_LookForSeparator, + MPI_LookForNextCharOrSeparator, + MPI_ParseQuote, + MPI_RightQuote, + }; + + void initTVP(TVPType type, String tvpPartName) throws SQLServerException { + tvpType = type; + columnMetadata = new LinkedHashMap<>(); + parseTypeName(tvpPartName); + } + + TVP(String tvpPartName) throws SQLServerException { + initTVP(TVPType.Null, tvpPartName); + } + + // Name used in CREATE TYPE + TVP(String tvpPartName, SQLServerDataTable tvpDataTable) throws SQLServerException { + if (tvpPartName == null) { + tvpPartName = tvpDataTable.getTvpName(); + } + initTVP(TVPType.SQLServerDataTable, tvpPartName); + sourceDataTable = tvpDataTable; + sourceDataTableRowIterator = sourceDataTable.getIterator(); + populateMetadataFromDataTable(); + } + + TVP(String tvpPartName, ResultSet tvpResultSet) throws SQLServerException { + initTVP(TVPType.ResultSet, tvpPartName); + sourceResultSet = tvpResultSet; + // Populate TVP metdata from ResultSetMetadta. + populateMetadataFromResultSet(); + } + + TVP(String tvpPartName, ISQLServerDataRecord tvpRecord) throws SQLServerException { + initTVP(TVPType.ISQLServerDataRecord, tvpPartName); + sourceRecord = tvpRecord; + columnNames = new HashSet<>(); + // Populate TVP metdata from ISQLServerDataRecord. + populateMetadataFromDataRecord(); + + // validate sortOrdinal and throw all relavent exceptions before proceeding + validateOrderProperty(); + } + + boolean isNull() { + return (TVPType.Null == tvpType); + } + + Object[] getRowData() throws SQLServerException { + if (TVPType.ResultSet == tvpType) { + int colCount = columnMetadata.size(); + Object[] rowData = new Object[colCount]; + for (int i = 0; i < colCount; i++) { + try { + // for Time types, getting Timestamp instead of Time, because this value will be converted to String + // later on. If the value is a + // time object, the millisecond would be removed. + if (java.sql.Types.TIME == sourceResultSet.getMetaData().getColumnType(i + 1)) { + rowData[i] = sourceResultSet.getTimestamp(i + 1); + } else { + rowData[i] = sourceResultSet.getObject(i + 1); + } + } catch (SQLException e) { + throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveSourceData"), e); + } + } + return rowData; + } else if (TVPType.SQLServerDataTable == tvpType) { + Map.Entry rowPair = sourceDataTableRowIterator.next(); + return rowPair.getValue(); + } else + return sourceRecord.getRowData(); + } + + boolean next() throws SQLServerException { + if (TVPType.ResultSet == tvpType) { + try { + return sourceResultSet.next(); + } catch (SQLException e) { + throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveSourceData"), e); + } + } else if (TVPType.SQLServerDataTable == tvpType) { + return sourceDataTableRowIterator.hasNext(); + } else + return sourceRecord.next(); + } + + void populateMetadataFromDataTable() throws SQLServerException { + assert null != sourceDataTable; + + Map dataTableMetaData = sourceDataTable.getColumnMetadata(); + if (null == dataTableMetaData || dataTableMetaData.isEmpty()) { + throw new SQLServerException(SQLServerException.getErrString("R_TVPEmptyMetadata"), null); + } + for (Entry pair : dataTableMetaData.entrySet()) { + // duplicate column names for the dataTable will be checked in the SQLServerDataTable. + columnMetadata.put(pair.getKey(), new SQLServerMetaData(pair.getValue().columnName, + pair.getValue().javaSqlType, pair.getValue().precision, pair.getValue().scale)); + } + } + + void populateMetadataFromResultSet() throws SQLServerException { + assert null != sourceResultSet; + try { + ResultSetMetaData rsmd = sourceResultSet.getMetaData(); + for (int i = 0; i < rsmd.getColumnCount(); i++) { + SQLServerMetaData columnMetaData = new SQLServerMetaData(rsmd.getColumnName(i + 1), + rsmd.getColumnType(i + 1), rsmd.getPrecision(i + 1), rsmd.getScale(i + 1)); + columnMetadata.put(i, columnMetaData); + } + } catch (SQLException e) { + throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveColMeta"), e); + } + } + + void populateMetadataFromDataRecord() throws SQLServerException { + assert null != sourceRecord; + if (0 >= sourceRecord.getColumnCount()) { + throw new SQLServerException(SQLServerException.getErrString("R_TVPEmptyMetadata"), null); + } + for (int i = 0; i < sourceRecord.getColumnCount(); i++) { + Util.checkDuplicateColumnName(sourceRecord.getColumnMetaData(i + 1).columnName, columnNames); + + // Make a copy here as we do not want to change user's metadata. + SQLServerMetaData metaData = new SQLServerMetaData(sourceRecord.getColumnMetaData(i + 1)); + columnMetadata.put(i, metaData); + } + } + + void validateOrderProperty() throws SQLServerException { + int columnCount = columnMetadata.size(); + boolean[] sortOrdinalSpecified = new boolean[columnCount]; + + int maxSortOrdinal = -1; + int sortCount = 0; + for (Entry columnPair : columnMetadata.entrySet()) { + SQLServerSortOrder columnSortOrder = columnPair.getValue().sortOrder; + int columnSortOrdinal = columnPair.getValue().sortOrdinal; + + if (SQLServerSortOrder.Unspecified != columnSortOrder) { + // check if there's no way sort order could be monotonically increasing + if (columnCount <= columnSortOrdinal) { + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_TVPSortOrdinalGreaterThanFieldCount")); + throw new SQLServerException(form.format(new Object[] {columnSortOrdinal, columnPair.getKey()}), + null, 0, null); + } + + // Check to make sure we haven't seen this ordinal before + if (sortOrdinalSpecified[columnSortOrdinal]) { + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_TVPDuplicateSortOrdinal")); + throw new SQLServerException(form.format(new Object[] {columnSortOrdinal}), null, 0, null); + } + + sortOrdinalSpecified[columnSortOrdinal] = true; + if (columnSortOrdinal > maxSortOrdinal) + maxSortOrdinal = columnSortOrdinal; + + sortCount++; + } + } + + if (0 < sortCount) { + // validate monotonically increasing sort order. watch for values outside of the sortCount range. + if (maxSortOrdinal >= sortCount) { + // there is at least one hole, find the first one + int i; + for (i = 0; i < sortCount; i++) { + if (!sortOrdinalSpecified[i]) + break; + } + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_TVPMissingSortOrdinal")); + throw new SQLServerException(form.format(new Object[] {i}), null, 0, null); + } + } + } + + void parseTypeName(String name) throws SQLServerException { + String leftQuote = "[\""; + String rightQuote = "]\""; + char separator = '.'; + int limit = 3; // DbName, SchemaName, table type name + String[] parsedNames = new String[limit]; + int stringCount = 0; // index of current string in the buffer + + if ((null == name) || (0 == name.length())) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidTVPName")); + Object[] msgArgs = {}; + throw new SQLServerException(null, form.format(msgArgs), null, 0, false); + } + + StringBuilder sb = new StringBuilder(name.length()); + + // String buffer to hold white space used when parsing nonquoted strings 'a b . c d' = 'a b' and 'c d' + StringBuilder whitespaceSB = null; + + // Right quote character to use given the left quote character found. + char rightQuoteChar = ' '; + MPIState state = MPIState.MPI_Value; + + for (int index = 0; index < name.length(); ++index) { + char testchar = name.charAt(index); + switch (state) { + case MPI_Value: + int quoteIndex; + if (Character.isWhitespace(testchar)) // skip the whitespace + continue; + else if (testchar == separator) { + // If separator was found,but no string was found, initialize the string we are parsing to + // Empty. + parsedNames[stringCount] = ""; + stringCount++; + } else if (-1 != (quoteIndex = leftQuote.indexOf(testchar))) { + // If we are at left quote + rightQuoteChar = rightQuote.charAt(quoteIndex); // record the corresponding right quote for the + // left quote + sb.setLength(0); + state = MPIState.MPI_ParseQuote; + } else if (-1 != rightQuote.indexOf(testchar)) { + // If we shouldn't see a right quote + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_invalidThreePartName")); + throw new SQLServerException(null, form.format(new Object[] {}), null, 0, false); + } else { + sb.setLength(0); + sb.append(testchar); + state = MPIState.MPI_ParseNonQuote; + } + break; + + case MPI_ParseNonQuote: + if (testchar == separator) { + parsedNames[stringCount] = sb.toString(); // set the currently parsed string + stringCount = incrementStringCount(parsedNames, stringCount); + state = MPIState.MPI_Value; + } + // Quotes are not valid inside a non-quoted name + else if ((-1 != rightQuote.indexOf(testchar)) || (-1 != leftQuote.indexOf(testchar))) { + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_invalidThreePartName")); + throw new SQLServerException(null, form.format(new Object[] {}), null, 0, false); + } else if (Character.isWhitespace(testchar)) { + // If it is Whitespace + parsedNames[stringCount] = sb.toString(); // Set the currently parsed string + if (null == whitespaceSB) + whitespaceSB = new StringBuilder(); + whitespaceSB.setLength(0); + // start to record the white space, if we are parsing a name like "foo bar" we should return + // "foo bar" + whitespaceSB.append(testchar); + state = MPIState.MPI_LookForNextCharOrSeparator; + } else + sb.append(testchar); + + break; + + case MPI_LookForNextCharOrSeparator: + if (!Character.isWhitespace(testchar)) { + // If it is not whitespace + if (testchar == separator) { + stringCount = incrementStringCount(parsedNames, stringCount); + state = MPIState.MPI_Value; + } else { + // If its not a separator and not whitespace + sb.append(whitespaceSB); + sb.append(testchar); + parsedNames[stringCount] = sb.toString(); // Need to set the name here in case the string + // ends here. + state = MPIState.MPI_ParseNonQuote; + } + } else { + if (null == whitespaceSB) { + whitespaceSB = new StringBuilder(); + } + whitespaceSB.append(testchar); + } + break; + + case MPI_ParseQuote: + // if are on a right quote see if we are escapeing the right quote or ending the quoted string + if (testchar == rightQuoteChar) + state = MPIState.MPI_RightQuote; + else + sb.append(testchar); // Append what we are currently parsing + break; + + case MPI_RightQuote: + if (testchar == rightQuoteChar) { + // If the next char is a another right quote then we were escapeing the right quote + sb.append(testchar); + state = MPIState.MPI_ParseQuote; + } else if (testchar == separator) { + // If its a separator then record what we've parsed + parsedNames[stringCount] = sb.toString(); + stringCount = incrementStringCount(parsedNames, stringCount); + state = MPIState.MPI_Value; + } else if (!Character.isWhitespace(testchar)) { + // If it is not white space we got problems + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_invalidThreePartName")); + throw new SQLServerException(null, form.format(new Object[] {}), null, 0, false); + } else { + // It is a whitespace character + // the following char should be whitespace, separator, or end of string anything else is bad + parsedNames[stringCount] = sb.toString(); + state = MPIState.MPI_LookForSeparator; + } + break; + + case MPI_LookForSeparator: + if (!Character.isWhitespace(testchar)) { + // If it is not whitespace + if (testchar == separator) { + // If it is a separator + stringCount = incrementStringCount(parsedNames, stringCount); + state = MPIState.MPI_Value; + } else { + // not a separator + MessageFormat form = new MessageFormat( + SQLServerException.getErrString("R_invalidThreePartName")); + throw new SQLServerException(null, form.format(new Object[] {}), null, 0, false); + } + } + break; + } + } + + if (stringCount > limit - 1) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidThreePartName")); + throw new SQLServerException(null, form.format(new Object[] {}), null, 0, false); + } + + // Resolve final states after parsing the string + switch (state) { + case MPI_Value: // These states require no extra action + case MPI_LookForSeparator: + case MPI_LookForNextCharOrSeparator: + break; + + case MPI_ParseNonQuote: // Dump what ever was parsed + case MPI_RightQuote: + parsedNames[stringCount] = sb.toString(); + break; + + case MPI_ParseQuote: // Invalid Ending States + default: + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidThreePartName")); + throw new SQLServerException(null, form.format(new Object[] {}), null, 0, false); + } + + if (parsedNames[0] == null) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidThreePartName")); + throw new SQLServerException(null, form.format(new Object[] {}), null, 0, false); + } else { + // Shuffle the parsed name, from left justification to right justification, ie [a][b][null][null] goes to + // [null][null][a][b] + int offset = limit - stringCount - 1; + if (offset > 0) { + for (int x = limit - 1; x >= offset; --x) { + parsedNames[x] = parsedNames[x - offset]; + parsedNames[x - offset] = null; + } + } + } + this.TVPName = parsedNames[2]; + this.TVP_owningSchema = parsedNames[1]; + this.TVP_dbName = parsedNames[0]; + } + + /* + * parsing the multipart identifer string. paramaters: name - string to parse leftquote: set of characters which are + * valid quoteing characters to initiate a quote rightquote: set of characters which are valid to stop a quote, + * array index's correspond to the the leftquote array. separator: separator to use limit: number of names to parse + * out removequote:to remove the quotes on the returned string + */ + private int incrementStringCount(String[] ary, int position) throws SQLServerException { + ++position; + int limit = ary.length; + if (position >= limit) { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidThreePartName")); + throw new SQLServerException(null, form.format(new Object[] {}), null, 0, false); + } + ary[position] = new String(); + return position; + } + + String getTVPName() { + return TVPName; + } + + String getDbNameTVP() { + return TVP_dbName; + } + + String getOwningSchemaNameTVP() { + return TVP_owningSchema; + } + + int getTVPColumnCount() { + return columnMetadata.size(); + } + + Map getColumnMetadata() { + return columnMetadata; + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ThreePartName.java b/src/main/java/com/microsoft/sqlserver/jdbc/ThreePartName.java index dc6e21be8..d426b86ba 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ThreePartName.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ThreePartName.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -11,11 +8,12 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; + class ThreePartName { /* - * Three part names parsing For metdata calls we parse the procedure name into parts so we can use it in sp_sproc_columns sp_sproc_columns - * [[@procedure_name =] 'name'] [,[@procedure_owner =] 'owner'] [,[@procedure_qualifier =] 'qualifier'] - * + * Three part names parsing For metdata calls we parse the procedure name into parts so we can use it in + * sp_sproc_columns sp_sproc_columns [[@procedure_name =] 'name'] [,[@procedure_owner =] 'owner'] + * [,[@procedure_qualifier =] 'qualifier'] */ private static final Pattern THREE_PART_NAME = Pattern.compile(JDBCSyntaxTranslator.getSQLIdentifierWithGroups()); @@ -58,19 +56,16 @@ static ThreePartName parse(String theProcName) { if (null != matcher.group(2)) { ownerPart = matcher.group(1); procedurePart = matcher.group(2); - } - else { + } else { ownerPart = databasePart; databasePart = null; procedurePart = matcher.group(1); } } - } - else { + } else { procedurePart = matcher.group(1); } - } - else { + } else { procedurePart = theProcName; } } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/UDTTDSHeader.java b/src/main/java/com/microsoft/sqlserver/jdbc/UDTTDSHeader.java index 09f0fe0de..4d848aa0f 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/UDTTDSHeader.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/UDTTDSHeader.java @@ -1,52 +1,45 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -/** -* UDTTDSHeader is helper class used to read and write the UDT TDS 7.2x header from a TDS stream. -* -* Typical UDT header-> -* -* UDT header with schema/type/assembly information -* -* F0 -* 21 00 <- MaxLen (2 byte length) -* 03|54 00 44 00 53 00 <- DB_NAME (1 byte length in UNICODE chars) -* 03|64 00 62 00 6F 00 <- SCHEMA_NAME (1 byte length in UNICODE chars) -* 12|4D 00 79 00 43 00 68 00 75 00 6E 00 6B 00 79 <- TYPE_NAME (1 byte length in UNICODE chars) -* 00 46 00 75 00 6E 00 6B 00 79 00 54 00 79 00 70 00 65 00 32 00 -* 63 00|4D 00 79 00 43 00 68 00 75 00 6E 00 6B 00 <- ASSEMBLY_QUALIFIED_NAME (2 byte length in UNICODE chars) -* 79 00 46 00 75 00 6E 00 6B 00 79 00 54 00 79 00 -* 70 00 65 00 32 00 2C 00 20 00 53 00 71 00 6C 00 -* -*/ - -final class UDTTDSHeader { - private final int maxLen; // MaxLen read from UDT type (not used when writing). - private final String databaseName; // Database name where UDT type resides. - private final String schemaName; // Schema where UDT resides. - private final String typeName; // Type name of UDT. - private final String assemblyQualifiedName; // Assembly qualified name of UDT. - - UDTTDSHeader(TDSReader tdsReader) throws SQLServerException { - maxLen = tdsReader.readUnsignedShort(); - databaseName = tdsReader.readUnicodeString(tdsReader.readUnsignedByte()); - schemaName = tdsReader.readUnicodeString(tdsReader.readUnsignedByte()); - typeName = tdsReader.readUnicodeString(tdsReader.readUnsignedByte()); - assemblyQualifiedName = tdsReader.readUnicodeString(tdsReader.readUnsignedShort()); - } - - int getMaxLen() { - return maxLen; - } - - String getTypeName() { - return typeName; - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +/** + * UDTTDSHeader is helper class used to read and write the UDT TDS 7.2x header from a TDS stream. + * + * Typical UDT header-> + * + * UDT header with schema/type/assembly information + * + * F0 21 00 <- MaxLen (2 byte length) 03|54 00 44 00 53 00 <- DB_NAME (1 byte length in UNICODE chars) 03|64 00 62 00 6F + * 00 <- SCHEMA_NAME (1 byte length in UNICODE chars) 12|4D 00 79 00 43 00 68 00 75 00 6E 00 6B 00 79 <- TYPE_NAME (1 + * byte length in UNICODE chars) 00 46 00 75 00 6E 00 6B 00 79 00 54 00 79 00 70 00 65 00 32 00 63 00|4D 00 79 00 43 00 + * 68 00 75 00 6E 00 6B 00 <- ASSEMBLY_QUALIFIED_NAME (2 byte length in UNICODE chars) 79 00 46 00 75 00 6E 00 6B 00 79 + * 00 54 00 79 00 70 00 65 00 32 00 2C 00 20 00 53 00 71 00 6C 00 + * + */ + +final class UDTTDSHeader { + private final int maxLen; // MaxLen read from UDT type (not used when writing). + private final String databaseName; // Database name where UDT type resides. + private final String schemaName; // Schema where UDT resides. + private final String typeName; // Type name of UDT. + private final String assemblyQualifiedName; // Assembly qualified name of UDT. + + UDTTDSHeader(TDSReader tdsReader) throws SQLServerException { + maxLen = tdsReader.readUnsignedShort(); + databaseName = tdsReader.readUnicodeString(tdsReader.readUnsignedByte()); + schemaName = tdsReader.readUnicodeString(tdsReader.readUnsignedByte()); + typeName = tdsReader.readUnicodeString(tdsReader.readUnsignedByte()); + assemblyQualifiedName = tdsReader.readUnicodeString(tdsReader.readUnsignedShort()); + } + + int getMaxLen() { + return maxLen; + } + + String getTypeName() { + return typeName; + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/Util.java b/src/main/java/com/microsoft/sqlserver/jdbc/Util.java index d2858efb1..d1536e735 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/Util.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/Util.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -16,8 +13,6 @@ import java.text.MessageFormat; import java.util.Date; import java.util.Locale; -import java.util.Map; -import java.util.Map.Entry; import java.util.Properties; import java.util.Set; import java.util.UUID; @@ -25,6 +20,7 @@ import java.util.logging.LogManager; import java.util.logging.Logger; + /** * Various driver utilities. * @@ -100,13 +96,12 @@ static final Boolean isBinaryType(int jdbcType) { * Read a short int from a byte stream * * @param data - * the databytes + * the databytes * @param nOffset - * offset to read from + * offset to read from * @return the value */ - /* L0 */ static short readShort(byte data[], - int nOffset) { + /* L0 */ static short readShort(byte data[], int nOffset) { return (short) ((data[nOffset] & 0xff) | ((data[nOffset + 1] & 0xff) << 8)); } @@ -114,31 +109,25 @@ static final Boolean isBinaryType(int jdbcType) { * Read an unsigned short int (16 bits) from a byte stream * * @param data - * the databytes + * the databytes * @param nOffset - * offset to read from + * offset to read from * @return the value */ - /* L0 */ static int readUnsignedShort(byte data[], - int nOffset) { + /* L0 */ static int readUnsignedShort(byte data[], int nOffset) { return ((data[nOffset] & 0xff) | ((data[nOffset + 1] & 0xff) << 8)); } - static int readUnsignedShortBigEndian(byte data[], - int nOffset) { + static int readUnsignedShortBigEndian(byte data[], int nOffset) { return ((data[nOffset] & 0xFF) << 8) | (data[nOffset + 1] & 0xFF); } - static void writeShort(short value, - byte valueBytes[], - int offset) { + static void writeShort(short value, byte valueBytes[], int offset) { valueBytes[offset + 0] = (byte) ((value >> 0) & 0xFF); valueBytes[offset + 1] = (byte) ((value >> 8) & 0xFF); } - static void writeShortBigEndian(short value, - byte valueBytes[], - int offset) { + static void writeShortBigEndian(short value, byte valueBytes[], int offset) { valueBytes[offset + 0] = (byte) ((value >> 8) & 0xFF); valueBytes[offset + 1] = (byte) ((value >> 0) & 0xFF); } @@ -147,13 +136,12 @@ static void writeShortBigEndian(short value, * Read an int from a byte stream * * @param data - * the databytes + * the databytes * @param nOffset - * offset to read from + * offset to read from * @return the value */ - /* L0 */ static int readInt(byte data[], - int nOffset) { + /* L0 */ static int readInt(byte data[], int nOffset) { int b1 = ((int) data[nOffset + 0] & 0xff); int b2 = ((int) data[nOffset + 1] & 0xff) << 8; int b3 = ((int) data[nOffset + 2] & 0xff) << 16; @@ -161,33 +149,26 @@ static void writeShortBigEndian(short value, return b4 | b3 | b2 | b1; } - static int readIntBigEndian(byte data[], - int nOffset) { - return ((data[nOffset + 3] & 0xFF) << 0) | ((data[nOffset + 2] & 0xFF) << 8) | ((data[nOffset + 1] & 0xFF) << 16) - | ((data[nOffset + 0] & 0xFF) << 24); + static int readIntBigEndian(byte data[], int nOffset) { + return ((data[nOffset + 3] & 0xFF) << 0) | ((data[nOffset + 2] & 0xFF) << 8) + | ((data[nOffset + 1] & 0xFF) << 16) | ((data[nOffset + 0] & 0xFF) << 24); } - static void writeInt(int value, - byte valueBytes[], - int offset) { + static void writeInt(int value, byte valueBytes[], int offset) { valueBytes[offset + 0] = (byte) ((value >> 0) & 0xFF); valueBytes[offset + 1] = (byte) ((value >> 8) & 0xFF); valueBytes[offset + 2] = (byte) ((value >> 16) & 0xFF); valueBytes[offset + 3] = (byte) ((value >> 24) & 0xFF); } - static void writeIntBigEndian(int value, - byte valueBytes[], - int offset) { + static void writeIntBigEndian(int value, byte valueBytes[], int offset) { valueBytes[offset + 0] = (byte) ((value >> 24) & 0xFF); valueBytes[offset + 1] = (byte) ((value >> 16) & 0xFF); valueBytes[offset + 2] = (byte) ((value >> 8) & 0xFF); valueBytes[offset + 3] = (byte) ((value >> 0) & 0xFF); } - static void writeLongBigEndian(long value, - byte valueBytes[], - int offset) { + static void writeLongBigEndian(long value, byte valueBytes[], int offset) { valueBytes[offset + 0] = (byte) ((value >> 56) & 0xFF); valueBytes[offset + 1] = (byte) ((value >> 48) & 0xFF); valueBytes[offset + 2] = (byte) ((value >> 40) & 0xFF); @@ -198,9 +179,7 @@ static void writeLongBigEndian(long value, valueBytes[offset + 7] = (byte) ((value >> 0) & 0xFF); } - static BigDecimal readBigDecimal(byte valueBytes[], - int valueLength, - int scale) { + static BigDecimal readBigDecimal(byte valueBytes[], int valueLength, int scale) { int sign = (0 == valueBytes[0]) ? -1 : 1; byte[] magnitude = new byte[valueLength - 1]; for (int i = 1; i <= magnitude.length; i++) @@ -212,13 +191,12 @@ static BigDecimal readBigDecimal(byte valueBytes[], * Reads a long value from byte array. * * @param data - * the byte array. + * the byte array. * @param nOffset - * the offset into byte array to start reading. + * the offset into byte array to start reading. * @return long value as read from bytes. */ - /* L0 */static long readLong(byte data[], - int nOffset) { + /* L0 */static long readLong(byte data[], int nOffset) { long v = 0; for (int i = 7; i > 0; i--) { v += (long) (data[nOffset + i] & 0xff); @@ -231,13 +209,12 @@ static BigDecimal readBigDecimal(byte valueBytes[], * Parse a JDBC URL into a set of properties. * * @param url - * the JDBC URL + * the JDBC URL * @param logger * @return the properties * @throws SQLServerException */ - /* L0 */ static Properties parseUrl(String url, - Logger logger) throws SQLServerException { + /* L0 */ static Properties parseUrl(String url, Logger logger) throws SQLServerException { Properties p = new Properties(); String tmpUrl = url; String sPrefix = "jdbc:sqlserver://"; @@ -273,8 +250,7 @@ static BigDecimal readBigDecimal(byte valueBytes[], if (ch == ';') { // done immediately state = inName; - } - else { + } else { builder = new StringBuilder(); builder.append(result); builder.append(ch); @@ -302,8 +278,7 @@ else if (ch == ':') state = inPort; else state = inInstanceName; - } - else { + } else { builder = new StringBuilder(); builder.append(result); builder.append(ch); @@ -322,8 +297,7 @@ else if (ch == ':') p.put(SQLServerDriverIntProperty.PORT_NUMBER.toString(), result); result = ""; state = inName; - } - else { + } else { builder = new StringBuilder(); builder.append(result); builder.append(ch); @@ -346,8 +320,7 @@ else if (ch == ':') state = inName; else state = inPort; - } - else { + } else { builder = new StringBuilder(); builder.append(result); builder.append(ch); @@ -361,20 +334,18 @@ else if (ch == ':') // name is never escaped! name = name.trim(); if (name.length() <= 0) { - SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_errorConnectionString"), null, - true); + SQLServerException.makeFromDriverError(null, null, + SQLServerException.getErrString("R_errorConnectionString"), null, true); } state = inValue; - } - else if (ch == ';') { + } else if (ch == ';') { name = name.trim(); if (name.length() > 0) { - SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_errorConnectionString"), null, - true); + SQLServerException.makeFromDriverError(null, null, + SQLServerException.getErrString("R_errorConnectionString"), null, true); } // same state - } - else { + } else { builder = new StringBuilder(); builder.append(name); builder.append(ch); @@ -391,11 +362,10 @@ else if (ch == ':') if (null != name) { if (logger.isLoggable(Level.FINE)) { if (false == name.equals(SQLServerDriverStringProperty.USER.toString())) { - if (!name.toLowerCase(Locale.ENGLISH).contains("password") && - !name.toLowerCase(Locale.ENGLISH).contains("keystoresecret")) { + if (!name.toLowerCase(Locale.ENGLISH).contains("password") + && !name.toLowerCase(Locale.ENGLISH).contains("keystoresecret")) { logger.fine("Property:" + name + " Value:" + value); - } - else { + } else { logger.fine("Property:" + name); } } @@ -406,16 +376,14 @@ else if (ch == ':') value = ""; state = inName; - } - else if (ch == '{') { + } else if (ch == '{') { state = inEscapedValueStart; value = value.trim(); if (value.length() > 0) { - SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_errorConnectionString"), null, - true); + SQLServerException.makeFromDriverError(null, null, + SQLServerException.getErrString("R_errorConnectionString"), null, true); } - } - else { + } else { builder = new StringBuilder(); builder.append(value); builder.append(ch); @@ -442,8 +410,7 @@ else if (ch == '{') { // to eat the spaces until the ; potentially we could do without the state but // it would not be clean state = inEscapedValueEnd; - } - else { + } else { builder = new StringBuilder(); builder.append(value); builder.append(ch); @@ -456,10 +423,10 @@ else if (ch == '{') { if (ch == ';') // eat space chars till ; anything else is an error { state = inName; - } - else if (ch != ' ') { + } else if (ch != ' ') { // error if the chars are not space - SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_errorConnectionString"), null, true); + SQLServerException.makeFromDriverError(null, null, + SQLServerException.getErrString("R_errorConnectionString"), null, true); } break; } @@ -517,20 +484,22 @@ else if (ch != ' ') { case inName: { name = name.trim(); if (name.length() > 0) { - SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_errorConnectionString"), null, true); + SQLServerException.makeFromDriverError(null, null, + SQLServerException.getErrString("R_errorConnectionString"), null, true); } break; } default: - SQLServerException.makeFromDriverError(null, null, SQLServerException.getErrString("R_errorConnectionString"), null, true); + SQLServerException.makeFromDriverError(null, null, + SQLServerException.getErrString("R_errorConnectionString"), null, true); } return p; } /** - * Accepts a SQL identifier (such as a column name or table name) and escapes the identifier using SQL Server bracket escaping rules. Assumes that - * the incoming identifier is unescaped. + * Accepts a SQL identifier (such as a column name or table name) and escapes the identifier using SQL Server + * bracket escaping rules. Assumes that the incoming identifier is unescaped. * * @inID input identifier to escape. * @return the escaped value. @@ -559,18 +528,17 @@ static String escapeSQLId(String inID) { outID.append(']'); return outID.toString(); } - + /** * Checks if duplicate columns exists, in O(n) time. * * @param columnName - * the name of the column + * the name of the column * @throws SQLServerException - * when a duplicate column exists + * when a duplicate column exists */ - static void checkDuplicateColumnName(String columnName, - Set columnNames) throws SQLServerException { - //columnList.add will return false if the same column name already exists + static void checkDuplicateColumnName(String columnName, Set columnNames) throws SQLServerException { + // columnList.add will return false if the same column name already exists if (!columnNames.add(columnName)) { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_TVPDuplicateColumnName")); Object[] msgArgs = {columnName}; @@ -582,24 +550,22 @@ static void checkDuplicateColumnName(String columnName, * Reads a UNICODE string from byte buffer at offset (up to byteLength). * * @param b - * the buffer containing UNICODE bytes. + * the buffer containing UNICODE bytes. * @param offset - * - the offset into b where the UNICODE string starts. + * - the offset into b where the UNICODE string starts. * @param byteLength - * - the length in bytes of the UNICODE string. + * - the length in bytes of the UNICODE string. * @param conn - * - the SQLServerConnection object. + * - the SQLServerConnection object. * @return new String with UNICODE data inside. */ - static String readUnicodeString(byte[] b, - int offset, - int byteLength, + static String readUnicodeString(byte[] b, int offset, int byteLength, SQLServerConnection conn) throws SQLServerException { try { return new String(b, offset, byteLength, Encoding.UNICODE.charset()); - } - catch (IndexOutOfBoundsException ex) { - String txtMsg = SQLServerException.checkAndAppendClientConnId(SQLServerException.getErrString("R_stringReadError"), conn); + } catch (IndexOutOfBoundsException ex) { + String txtMsg = SQLServerException + .checkAndAppendClientConnId(SQLServerException.getErrString("R_stringReadError"), conn); MessageFormat form = new MessageFormat(txtMsg); Object[] msgArgs = {offset}; // Re-throw SQLServerException if conversion fails. @@ -613,7 +579,7 @@ static String readUnicodeString(byte[] b, * Converts byte array to a string representation of hex bytes for display purposes. * * @param b - * the source buffer. + * the source buffer. * @return "hexized" string representation of bytes. */ static String byteToHexDisplayString(byte[] b) { @@ -634,11 +600,10 @@ static String byteToHexDisplayString(byte[] b) { * Converts byte array to a string representation of hex bytes. * * @param b - * the source buffer. + * the source buffer. * @return "hexized" string representation of bytes. */ - static String bytesToHexString(byte[] b, - int length) { + static String bytesToHexString(byte[] b, int length) { StringBuilder sb = new StringBuilder(length * 2); for (int i = 0; i < length; i++) { int hexVal = b[i] & 0xFF; @@ -652,8 +617,9 @@ static String bytesToHexString(byte[] b, * Looks up local hostname of client machine. * * @exception UnknownHostException - * if local hostname is not found. - * @return hostname string or ip of host if hostname cannot be resolved. If neither hostname or ip found returns "" per spec. + * if local hostname is not found. + * @return hostname string or ip of host if hostname cannot be resolved. If neither hostname or ip found returns "" + * per spec. */ static String lookupHostName() { @@ -668,8 +634,7 @@ static String lookupHostName() { if (null != value && value.length() > 0) return value; } - } - catch (UnknownHostException e) { + } catch (UnknownHostException e) { return WSIDNotAvailable; } // If hostname not found, return standard "" string. @@ -741,11 +706,11 @@ static final UUID readGUIDtoUUID(byte[] inputGUID) throws SQLServerException { long msb = 0L; for (int i = 0; i < 8; i++) { - msb = msb << 8 | ((long) inputGUID[i] & 0xFFL); + msb = msb << 8 | ((long) inputGUID[i] & 0xFFL); } long lsb = 0L; for (int i = 8; i < 16; i++) { - lsb = lsb << 8 | ((long) inputGUID[i] & 0xFFL); + lsb = lsb << 8 | ((long) inputGUID[i] & 0xFFL); } return new UUID(msb, lsb); } @@ -790,7 +755,8 @@ static boolean IsActivityTraceOn() { } /** - * Determines if a column value should be transparently decrypted (based on SQLServerStatement and the connection string settings). + * Determines if a column value should be transparently decrypted (based on SQLServerStatement and the connection + * string settings). * * @return true if the value should be transparently decrypted, false otherwise. */ @@ -811,7 +777,8 @@ static boolean shouldHonorAEForRead(SQLServerStatementColumnEncryptionSetting st } /** - * Determines if parameters should be transparently encrypted (based on SQLServerStatement and the connection string settings). + * Determines if parameters should be transparently encrypted (based on SQLServerStatement and the connection string + * settings). * * @return true if the value should be transparently encrypted, false otherwise. */ @@ -831,8 +798,7 @@ static boolean shouldHonorAEForParameters(SQLServerStatementColumnEncryptionSett } } - static void validateMoneyRange(BigDecimal bd, - JDBCType jdbcType) throws SQLServerException { + static void validateMoneyRange(BigDecimal bd, JDBCType jdbcType) throws SQLServerException { if (null == bd) return; @@ -843,7 +809,8 @@ static void validateMoneyRange(BigDecimal bd, } break; case SMALLMONEY: - if ((1 != bd.compareTo(SSType.MAX_VALUE_SMALLMONEY)) && (-1 != bd.compareTo(SSType.MIN_VALUE_SMALLMONEY))) { + if ((1 != bd.compareTo(SSType.MAX_VALUE_SMALLMONEY)) + && (-1 != bd.compareTo(SSType.MIN_VALUE_SMALLMONEY))) { return; } break; @@ -853,10 +820,7 @@ static void validateMoneyRange(BigDecimal bd, throw new SQLServerException(form.format(msgArgs), null); } - static int getValueLengthBaseOnJavaType(Object value, - JavaType javaType, - Integer precision, - Integer scale, + static int getValueLengthBaseOnJavaType(Object value, JavaType javaType, Integer precision, Integer scale, JDBCType jdbcType) throws SQLServerException { switch (javaType) { // when the value of setObject() is null, the javaType stays @@ -887,14 +851,12 @@ static int getValueLengthBaseOnJavaType(Object value, if (JDBCType.GUID == jdbcType) { String guidTemplate = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"; return ((null == value) ? 0 : guidTemplate.length()); - } - else if (JDBCType.TIMESTAMP == jdbcType || JDBCType.TIME == jdbcType || JDBCType.DATETIMEOFFSET == jdbcType) { + } else if (JDBCType.TIMESTAMP == jdbcType || JDBCType.TIME == jdbcType + || JDBCType.DATETIMEOFFSET == jdbcType) { return ((null == scale) ? TDS.MAX_FRACTIONAL_SECONDS_SCALE : scale); - } - else if (JDBCType.BINARY == jdbcType || JDBCType.VARBINARY == jdbcType) { + } else if (JDBCType.BINARY == jdbcType || JDBCType.VARBINARY == jdbcType) { return ((null == value) ? 0 : (ParameterUtils.HexToBin((String) value).length)); - } - else { + } else { return ((null == value) ? 0 : ((String) value).length()); } @@ -907,16 +869,14 @@ else if (JDBCType.BINARY == jdbcType || JDBCType.VARBINARY == jdbcType) { if (null == precision) { if (null == value) { length = 0; - } - else { + } else { if (0 == ((BigDecimal) value).intValue()) { String s = "" + value; s = s.replaceAll("\\-", ""); if (s.startsWith("0.")) { // remove the leading zero, eg., for 0.32, the precision should be 2 and not 3 s = s.replaceAll("0\\.", ""); - } - else { + } else { s = s.replaceAll("\\.", ""); } length = s.length(); @@ -928,13 +888,11 @@ else if (("" + value).contains("E")) { s = s.replaceAll("\\.", ""); s = s.replaceAll("\\-", ""); length = s.length(); - } - else { + } else { length = ((BigDecimal) value).precision(); } } - } - else { + } else { length = precision; } @@ -956,7 +914,8 @@ else if (("" + value).contains("E")) { } // If the access token is expiring within next 10 minutes, lets just re-create a token for this connection attempt. - // If the token is expiring within the next 45 mins, try to fetch a new token if there is no thread already doing it. + // If the token is expiring within the next 45 mins, try to fetch a new token if there is no thread already doing + // it. // If a thread is already doing the refresh, just use the existing token and proceed. static synchronized boolean checkIfNeedNewAccessToken(SQLServerConnection connection) { Date accessTokenExpireDate = connection.getAuthenticationResult().getExpiresOnDate(); @@ -969,13 +928,11 @@ static synchronized boolean checkIfNeedNewAccessToken(SQLServerConnection connec // within the next 10 mins if ((accessTokenExpireDate.getTime() - now.getTime()) < (10 * 60 * 1000)) { return true; - } - else { + } else { // check if another thread is already updating the access token if (connection.attemptRefreshTokenLocked) { return false; - } - else { + } else { connection.attemptRefreshTokenLocked = true; return true; } @@ -984,15 +941,14 @@ static synchronized boolean checkIfNeedNewAccessToken(SQLServerConnection connec return false; } - + static final boolean use43Wrapper; static { boolean supportJDBC43 = true; try { DriverJDBCVersion.checkSupportsJDBC43(); - } - catch (UnsupportedOperationException e) { + } catch (UnsupportedOperationException e) { supportJDBC43 = false; } @@ -1000,7 +956,7 @@ static synchronized boolean checkIfNeedNewAccessToken(SQLServerConnection connec use43Wrapper = supportJDBC43 && (9 <= jvmVersion); } - + // if driver is for JDBC 43 and jvm version is 9 or higher, then always return as SQLServerConnection43, // otherwise return SQLServerConnection static boolean use43Wrapper() { @@ -1008,6 +964,7 @@ static boolean use43Wrapper() { } } + final class SQLIdentifier { // Component names default to empty string (rather than null) for consistency // with API behavior which returns empty string (rather than null) when the diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/XMLTDSHeader.java b/src/main/java/com/microsoft/sqlserver/jdbc/XMLTDSHeader.java index b3873f394..efcb52a48 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/XMLTDSHeader.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/XMLTDSHeader.java @@ -1,50 +1,43 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.jdbc; - -/** -* XMLTDSHeader is helper class used to read and write the XML TDS header from a TDS stream. -* -* Typical XML headers -> -* -* XML with schema. -* -* F1 -* 01 <- SCHEMA_PRESENT=1 -* 03|54 00 44 00 53 00 <- DBNAME (1 byte length in UNICODE chars) -* 03|64 00 62 00 6F 00 <- OWNING_SCHEMA (1 byte length in UNICODE chars) -* 09 00|53 00 68 00 69 00 70 00 4F 00 72 00 64 00 65 00 72 00 <- XML_SCHEMA_COLLECTION (2 byte length in UNICODE chars) -* -* XML without any schema (this is common as well). -* -* F1 -* 00 <- SCHEMA_PRESENT=0 -* -*/ - -final class XMLTDSHeader { - private final String databaseName; // Database name where XML schema resides. - private final String owningSchema; // Owner of XML schema (like dbo for example). - private final String xmlSchemaCollection; // Name of XML schema collection. - - XMLTDSHeader(TDSReader tdsReader) throws SQLServerException { - // Check schema present byte. - if (0 != tdsReader.readUnsignedByte()) { - // Ok, we have a schema present, process it. - databaseName = tdsReader.readUnicodeString(tdsReader.readUnsignedByte()); - owningSchema = tdsReader.readUnicodeString(tdsReader.readUnsignedByte()); - xmlSchemaCollection = tdsReader.readUnicodeString(tdsReader.readUnsignedShort()); - } - else { - xmlSchemaCollection = null; - owningSchema = null; - databaseName = null; - } - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.jdbc; + +/** + * XMLTDSHeader is helper class used to read and write the XML TDS header from a TDS stream. + * + * Typical XML headers -> + * + * XML with schema. + * + * F1 01 <- SCHEMA_PRESENT=1 03|54 00 44 00 53 00 <- DBNAME (1 byte length in UNICODE chars) 03|64 00 62 00 6F 00 <- + * OWNING_SCHEMA (1 byte length in UNICODE chars) 09 00|53 00 68 00 69 00 70 00 4F 00 72 00 64 00 65 00 72 00 <- + * XML_SCHEMA_COLLECTION (2 byte length in UNICODE chars) + * + * XML without any schema (this is common as well). + * + * F1 00 <- SCHEMA_PRESENT=0 + * + */ + +final class XMLTDSHeader { + private final String databaseName; // Database name where XML schema resides. + private final String owningSchema; // Owner of XML schema (like dbo for example). + private final String xmlSchemaCollection; // Name of XML schema collection. + + XMLTDSHeader(TDSReader tdsReader) throws SQLServerException { + // Check schema present byte. + if (0 != tdsReader.readUnsignedByte()) { + // Ok, we have a schema present, process it. + databaseName = tdsReader.readUnicodeString(tdsReader.readUnsignedByte()); + owningSchema = tdsReader.readUnicodeString(tdsReader.readUnsignedByte()); + xmlSchemaCollection = tdsReader.readUnicodeString(tdsReader.readUnsignedShort()); + } else { + xmlSchemaCollection = null; + owningSchema = null; + databaseName = null; + } + } +} diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/dataclassification/ColumnSensitivity.java b/src/main/java/com/microsoft/sqlserver/jdbc/dataclassification/ColumnSensitivity.java index 9d56c13c0..5bc4cab72 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/dataclassification/ColumnSensitivity.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/dataclassification/ColumnSensitivity.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.dataclassification; @@ -11,31 +8,30 @@ import java.util.ArrayList; import java.util.List; + /** - * This class is used to retrieve Sensitivity Information for columns as - * configured in Database. + * Represents the Data Classification Sensitivity Information for columns as configured in Database. */ public class ColumnSensitivity { - private List sensitivityProperties; + private List sensitivityProperties; - /** - * Constructor for ColumnSensitivity - * - * @param sensitivityProperties - * List of sensitivity properties as received from SQL Server - */ - public ColumnSensitivity(List sensitivityProperties) { - this.sensitivityProperties = new ArrayList( - sensitivityProperties); - } + /** + * Constructs a ColumnSensitivity + * + * @param sensitivityProperties + * List of sensitivity properties as received from SQL Server + */ + public ColumnSensitivity(List sensitivityProperties) { + this.sensitivityProperties = new ArrayList(sensitivityProperties); + } - /** - * Retrieves list of sensitivity properties as received from Server for this - * ColumnSensitivity information - * - * @return sensitivityProperties for this Class Object - */ - public List getSensitivityProperties() { - return sensitivityProperties; - } + /** + * Returns the list of sensitivity properties as received from Server for this ColumnSensitivity + * information + * + * @return sensitivityProperties for this Class Object + */ + public List getSensitivityProperties() { + return sensitivityProperties; + } } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/dataclassification/InformationType.java b/src/main/java/com/microsoft/sqlserver/jdbc/dataclassification/InformationType.java index 8e0b4ea03..c6c0fc103 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/dataclassification/InformationType.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/dataclassification/InformationType.java @@ -1,49 +1,45 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.dataclassification; /** - * This class retrieves Information Types as recieved from SQL Server for the - * active resultSet + * Represents the Data Classification Information Types as received from SQL Server for the active resultSet */ public class InformationType { - private String name; - private String id; + private String name; + private String id; - /** - * Constructor for Information Type - * - * @param name - * Name of Information Type - * @param id - * ID of Information Type - */ - public InformationType(String name, String id) { - this.name = name; - this.id = id; - } + /** + * Constructs a InformationType + * + * @param name + * Name of Information Type + * @param id + * ID of Information Type + */ + public InformationType(String name, String id) { + this.name = name; + this.id = id; + } - /** - * Retrieves Name of this InformationType Object - * - * @return Name of Information Type - */ - public String getName() { - return name; - } + /** + * Returns the name of this InformationType Object + * + * @return Name of Information Type + */ + public String getName() { + return name; + } - /** - * Retrieves ID for this InformationType object - * - * @return ID of Information Type - */ - public String getId() { - return id; - } + /** + * Returns the ID for this InformationType object + * + * @return ID of Information Type + */ + public String getId() { + return id; + } } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/dataclassification/Label.java b/src/main/java/com/microsoft/sqlserver/jdbc/dataclassification/Label.java index 7ccbeddec..0d481eddd 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/dataclassification/Label.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/dataclassification/Label.java @@ -1,49 +1,45 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.dataclassification; /** - * This class retrieves Labels as recieved from SQL Server for the active - * resultSet + * Represents the Data Classification Labels as received from SQL Server for the active resultSet */ public class Label { - private String name; - private String id; + private String name; + private String id; - /** - * Constructor for Label - * - * @param name - * Name of Label - * @param id - * ID of Label - */ - public Label(String name, String id) { - this.name = name; - this.id = id; - } + /** + * Constructs a Label + * + * @param name + * Name of Label + * @param id + * ID of Label + */ + public Label(String name, String id) { + this.name = name; + this.id = id; + } - /** - * Retrieves Name of this InformationType Object - * - * @return Name of Information Type - */ - public String getName() { - return name; - } + /** + * Returns the name of this InformationType Object + * + * @return Name of Information Type + */ + public String getName() { + return name; + } - /** - * Retrieves ID for this InformationType object - * - * @return ID of Information Type - */ - public String getId() { - return id; - } + /** + * Returns the ID for this InformationType object + * + * @return ID of Information Type + */ + public String getId() { + return id; + } } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/dataclassification/SensitivityClassification.java b/src/main/java/com/microsoft/sqlserver/jdbc/dataclassification/SensitivityClassification.java index 7c9b76e31..7acffa514 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/dataclassification/SensitivityClassification.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/dataclassification/SensitivityClassification.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.dataclassification; @@ -11,65 +8,61 @@ import java.util.ArrayList; import java.util.List; + /** - * This class retrieves Sensitivity Classification data as recieved from SQL - * Server for the active resultSet + * Provides the functionlity to retrieve Sensitivity Classification data as received from SQL Server for the active + * resultSet */ public class SensitivityClassification { - private List

- * The returned value represents an instant in time as the number of milliseconds since January 1, 1970, 00:00:00 GMT. - * - * @return this DateTimeOffset object's timestamp component - */ - public java.sql.Timestamp getTimestamp() { - java.sql.Timestamp timestamp = new java.sql.Timestamp(utcMillis); - timestamp.setNanos(nanos); - return timestamp; - } - - /** - * Gets this DateTimeOffset object's offset value. - * - * @return this DateTimeOffset object's minutes offset from GMT - */ - public int getMinutesOffset() { - return minutesOffset; - } - - /** - * Compares this DateTimeOffset object with another DateTimeOffset object to determine their relative order. - *

- * The ordering is based on the timestamp component only. The offset component is not compared. Two DateTimeOffset objects are considered - * equivalent with respect to ordering as long as they represent the same moment in time, regardless of the location of the event. This is how SQL - * Server orders DATETIMEOFFSET values. - * - * @return a negative integer, zero, or a positive integer as this DateTimeOffset is less than, equal to, or greater than the specified - * DateTimeOffset. - */ - public int compareTo(DateTimeOffset other) { - // Note that no explicit check for null==other is necessary. The contract for compareTo() - // says that a NullPointerException is to be thrown if null is passed as an argument. - - // The fact that nanos are non-negative guarantees the subtraction at the end - // cannot produce a signed value outside the range representable in an int. - assert nanos >= 0; - assert other.nanos >= 0; - - return (utcMillis > other.utcMillis) ? 1 : (utcMillis < other.utcMillis) ? -1 : nanos - other.nanos; - } - - private static class SerializationProxy implements java.io.Serializable { - private final long utcMillis; - private final int nanos; - private final int minutesOffset; - - SerializationProxy(DateTimeOffset dateTimeOffset) { - this.utcMillis = dateTimeOffset.utcMillis; - this.nanos = dateTimeOffset.nanos; - this.minutesOffset = dateTimeOffset.minutesOffset; - } - - private static final long serialVersionUID = 664661379547314226L; - - private Object readResolve() { - java.sql.Timestamp timestamp = new java.sql.Timestamp(utcMillis); - timestamp.setNanos(nanos); - return new DateTimeOffset(timestamp, minutesOffset); - } - } - - private Object writeReplace() { - return new SerializationProxy(this); - } - - private void readObject(java.io.ObjectInputStream stream) throws java.io.InvalidObjectException { - // For added security/robustness, the only way to rehydrate a serialized DateTimeOffset - // is to use a SerializationProxy. Direct use of readObject() is not supported. - throw new java.io.InvalidObjectException(""); - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package microsoft.sql; + +import java.util.Calendar; +import java.util.Locale; +import java.util.TimeZone; + + +/** + * Represents the SQL Server DATETIMEOFFSET data type. + * + * The DateTimeOffset class represents a java.sql.Timestamp, including fractional seconds, plus an integer representing + * the number of minutes offset from GMT. + */ +public final class DateTimeOffset implements java.io.Serializable, java.lang.Comparable { + private static final long serialVersionUID = 541973748553014280L; + + private final long utcMillis; + private final int nanos; + private final int minutesOffset; + + private static final int NANOS_MIN = 0; + private static final int NANOS_MAX = 999999999; + private static final int SS_NANOS_MAX = 9999999; + private static final int MINUTES_OFFSET_MIN = -14 * 60; + private static final int MINUTES_OFFSET_MAX = 14 * 60; + private static final int HUNDRED_NANOS_PER_SECOND = 10000000; + + /** + * Constructs a DateTimeOffset. + * + * This method does not check that its arguments represent a timestamp value that falls within the range of values + * acceptable to SQL Server for the DATETIMEOFFSET data type. That is, it is possible to create a DateTimeOffset + * instance representing a value outside the range from 1 January 1AD 00:00:00 UTC to 31 December 9999 00:00:00 UTC. + */ + private DateTimeOffset(java.sql.Timestamp timestamp, int minutesOffset) { + // Combined time zone and DST offset must be between -14:00 and 14:00 + if (minutesOffset < MINUTES_OFFSET_MIN || minutesOffset > MINUTES_OFFSET_MAX) + throw new IllegalArgumentException(); + this.minutesOffset = minutesOffset; + + // Nanos must be between 0 and 999999999 inclusive + int timestampNanos = timestamp.getNanos(); + if (timestampNanos < NANOS_MIN || timestampNanos > NANOS_MAX) + throw new IllegalArgumentException(); + + // This class represents values to 100ns precision. If the java.sql.Timestamp argument + // represents a value that is more precise, then nanos in excess of the 100ns precision + // allowed by this class are rounded to the nearest multiple of 100ns. + // + // Values within 50 nanoseconds of the next second are rounded up to the next second. + // Note: Values within 50 nanoseconds of the end of time wrap back to the beginning. + int hundredNanos = (timestampNanos + 50) / 100; + this.nanos = 100 * (hundredNanos % HUNDRED_NANOS_PER_SECOND); + this.utcMillis = timestamp.getTime() - timestamp.getNanos() / 1000000 + + 1000 * (hundredNanos / HUNDRED_NANOS_PER_SECOND); + + // Postconditions + assert this.minutesOffset >= MINUTES_OFFSET_MIN && this.minutesOffset <= MINUTES_OFFSET_MAX : "minutesOffset: " + + this.minutesOffset; + assert this.nanos >= NANOS_MIN && this.nanos <= NANOS_MAX : "nanos: " + this.nanos; + assert 0 == this.nanos % 100 : "nanos: " + this.nanos; + assert 0 == this.utcMillis % 1000L : "utcMillis: " + this.utcMillis; + } + + /** + * Converts a java.sql.Timestamp value with an integer offset to the equivalent DateTimeOffset value + * + * @param timestamp + * A java.sql.Timestamp value + * @param minutesOffset + * An integer offset in minutes + * @return The DateTimeOffset value of the input timestamp and minutesOffset + */ + public static DateTimeOffset valueOf(java.sql.Timestamp timestamp, int minutesOffset) { + return new DateTimeOffset(timestamp, minutesOffset); + } + + /** + * Converts a java.sql.Timestamp value with a Calendar value to the equivalent DateTimeOffset value + * + * @param timestamp + * A java.sql.Timestamp value + * @param calendar + * A java.util.Calendar value + * @return The DateTimeOffset value of the input timestamp and calendar + */ + public static DateTimeOffset valueOf(java.sql.Timestamp timestamp, Calendar calendar) { + // (Re)Set the calendar's time to the value in the timestamp so that get(ZONE_OFFSET) and get(DST_OFFSET) report + // the correct values for the time indicated, taking into account DST transition times and any historical + // changes + // to the DST transition schedule. + calendar.setTimeInMillis(timestamp.getTime()); + + return new DateTimeOffset(timestamp, + (calendar.get(Calendar.ZONE_OFFSET) + calendar.get(Calendar.DST_OFFSET)) / (60 * 1000)); + } + + private String formattedValue = null; + + /** + * Formats a datetimeoffset as yyyy-mm-dd hh:mm:ss[.fffffffff] [+|-]hh:mm, where yyyy-mm-dd hh:mm:ss[.fffffffff] + * indicates a timestamp that is offset from UTC by the number of minutes indicated by [+|-]hh:mm. + * + * @return a String object in yyyy-mm-dd hh:mm:ss[.fffffffff] [+|-]hh:mm format + */ + @Override + public String toString() { + // Because formatting the value as a string is computationally expensive (involving creation of a Calendar and + // a TimeZone, String formatters, etc.), cache the formatted value the first time it is needed. This can be done + // simply with the single-check idiom because the DateTimeOffset class is effectively immutable. + String result = formattedValue; + if (null == result) { + // Format the offset as +hh:mm or -hh:mm. Zero offset is formatted as +00:00. + String formattedOffset = (minutesOffset < 0) ? + + String.format(Locale.US, "-%1$02d:%2$02d", -minutesOffset / 60, + -minutesOffset % 60) + : + + String.format(Locale.US, "+%1$02d:%2$02d", minutesOffset / 60, + minutesOffset % 60); + + // Like java.sql.Date.toString() and java.sql.Timestamp.toString(), DateTimeOffset.toString() produces + // a value that is not locale-sensitive. The date part of the returned string is a Gregorian date, even + // if the VM default locale would otherwise indicate that a Buddhist calendar should be used. + Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("GMT" + formattedOffset), Locale.US); + + // Initialize the calendar with the UTC milliseconds value represented by this DateTimeOffset object + calendar.setTimeInMillis(utcMillis); + + // Assumption: nanos is in a valid range for printing as a 0-prefixed, 7-digit decimal number + // The DateTimeOffset constructor ensures that this is the case. + assert nanos >= NANOS_MIN && nanos <= NANOS_MAX; + + // Format the returned string value from the calendar's component fields and the UTC offset + formattedValue = result = (0 == nanos) ? + + String.format(Locale.US, "%1$tF %1$tT %2$s", calendar, + formattedOffset) + : + + String.format(Locale.US, "%1$tF %1$tT.%2$s %3$s", calendar, // Example + // (nanos + // = + // 123456000): + java.math.BigDecimal.valueOf(nanos, 9) // -> 0.123456000 + .stripTrailingZeros() // -> 0.123456 + .toPlainString() // -> "0.123456" + .substring(2), // -> "123456" + formattedOffset); + } + + return result; + } + + @Override + public boolean equals(Object o) { + // Fast check for reference equality + if (this == o) + return true; + + // Check other object's type (and implicitly test for null) + if (!(o instanceof DateTimeOffset)) + return false; + + DateTimeOffset other = (DateTimeOffset) o; + return utcMillis == other.utcMillis && nanos == other.nanos && minutesOffset == other.minutesOffset; + } + + @Override + public int hashCode() { + + // Start by approximately folding the date and time components together. + // Ignore any sub-second component of the utcMillis, which is always 0. + // Milliseconds are kept in the nanos field. + assert 0 == utcMillis % 1000L; + long seconds = utcMillis / 1000L; + + int result = 571; + result = 2011 * result + (int) seconds; + result = 3217 * result + (int) (seconds / 60 * 60 * 24 * 365); + + // Fold in nanoseconds/microseconds/milliseconds + result = 3919 * result + nanos / 100000; + result = 4463 * result + nanos / 1000; + result = 5227 * result + nanos; + + // Fold in the hour and minute portions of the time zone offset + // Typically the minutes are 0, so the hours have more impact on the hash + result = 6689 * result + minutesOffset; + result = 7577 * result + minutesOffset / 60; + + // The low order bits of the result should at this point be very + // sensitive to differences in any of the DateTimeOffset fields, + // even for small bucket sizes. + return result; + } + + /** + * Returns this DateTimeOffset object's timestamp value. + *

+ * The returned value represents an instant in time as the number of milliseconds since January 1, 1970, 00:00:00 + * GMT. + * + * @return this DateTimeOffset object's timestamp component + */ + public java.sql.Timestamp getTimestamp() { + java.sql.Timestamp timestamp = new java.sql.Timestamp(utcMillis); + timestamp.setNanos(nanos); + return timestamp; + } + + /** + * Returns this DateTimeOffset object's offset value. + * + * @return this DateTimeOffset object's minutes offset from GMT + */ + public int getMinutesOffset() { + return minutesOffset; + } + + /** + * Compares this DateTimeOffset object with another DateTimeOffset object to determine their relative order. + *

+ * The ordering is based on the timestamp component only. The offset component is not compared. Two DateTimeOffset + * objects are considered equivalent with respect to ordering as long as they represent the same moment in time, + * regardless of the location of the event. This is how SQL Server orders DATETIMEOFFSET values. + * + * @return a negative integer, zero, or a positive integer as this DateTimeOffset is less than, equal to, or greater + * than the specified DateTimeOffset. + */ + public int compareTo(DateTimeOffset other) { + // Note that no explicit check for null==other is necessary. The contract for compareTo() + // says that a NullPointerException is to be thrown if null is passed as an argument. + + // The fact that nanos are non-negative guarantees the subtraction at the end + // cannot produce a signed value outside the range representable in an int. + assert nanos >= 0; + assert other.nanos >= 0; + + return (utcMillis > other.utcMillis) ? 1 : (utcMillis < other.utcMillis) ? -1 : nanos - other.nanos; + } + + private static class SerializationProxy implements java.io.Serializable { + private final long utcMillis; + private final int nanos; + private final int minutesOffset; + + SerializationProxy(DateTimeOffset dateTimeOffset) { + this.utcMillis = dateTimeOffset.utcMillis; + this.nanos = dateTimeOffset.nanos; + this.minutesOffset = dateTimeOffset.minutesOffset; + } + + private static final long serialVersionUID = 664661379547314226L; + + private Object readResolve() { + java.sql.Timestamp timestamp = new java.sql.Timestamp(utcMillis); + timestamp.setNanos(nanos); + return new DateTimeOffset(timestamp, minutesOffset); + } + } + + private Object writeReplace() { + return new SerializationProxy(this); + } + + private void readObject(java.io.ObjectInputStream stream) throws java.io.InvalidObjectException { + // For added security/robustness, the only way to rehydrate a serialized DateTimeOffset + // is to use a SerializationProxy. Direct use of readObject() is not supported. + throw new java.io.InvalidObjectException(""); + } +} diff --git a/src/main/java/microsoft/sql/Types.java b/src/main/java/microsoft/sql/Types.java index b2e7cb5d0..ec326fe3c 100644 --- a/src/main/java/microsoft/sql/Types.java +++ b/src/main/java/microsoft/sql/Types.java @@ -1,15 +1,12 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package microsoft.sql; /** - * The class that defines the constants that are used to identify the SQL types that are specific to Microsoft SQL Server. + * Defines the constants that are used to identify the SQL types that are specific to Microsoft SQL Server. * * This class is never instantiated. */ @@ -19,52 +16,62 @@ private Types() { } /** - * The constant in the Java programming language, sometimes referred to as a type code, that identifies the Microsoft SQL type DATETIMEOFFSET. + * The constant in the Java programming language, sometimes referred to as a type code, that identifies the + * Microsoft SQL type DATETIMEOFFSET. */ public static final int DATETIMEOFFSET = -155; /** - * The constant in the Java programming language, sometimes referred to as a type code, that identifies the Microsoft SQL type STRUCTURED. + * The constant in the Java programming language, sometimes referred to as a type code, that identifies the + * Microsoft SQL type STRUCTURED. */ public static final int STRUCTURED = -153; /** - * The constant in the Java programming language, sometimes referred to as a type code, that identifies the Microsoft SQL type DATETIME. + * The constant in the Java programming language, sometimes referred to as a type code, that identifies the + * Microsoft SQL type DATETIME. */ public static final int DATETIME = -151; /** - * The constant in the Java programming language, sometimes referred to as a type code, that identifies the Microsoft SQL type SMALLDATETIME. + * The constant in the Java programming language, sometimes referred to as a type code, that identifies the + * Microsoft SQL type SMALLDATETIME. */ public static final int SMALLDATETIME = -150; /** - * The constant in the Java programming language, sometimes referred to as a type code, that identifies the Microsoft SQL type MONEY. + * The constant in the Java programming language, sometimes referred to as a type code, that identifies the + * Microsoft SQL type MONEY. */ public static final int MONEY = -148; /** - * The constant in the Java programming language, sometimes referred to as a type code, that identifies the Microsoft SQL type SMALLMONEY. + * The constant in the Java programming language, sometimes referred to as a type code, that identifies the + * Microsoft SQL type SMALLMONEY. */ public static final int SMALLMONEY = -146; /** - * The constant in the Java programming language, sometimes referred to as a type code, that identifies the Microsoft SQL type GUID. + * The constant in the Java programming language, sometimes referred to as a type code, that identifies the + * Microsoft SQL type GUID. */ public static final int GUID = -145; - + /** - * The constant in the Java programming language, sometimes referred to as a type code, that identifies the Microsoft SQL type SQL_VARIANT. + * The constant in the Java programming language, sometimes referred to as a type code, that identifies the + * Microsoft SQL type SQL_VARIANT. */ public static final int SQL_VARIANT = -156; - + /** - * The constant in the Java programming language, sometimes referred to as a type code, that identifies the Microsoft SQL type GEOMETRY. + * The constant in the Java programming language, sometimes referred to as a type code, that identifies the + * Microsoft SQL type GEOMETRY. */ public static final int GEOMETRY = -157; - + /** - * The constant in the Java programming language, sometimes referred to as a type code, that identifies the Microsoft SQL type GEOGRAPHY. + * The constant in the Java programming language, sometimes referred to as a type code, that identifies the + * Microsoft SQL type GEOGRAPHY. */ public static final int GEOGRAPHY = -158; } diff --git a/src/main/java/mssql/googlecode/cityhash/CityHash.java b/src/main/java/mssql/googlecode/cityhash/CityHash.java new file mode 100644 index 000000000..2585916e4 --- /dev/null +++ b/src/main/java/mssql/googlecode/cityhash/CityHash.java @@ -0,0 +1,358 @@ +package mssql.googlecode.cityhash; + +/** + * Copyright (C) 2012 tamtam180 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations + * under the License. + * + * @author tamtam180 - kirscheless at gmail.com + * @see http://google-opensource.blogspot.jp/2011/04/introducing-cityhash.html + * @see http://code.google.com/p/cityhash/ + */ +public final class CityHash { + + private static final long k0 = 0xc3a5c85c97cb3127L; + private static final long k1 = 0xb492b66fbe98f273L; + private static final long k2 = 0x9ae16a3b2f90404fL; + private static final long k3 = 0xc949d7c7509e6557L; + + private static long toLongLE(byte[] b, + int i) { + return (((long) b[i + 7] << 56) + ((long) (b[i + 6] & 255) << 48) + ((long) (b[i + 5] & 255) << 40) + ((long) (b[i + 4] & 255) << 32) + + ((long) (b[i + 3] & 255) << 24) + ((b[i + 2] & 255) << 16) + ((b[i + 1] & 255) << 8) + ((b[i + 0] & 255) << 0)); + } + + private static int toIntLE(byte[] b, + int i) { + return (((b[i + 3] & 255) << 24) + ((b[i + 2] & 255) << 16) + ((b[i + 1] & 255) << 8) + ((b[i + 0] & 255) << 0)); + } + + private static long fetch64(byte[] s, + int pos) { + return toLongLE(s, pos); + } + + private static int fetch32(byte[] s, + int pos) { + return toIntLE(s, pos); + } + + private static long rotate(long val, + int shift) { + return shift == 0 ? val : (val >>> shift) | (val << (64 - shift)); + } + + private static long rotateByAtLeast1(long val, + int shift) { + return (val >>> shift) | (val << (64 - shift)); + } + + private static long shiftMix(long val) { + return val ^ (val >>> 47); + } + + private static final long kMul = 0x9ddfea08eb382d69L; + + private static long hash128to64(long u, + long v) { + long a = (u ^ v) * kMul; + a ^= (a >>> 47); + long b = (v ^ a) * kMul; + b ^= (b >>> 47); + b *= kMul; + return b; + } + + private static long hashLen16(long u, + long v) { + return hash128to64(u, v); + } + + private static long hashLen0to16(byte[] s, + int pos, + int len) { + if (len > 8) { + long a = fetch64(s, pos + 0); + long b = fetch64(s, pos + len - 8); + return hashLen16(a, rotateByAtLeast1(b + len, len)) ^ b; + } + if (len >= 4) { + long a = 0xffffffffL & fetch32(s, pos + 0); + return hashLen16((a << 3) + len, 0xffffffffL & fetch32(s, pos + len - 4)); + } + if (len > 0) { + int a = s[pos + 0] & 0xFF; + int b = s[pos + (len >>> 1)] & 0xFF; + int c = s[pos + len - 1] & 0xFF; + int y = a + (b << 8); + int z = len + (c << 2); + return shiftMix(y * k2 ^ z * k3) * k2; + } + return k2; + } + + private static long hashLen17to32(byte[] s, + int pos, + int len) { + long a = fetch64(s, pos + 0) * k1; + long b = fetch64(s, pos + 8); + long c = fetch64(s, pos + len - 8) * k2; + long d = fetch64(s, pos + len - 16) * k0; + return hashLen16(rotate(a - b, 43) + rotate(c, 30) + d, a + rotate(b ^ k3, 20) - c + len); + } + + private static long[] weakHashLen32WithSeeds(long w, + long x, + long y, + long z, + long a, + long b) { + + a += w; + b = rotate(b + a + z, 21); + long c = a; + a += x; + a += y; + b += rotate(a, 44); + return new long[] {a + z, b + c}; + } + + private static long[] weakHashLen32WithSeeds(byte[] s, + int pos, + long a, + long b) { + return weakHashLen32WithSeeds(fetch64(s, pos + 0), fetch64(s, pos + 8), fetch64(s, pos + 16), fetch64(s, pos + 24), a, b); + } + + private static long hashLen33to64(byte[] s, + int pos, + int len) { + + long z = fetch64(s, pos + 24); + long a = fetch64(s, pos + 0) + (fetch64(s, pos + len - 16) + len) * k0; + long b = rotate(a + z, 52); + long c = rotate(a, 37); + + a += fetch64(s, pos + 8); + c += rotate(a, 7); + a += fetch64(s, pos + 16); + + long vf = a + z; + long vs = b + rotate(a, 31) + c; + + a = fetch64(s, pos + 16) + fetch64(s, pos + len - 32); + z = fetch64(s, pos + len - 8); + b = rotate(a + z, 52); + c = rotate(a, 37); + a += fetch64(s, pos + len - 24); + c += rotate(a, 7); + a += fetch64(s, pos + len - 16); + + long wf = a + z; + long ws = b + rotate(a, 31) + c; + long r = shiftMix((vf + ws) * k2 + (wf + vs) * k0); + + return shiftMix(r * k0 + vs) * k2; + + } + + static long cityHash64(byte[] s, + int pos, + int len) { + + if (len <= 32) { + if (len <= 16) { + return hashLen0to16(s, pos, len); + } + else { + return hashLen17to32(s, pos, len); + } + } + else if (len <= 64) { + return hashLen33to64(s, pos, len); + } + + long x = fetch64(s, pos + len - 40); + long y = fetch64(s, pos + len - 16) + fetch64(s, pos + len - 56); + long z = hashLen16(fetch64(s, pos + len - 48) + len, fetch64(s, pos + len - 24)); + + long[] v = weakHashLen32WithSeeds(s, pos + len - 64, len, z); + long[] w = weakHashLen32WithSeeds(s, pos + len - 32, y + k1, x); + x = x * k1 + fetch64(s, pos + 0); + + len = (len - 1) & (~63); + do { + x = rotate(x + y + v[0] + fetch64(s, pos + 8), 37) * k1; + y = rotate(y + v[1] + fetch64(s, pos + 48), 42) * k1; + x ^= w[1]; + y += v[0] + fetch64(s, pos + 40); + z = rotate(z + w[0], 33) * k1; + v = weakHashLen32WithSeeds(s, pos + 0, v[1] * k1, x + w[0]); + w = weakHashLen32WithSeeds(s, pos + 32, z + w[1], y + fetch64(s, pos + 16)); + { + long swap = z; + z = x; + x = swap; + } + pos += 64; + len -= 64; + } + while (len != 0); + + return hashLen16(hashLen16(v[0], w[0]) + shiftMix(y) * k1 + z, hashLen16(v[1], w[1]) + x); + + } + + static long cityHash64WithSeed(byte[] s, + int pos, + int len, + long seed) { + return cityHash64WithSeeds(s, pos, len, k2, seed); + } + + static long cityHash64WithSeeds(byte[] s, + int pos, + int len, + long seed0, + long seed1) { + return hashLen16(cityHash64(s, pos, len) - seed0, seed1); + } + + static long[] cityMurmur(byte[] s, + int pos, + int len, + long seed0, + long seed1) { + + long a = seed0; + long b = seed1; + long c = 0; + long d = 0; + + int l = len - 16; + if (l <= 0) { + a = shiftMix(a * k1) * k1; + c = b * k1 + hashLen0to16(s, pos, len); + d = shiftMix(a + (len >= 8 ? fetch64(s, pos + 0) : c)); + } + else { + + c = hashLen16(fetch64(s, pos + len - 8) + k1, a); + d = hashLen16(b + len, c + fetch64(s, pos + len - 16)); + a += d; + + do { + a ^= shiftMix(fetch64(s, pos + 0) * k1) * k1; + a *= k1; + b ^= a; + c ^= shiftMix(fetch64(s, pos + 8) * k1) * k1; + c *= k1; + d ^= c; + pos += 16; + l -= 16; + } + while (l > 0); + } + + a = hashLen16(a, c); + b = hashLen16(d, b); + + return new long[] {a ^ b, hashLen16(b, a)}; + + } + + static long[] cityHash128WithSeed(byte[] s, + int pos, + int len, + long seed0, + long seed1) { + + if (len < 128) { + return cityMurmur(s, pos, len, seed0, seed1); + } + + long[] v = new long[2], w = new long[2]; + long x = seed0; + long y = seed1; + long z = k1 * len; + + v[0] = rotate(y ^ k1, 49) * k1 + fetch64(s, pos); + v[1] = rotate(v[0], 42) * k1 + fetch64(s, pos + 8); + w[0] = rotate(y + z, 35) * k1 + x; + w[1] = rotate(x + fetch64(s, pos + 88), 53) * k1; + + do { + x = rotate(x + y + v[0] + fetch64(s, pos + 8), 37) * k1; + y = rotate(y + v[1] + fetch64(s, pos + 48), 42) * k1; + + x ^= w[1]; + y += v[0] + fetch64(s, pos + 40); + z = rotate(z + w[0], 33) * k1; + v = weakHashLen32WithSeeds(s, pos + 0, v[1] * k1, x + w[0]); + w = weakHashLen32WithSeeds(s, pos + 32, z + w[1], y + fetch64(s, pos + 16)); + { + long swap = z; + z = x; + x = swap; + } + pos += 64; + x = rotate(x + y + v[0] + fetch64(s, pos + 8), 37) * k1; + y = rotate(y + v[1] + fetch64(s, pos + 48), 42) * k1; + x ^= w[1]; + y += v[0] + fetch64(s, pos + 40); + z = rotate(z + w[0], 33) * k1; + v = weakHashLen32WithSeeds(s, pos, v[1] * k1, x + w[0]); + w = weakHashLen32WithSeeds(s, pos + 32, z + w[1], y + fetch64(s, pos + 16)); + { + long swap = z; + z = x; + x = swap; + } + pos += 64; + len -= 128; + } + while (len >= 128); + + x += rotate(v[0] + z, 49) * k0; + z += rotate(w[0], 37) * k0; + + for (int tail_done = 0; tail_done < len;) { + tail_done += 32; + y = rotate(x + y, 42) * k0 + v[1]; + w[0] += fetch64(s, pos + len - tail_done + 16); + x = x * k0 + w[0]; + z += w[1] + fetch64(s, pos + len - tail_done); + w[1] += v[0]; + v = weakHashLen32WithSeeds(s, pos + len - tail_done, v[0] + z, v[1]); + } + + x = hashLen16(x, v[0]); + y = hashLen16(y + z, w[0]); + + return new long[] {hashLen16(x + v[1], w[1]) + y, hashLen16(x + w[1], y + v[1])}; + + } + + public static long[] cityHash128(byte[] s, + int pos, + int len) { + + if (len >= 16) { + return cityHash128WithSeed(s, pos + 16, len - 16, fetch64(s, pos + 0) ^ k3, fetch64(s, pos + 8)); + } + else if (len >= 8) { + return cityHash128WithSeed(new byte[0], 0, 0, fetch64(s, pos + 0) ^ (len * k0), fetch64(s, pos + len - 8) ^ k1); + } + else { + return cityHash128WithSeed(s, pos, len, k0, k1); + } + } +} diff --git a/src/main/java/mssql/googlecode/cityhash/LICENSE b/src/main/java/mssql/googlecode/cityhash/LICENSE new file mode 100644 index 000000000..261eeb9e9 --- /dev/null +++ b/src/main/java/mssql/googlecode/cityhash/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/src/main/java/mssql/googlecode/cityhash/NOTICE b/src/main/java/mssql/googlecode/cityhash/NOTICE new file mode 100644 index 000000000..b8c79f768 --- /dev/null +++ b/src/main/java/mssql/googlecode/cityhash/NOTICE @@ -0,0 +1,5 @@ +CityHash +Copyright 2012, tamtam180 + +More information: http://google-opensource.blogspot.jp/2011/04/introducing-cityhash.html +By Geoff Pike and Jyrki Alakuijala, Software Engineering Team, Google diff --git a/src/main/java/mssql/googlecode/cityhash/package-info.java b/src/main/java/mssql/googlecode/cityhash/package-info.java new file mode 100644 index 000000000..5a4d5748e --- /dev/null +++ b/src/main/java/mssql/googlecode/cityhash/package-info.java @@ -0,0 +1,18 @@ +/** + * Copyright (C) 2012 tamtam180 + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a + * copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations + * under the License. + * + * @author tamtam180 - kirscheless at gmail.com + * @see http://google-opensource.blogspot.jp/2011/04/introducing-cityhash.html + * @see http://code.google.com/p/cityhash/ + */ +package mssql.googlecode.cityhash; diff --git a/src/samples/README.md b/src/samples/README.md index 2ea757d28..444d5086a 100644 --- a/src/samples/README.md +++ b/src/samples/README.md @@ -1,59 +1,62 @@ -## Overview -The Microsoft JDBC Driver for SQL Server sample applications demonstrate various features of the JDBC driver. Additionally, they demonstrate good programming practices that you can follow when using the JDBC driver with SQL Server or Azure SQL Database. - -All the sample applications are contained in *.java code files that can be compiled and run on your local computer. These code samples are based on the ones found in [MSDN](https://msdn.microsoft.com/en-us/library/aa342346(v=sql.110).aspx), where you can find additional content with more detailed descriptions. - -The following samples are available: - -1. adaptive - * **executeStoredProcedure** - how to retrieve a large OUT parameter from a stored procedure and use adaptive buffering mode. - * **readLargeData** - how to read large data and use adaptive buffering mode. It also demonstrates how to retrieve a large single-column value from by using the getCharacterStream method. - * **updateLargeData** - how to update large data and set the adaptive buffering mode explicitly for updatable result sets. - -2. alwaysencrypted - * **AlwaysEncrypted** - how to create Column Master Key and Column Encryption Key for use with the Java Key Store for Always Encrypted feature. - -3. azureactivedirectoryauthentication - * **AzureActiveDirectoryAuthentication** - how to connect to Azure SQL Databases using identities in Azure Active Directory. - -4. connections - * **connectDS** - how to connect using a data source object and retrieve data using a stored procedure. - * **connectURL** - how to connect using a connection URL and retrieve data using an SQL statement. - -5. datatypes - * **basicDT** - how to retrieve and update basic SQL Server data type values. - * **sqlxmlExample** - how to store and retrieve XML data as well as how to parse XML data with the SQLXML Java data type. - -6. resultsets - * **cacheRS** - how to retrieve a large set of data and control the amount of data that is fetched and cached on the client - * **retrieveRS** - how to use a result set to retrieve a basic set of data. - * **updateRS** - how to use an updatable result set to insert, update, and delete a row of data. - -7. sparse - * **SparseColumns** - how to detect column sets. It also shows a technique for parsing a column set's XML output, to get data from the sparse columns. - -8. constrained - * **ConstrainedSample** - how to connect with Kerberos constrained delegation using an impersonated credential. - - -## Running Samples - -###Prerequisites -* Java 8 -* [Maven](http://maven.apache.org/download.cgi) -* An instance of SQL Server or SQL Azure Database that you can connect to. - -###Using Maven - -To run a sample, you need to provide Maven with the appropriate profile ID so that it knows which sample to run. To find them, open the associated POM file and look for the <id> elements within the <profile> section. For example, in \src\samples\adaptive\pom.xml, you will find: executeStoredProcedure, readLargeData and updateLargeData. - -To run a specific sample, go to the directory that contains the sample's POM file and run the following commands: - -* `mvn install -PprofileID` to compile the sample -* `mvn exec:java -PprofileID` to run the sample under the current directory. - -For example, if you wish to compile and run the executeStoredProcedure sample you can run: - -* `mvn install -PexecuteStoredProcedure` -* `mvn exec:java -PexecuteStoredProcedure` - + +# Running Sample Applications + +The Microsoft JDBC Driver for SQL Server sample applications demonstrate various features of the JDBC driver. Additionally, they demonstrate good programming practices that you can follow when using the JDBC driver with SQL Server or Azure SQL Database. + +All the sample applications are contained in *.java code files that can be compiled and run on your local computer. These code samples are based on the ones found in [Microsoft Docs](https://docs.microsoft.com/en-us/sql/connect/jdbc/sample-jdbc-driver-applications), where you can find additional content with more detailed descriptions. + +The following samples are available: + +1. adaptive + * **ExecuteStoredProcedures** - Demonstrates how to retrieve a large OUT parameter from a stored procedure and use adaptive buffering mode. + * **ReadLargeData** - Demonstrates how to read large data and use adaptive buffering mode. It also demonstrates how to retrieve a large single-column value from by using the getCharacterStream method. + * **UpdateLargeData** - Demonstrates how to update large data and set the adaptive buffering mode explicitly for updatable result sets. + +2. alwaysencrypted + * **AlwaysEncrypted** - Demonstrates how to create Column Master Key and Column Encryption Key for use with the Java Key Store for Always Encrypted feature. + +3. azureactivedirectoryauthentication + * **AzureActiveDirectoryAuthentication** - Demonstrates how to connect to Azure SQL Databases using identities in Azure Active Directory. + +4. connections + * **ConnectDS** - Demonstrates how to connect using a data source object and retrieve data using a stored procedure. + * **ConnectURL** - Demonstrates how to connect using a connection URL and retrieve data using an SQL statement. + +5. datatypes + * **BasicDataTypes** - Demonstrates how to retrieve and update basic SQL Server data type values. + * **SqlXmlDataType** - Demonstrates how to store and retrieve XML data as well as how to parse XML data with the SQLXML Java data type. + * **SpatialDatatypes** - Demonstrates how to store and retreive Spatial Data as well how to parse data using `Geometry` and `Geography` Java types defined by Microsoft JDBC Driver. + +6. resultsets + * **CacheRS** - Demonstrates how to retrieve a large set of data and control the amount of data that is fetched and cached on the client + * **RetrieveRS** - Demonstrates how to use a result set to retrieve a basic set of data. + * **UpdateRS** - Demonstrates how to use an updatable result set to insert, update, and delete a row of data. + +7. sparse + * **SparseColumns** - Demonstrates how to detect column sets. It also shows a technique for parsing a column set's XML output, to get data from the sparse columns. + +8. constrained + * **ConstrainedDelegation** - Demonstrates how to connect with Kerberos constrained delegation using an impersonated credential. + +## Running Samples + +### Pre-Requisites + +* Java 10 +* [Maven](http://maven.apache.org/download.cgi) +* An instance of SQL Server or SQL Azure Database that you can connect to. + +### Using Maven + +To run a sample, you need to provide Maven with the appropriate profile ID so that it knows which sample to run. To find them, open the associated POM file and look for the `` elements within the `` section. For example, in `\src\samples\adaptive\pom.xml`, you will find: _ExecuteStoredProcedures_, _ReadLargeData_ and _UpdateLargeData_. + +To run a specific sample, go to the directory that contains the sample's POM file and run the following commands: + +* `mvn install -PprofileID` to compile the sample +* `mvn exec:java -PprofileID` to run the sample under the current directory. + +For example, if you wish to compile and run the _ExecuteStoredProcedures_ sample you can run: + +* `mvn install -PExecuteStoredProcedures` +* `mvn exec:java -PExecuteStoredProcedures` + diff --git a/src/samples/adaptive/pom.xml b/src/samples/adaptive/pom.xml index fbece6732..dc9450b10 100644 --- a/src/samples/adaptive/pom.xml +++ b/src/samples/adaptive/pom.xml @@ -1,95 +1,83 @@ - 4.0.0 - com.microsoft.sqlserver.jdbc adaptive 0.0.1 - jar - ${project.artifactId} https://github.com/Microsoft/mssql-jdbc/tree/master/src/samples - UTF-8 - com.microsoft.sqlserver mssql-jdbc - 6.4.0.jre9 + 7.0.0.jre10 - - executeStoredProcedure + ExecuteStoredProcedures - executeStoredProcedure - + ExecuteStoredProcedures org.codehaus.mojo exec-maven-plugin 1.2.1 - adaptive.src.main.java.executeStoredProcedure + adaptive.src.main.java.ExecuteStoredProcedures - - readLargeData + ReadLargeData - readLargeData - + ReadLargeData org.codehaus.mojo exec-maven-plugin 1.2.1 - adaptive.src.main.java.readLargeData + adaptive.src.main.java.ReadLargeData - - updateLargeData + UpdateLargeData - updateLargeData - + UpdateLargeData org.codehaus.mojo exec-maven-plugin 1.2.1 - adaptive.src.main.java.updateLargeData + adaptive.src.main.java.UpdateLargeData - org.apache.maven.plugins maven-compiler-plugin - 9 - 9 + 10 + 10 - org.apache.maven.plugins maven-resources-plugin @@ -97,5 +85,4 @@ - diff --git a/src/samples/adaptive/src/main/java/ExecuteStoredProcedures.java b/src/samples/adaptive/src/main/java/ExecuteStoredProcedures.java new file mode 100644 index 000000000..f868dca42 --- /dev/null +++ b/src/samples/adaptive/src/main/java/ExecuteStoredProcedures.java @@ -0,0 +1,151 @@ +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package adaptive.src.main.java; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.Reader; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Statement; + +import com.microsoft.sqlserver.jdbc.SQLServerCallableStatement; +import com.microsoft.sqlserver.jdbc.SQLServerDataSource; + +/** + * Sample application to demonstrate how to retrieve a large OUT parameter from + * a stored procedure and how to get the adaptive buffering mode. + */ +public class ExecuteStoredProcedures { + + public static void main(String[] args) { + + String serverName = null; + String portNumber = null; + String databaseName = null; + String username = null; + String password = null; + + try (InputStreamReader in = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(in)) { + + System.out.print("Enter server name: "); + serverName = br.readLine(); + System.out.print("Enter port number: "); + portNumber = br.readLine(); + System.out.print("Enter database name: "); + databaseName = br.readLine(); + System.out.print("Enter username: "); + username = br.readLine(); + System.out.print("Enter password: "); + password = br.readLine(); + + // Establish the connection. + SQLServerDataSource ds = new SQLServerDataSource(); + ds.setServerName(serverName); + ds.setPortNumber(Integer.parseInt(portNumber)); + ds.setDatabaseName(databaseName); + ds.setUser(username); + ds.setPassword(password); + + try (Connection con = ds.getConnection(); Statement stmt = con.createStatement()) { + + createTable(stmt); + createStoredProcedure(stmt); + + // Create test data as an example. + StringBuffer buffer = new StringBuffer(4000); + for (int i = 0; i < 4000; i++) + buffer.append((char) ('A')); + + try (PreparedStatement pstmt = con.prepareStatement( + "UPDATE Document_JDBC_Sample " + "SET DocumentSummary = ? WHERE (DocumentID = 1)")) { + + pstmt.setString(1, buffer.toString()); + pstmt.executeUpdate(); + } + + // Query test data by using a stored procedure. + try (SQLServerCallableStatement cstmt = (SQLServerCallableStatement) con + .prepareCall("{call GetLargeDataValue(?, ?, ?, ?)}")) { + + cstmt.setInt(1, 1); + cstmt.registerOutParameter(2, java.sql.Types.INTEGER); + cstmt.registerOutParameter(3, java.sql.Types.CHAR); + cstmt.registerOutParameter(4, java.sql.Types.LONGVARCHAR); + + // Display the response buffering mode. + System.out.println("Response buffering mode is: " + cstmt.getResponseBuffering()); + + cstmt.execute(); + System.out.println("DocumentID: " + cstmt.getInt(2)); + System.out.println("Document_Title: " + cstmt.getString(3)); + + try (Reader reader = cstmt.getCharacterStream(4)) { + + // If your application needs to re-read any portion of the value, + // it must call the mark method on the InputStream or Reader to + // start buffering data that is to be re-read after a subsequent + // call to the reset method. + reader.mark(4000); + + // Read the first half of data. + char output1[] = new char[2000]; + reader.read(output1); + String stringOutput1 = new String(output1); + + // Reset the stream. + reader.reset(); + + // Read all the data. + char output2[] = new char[4000]; + reader.read(output2); + String stringOutput2 = new String(output2); + + System.out.println("Document_Summary in half: " + stringOutput1); + System.out.println("Document_Summary: " + stringOutput2); + } + } + } + } + // Handle any errors that may have occurred. + catch (Exception e) { + e.printStackTrace(); + } + } + + private static void createStoredProcedure(Statement stmt) throws SQLException { + String outputProcedure = "GetLargeDataValue"; + + String sql = " IF EXISTS (select * from sysobjects where id = object_id(N'" + outputProcedure + + "') and OBJECTPROPERTY(id, N'IsProcedure') = 1)" + " DROP PROCEDURE " + outputProcedure; + stmt.execute(sql); + + sql = "CREATE PROCEDURE " + outputProcedure + " @p0 int, @p1 int OUTPUT, @p2 char(50) OUTPUT, " + + "@p3 varchar(max) OUTPUT " + " AS" + " SELECT top 1 @p1=DocumentID, @p2=Title," + + " @p3=DocumentSummary FROM Document_JDBC_Sample where DocumentID = @p0"; + + stmt.execute(sql); + } + + private static void createTable(Statement stmt) throws SQLException { + stmt.execute("if exists (select * from sys.objects where name = 'Document_JDBC_Sample')" + + "drop table Document_JDBC_Sample"); + + String sql = "CREATE TABLE Document_JDBC_Sample(" + "[DocumentID] [int] NOT NULL identity," + + "[Title] [char](50) NOT NULL," + "[DocumentSummary] [varchar](max) NULL)"; + + stmt.execute(sql); + + sql = "INSERT Document_JDBC_Sample VALUES ('title1','summary1') "; + stmt.execute(sql); + + sql = "INSERT Document_JDBC_Sample VALUES ('title2','summary2') "; + stmt.execute(sql); + + sql = "INSERT Document_JDBC_Sample VALUES ('title3','summary3') "; + stmt.execute(sql); + } +} diff --git a/src/samples/adaptive/src/main/java/ReadLargeData.java b/src/samples/adaptive/src/main/java/ReadLargeData.java new file mode 100644 index 000000000..92778da92 --- /dev/null +++ b/src/samples/adaptive/src/main/java/ReadLargeData.java @@ -0,0 +1,122 @@ +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package adaptive.src.main.java; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.Reader; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import com.microsoft.sqlserver.jdbc.SQLServerStatement; + +/** + * Sample application to demonstrate how to read the large data from a database and + * how to get the adaptive buffering mode. + * + * It also demonstrates how to retrieve a large single-column value from a SQL Server + * database by using the getCharacterStream method. + */ +public class ReadLargeData { + + public static void main(String[] args) { + + String serverName = null; + String portNumber = null; + String databaseName = null; + String username = null; + String password = null; + + try (InputStreamReader in = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(in)) { + + System.out.print("Enter server name: "); + serverName = br.readLine(); + System.out.print("Enter port number: "); + portNumber = br.readLine(); + System.out.print("Enter database name: "); + databaseName = br.readLine(); + System.out.print("Enter username: "); + username = br.readLine(); + System.out.print("Enter password: "); + password = br.readLine(); + + // Create a variable for the connection string. + String connectionUrl = "jdbc:sqlserver://" + serverName + ":" + portNumber + ";" + "databaseName=" + + databaseName + ";username=" + username + ";password=" + password + ";"; + + // Establish the connection. + try (Connection con = DriverManager.getConnection(connectionUrl); + SQLServerStatement stmt = (SQLServerStatement) con.createStatement()) { + + createTable(stmt); + // Create test data as an example. + StringBuffer buffer = new StringBuffer(4000); + for (int i = 0; i < 4000; i++) + buffer.append((char) ('A')); + + try (PreparedStatement pstmt = con.prepareStatement( + "UPDATE Document_JDBC_Sample " + "SET DocumentSummary = ? WHERE (DocumentID = 1)")) { + + pstmt.setString(1, buffer.toString()); + pstmt.executeUpdate(); + } + + // In adaptive mode, the application does not have to use a server cursor + // to avoid OutOfMemoryError when the SELECT statement produces very large + // results. + + // Create and execute an SQL statement that returns some data. + String SQL = "SELECT Title, DocumentSummary " + "FROM Document_JDBC_Sample"; + + // Display the response buffering mode. + System.out.println("Response buffering mode is: " + stmt.getResponseBuffering()); + + // Get the updated data from the database and display it. + try (ResultSet rs = stmt.executeQuery(SQL)) { + + while (rs.next()) { + try (Reader reader = rs.getCharacterStream(2)) { + if (reader != null) { + char output[] = new char[40]; + while (reader.read(output) != -1) { + // Print the chunk of the data that was read. + String stringOutput = new String(output); + System.out.println("Document_Summary Data Chunk: " + stringOutput); + } + + System.out.println(rs.getString(1) + " has been accessed for the summary column."); + } + } + } + } + } + } + // Handle any errors that may have occurred. + catch (Exception e) { + e.printStackTrace(); + } + } + + private static void createTable(SQLServerStatement stmt) throws SQLException { + stmt.execute("if exists (select * from sys.objects where name = 'Document_JDBC_Sample')" + + "drop table Document_JDBC_Sample"); + + String sql = "CREATE TABLE Document_JDBC_Sample (" + "[DocumentID] [int] NOT NULL identity," + + "[Title] [char](50) NOT NULL," + "[DocumentSummary] [varchar](max) NULL)"; + + stmt.execute(sql); + + sql = "INSERT Document_JDBC_Sample VALUES ('title1','summary1') "; + stmt.execute(sql); + + sql = "INSERT Document_JDBC_Sample VALUES ('title2','summary2') "; + stmt.execute(sql); + + sql = "INSERT Document_JDBC_Sample VALUES ('title3','summary3') "; + stmt.execute(sql); + } +} diff --git a/src/samples/adaptive/src/main/java/UpdateLargeData.java b/src/samples/adaptive/src/main/java/UpdateLargeData.java new file mode 100644 index 000000000..424635111 --- /dev/null +++ b/src/samples/adaptive/src/main/java/UpdateLargeData.java @@ -0,0 +1,120 @@ +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package adaptive.src.main.java; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.Reader; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import com.microsoft.sqlserver.jdbc.SQLServerStatement; + + +/** + * Sample application to demonstrate how to update the large data in a database. + * It also demonstrates how to set the adaptive buffering mode explicitly for updatable result sets. + */ +public class UpdateLargeData { + + public static void main(String[] args) { + + String serverName = null; + String portNumber = null; + String databaseName = null; + String username = null; + String password = null; + + try (InputStreamReader in = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(in)) { + + System.out.print("Enter server name: "); + serverName = br.readLine(); + System.out.print("Enter port number: "); + portNumber = br.readLine(); + System.out.print("Enter database name: "); + databaseName = br.readLine(); + System.out.print("Enter username: "); + username = br.readLine(); + System.out.print("Enter password: "); + password = br.readLine(); + + // Create a variable for the connection string. + String connectionUrl = "jdbc:sqlserver://" + serverName + ":" + portNumber + ";" + "databaseName=" + + databaseName + ";username=" + username + ";password=" + password + ";"; + + // Establish the connection. + try (Connection con = DriverManager.getConnection(connectionUrl); Statement stmt = con.createStatement(); + Statement stmt1 = con.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE);) { + + createTable(stmt); + + /* Since the summaries could be large, we should make sure that + * the driver reads them incrementally from a database, + * even though a server cursor is used for the updatable result sets. + * + * The recommended way to access the Microsoft JDBC Driver for SQL Server + * specific methods is to use the JDBC 4.0 Wrapper functionality. + * The following code statement demonstrates how to use the + * Statement.isWrapperFor and Statement.unwrap methods + * to access the driver specific response buffering methods. + */ + if (stmt.isWrapperFor(com.microsoft.sqlserver.jdbc.SQLServerStatement.class)) { + SQLServerStatement SQLstmt = stmt.unwrap(com.microsoft.sqlserver.jdbc.SQLServerStatement.class); + + SQLstmt.setResponseBuffering("adaptive"); + System.out.println("Response buffering mode has been set to " + SQLstmt.getResponseBuffering()); + } + + // Select all of the document summaries. + try (ResultSet rs = stmt1.executeQuery("SELECT Title, DocumentSummary FROM Document_JDBC_Sample")) { + + // Update each document summary. + while (rs.next()) { + + // Retrieve the original document summary. + try (Reader reader = rs.getCharacterStream("DocumentSummary")) { + + if (reader == null) { + // Update the document summary. + System.out.println("Updating " + rs.getString("Title")); + rs.updateString("DocumentSummary", "Work in progress"); + rs.updateRow(); + } + } + } + } + } + } + // Handle any errors that may have occurred. + catch (Exception e) { + e.printStackTrace(); + } + } + + private static void createTable(Statement stmt) throws SQLException { + stmt.execute("if exists (select * from sys.objects where name = 'Document_JDBC_Sample')" + + "drop table Document_JDBC_Sample"); + + String sql = "CREATE TABLE Document_JDBC_Sample (" + "[DocumentID] [int] NOT NULL identity," + + "[Title] [char](50) NOT NULL," + "[DocumentSummary] [varchar](max) NULL)"; + + stmt.execute(sql); + + sql = "INSERT Document_JDBC_Sample VALUES ('title1','summary1') "; + stmt.execute(sql); + + sql = "INSERT Document_JDBC_Sample (title) VALUES ('title2') "; + stmt.execute(sql); + + sql = "INSERT Document_JDBC_Sample (title) VALUES ('title3') "; + stmt.execute(sql); + + sql = "INSERT Document_JDBC_Sample VALUES ('title4','summary3') "; + stmt.execute(sql); + } +} diff --git a/src/samples/adaptive/src/main/java/executeStoredProcedure.java b/src/samples/adaptive/src/main/java/executeStoredProcedure.java deleted file mode 100644 index 6fbd21803..000000000 --- a/src/samples/adaptive/src/main/java/executeStoredProcedure.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ -package adaptive.src.main.java; - -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.io.Reader; -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 com.microsoft.sqlserver.jdbc.SQLServerCallableStatement; -import com.microsoft.sqlserver.jdbc.SQLServerDataSource; - -public class executeStoredProcedure { - - public static void main(String[] args) { - - // Declare the JDBC objects. - Connection con = null; - Statement stmt = null; - ResultSet rs = null; - - String serverName = null; - String portNumber = null; - String databaseName = null; - String username = null; - String password = null; - - try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) { - - System.out.print("Enter server name: "); - serverName = br.readLine(); - System.out.print("Enter port number: "); - portNumber = br.readLine(); - System.out.print("Enter database name: "); - databaseName = br.readLine(); - System.out.print("Enter username: "); - username = br.readLine(); - System.out.print("Enter password: "); - password = br.readLine(); - - // Establish the connection. - SQLServerDataSource ds = new SQLServerDataSource(); - ds.setServerName(serverName); - ds.setPortNumber(Integer.parseInt(portNumber)); - ds.setDatabaseName(databaseName); - ds.setUser(username); - ds.setPassword(password); - - con = ds.getConnection(); - - createTable(con); - createStoredProcedure(con); - - // Create test data as an example. - StringBuffer buffer = new StringBuffer(4000); - for (int i = 0; i < 4000; i++) - buffer.append((char) ('A')); - - PreparedStatement pstmt = con.prepareStatement("UPDATE Document_JDBC_Sample " + "SET DocumentSummary = ? WHERE (DocumentID = 1)"); - - pstmt.setString(1, buffer.toString()); - pstmt.executeUpdate(); - pstmt.close(); - - // Query test data by using a stored procedure. - CallableStatement cstmt = con.prepareCall("{call GetLargeDataValue(?, ?, ?, ?)}"); - - cstmt.setInt(1, 1); - cstmt.registerOutParameter(2, java.sql.Types.INTEGER); - cstmt.registerOutParameter(3, java.sql.Types.CHAR); - cstmt.registerOutParameter(4, java.sql.Types.LONGVARCHAR); - - // Display the response buffering mode. - SQLServerCallableStatement SQLcstmt = (SQLServerCallableStatement) cstmt; - System.out.println("Response buffering mode is: " + SQLcstmt.getResponseBuffering()); - - SQLcstmt.execute(); - System.out.println("DocumentID: " + cstmt.getInt(2)); - System.out.println("Document_Title: " + cstmt.getString(3)); - - Reader reader = SQLcstmt.getCharacterStream(4); - - // If your application needs to re-read any portion of the value, - // it must call the mark method on the InputStream or Reader to - // start buffering data that is to be re-read after a subsequent - // call to the reset method. - reader.mark(4000); - - // Read the first half of data. - char output1[] = new char[2000]; - reader.read(output1); - String stringOutput1 = new String(output1); - - // Reset the stream. - reader.reset(); - - // Read all the data. - char output2[] = new char[4000]; - reader.read(output2); - String stringOutput2 = new String(output2); - - System.out.println("Document_Summary in half: " + stringOutput1); - System.out.println("Document_Summary: " + stringOutput2); - - // Close the stream. - reader.close(); - } - // Handle any errors that may have occurred. - catch (Exception e) { - e.printStackTrace(); - } - finally { - if (rs != null) - try { - rs.close(); - } - catch (Exception e) { - } - if (stmt != null) - try { - stmt.close(); - } - catch (Exception e) { - } - if (con != null) - try { - con.close(); - } - catch (Exception e) { - } - } - } - - private static void createStoredProcedure(Connection con) throws SQLException { - Statement stmt = con.createStatement(); - - String outputProcedure = "GetLargeDataValue"; - - String sql = " IF EXISTS (select * from sysobjects where id = object_id(N'" + outputProcedure - + "') and OBJECTPROPERTY(id, N'IsProcedure') = 1)" + " DROP PROCEDURE " + outputProcedure; - stmt.execute(sql); - - sql = "CREATE PROCEDURE " + outputProcedure + " @p0 int, @p1 int OUTPUT, @p2 char(50) OUTPUT, " + "@p3 varchar(max) OUTPUT " + " AS" - + " SELECT top 1 @p1=DocumentID, @p2=Title," + " @p3=DocumentSummary FROM Document_JDBC_Sample where DocumentID = @p0"; - - stmt.execute(sql); - } - - private static void createTable(Connection con) throws SQLException { - Statement stmt = con.createStatement(); - - stmt.execute("if exists (select * from sys.objects where name = 'Document_JDBC_Sample')" + "drop table Document_JDBC_Sample"); - - String sql = "CREATE TABLE Document_JDBC_Sample(" + "[DocumentID] [int] NOT NULL identity," + "[Title] [char](50) NOT NULL," - + "[DocumentSummary] [varchar](max) NULL)"; - - stmt.execute(sql); - - sql = "INSERT Document_JDBC_Sample VALUES ('title1','summary1') "; - stmt.execute(sql); - - sql = "INSERT Document_JDBC_Sample VALUES ('title2','summary2') "; - stmt.execute(sql); - - sql = "INSERT Document_JDBC_Sample VALUES ('title3','summary3') "; - stmt.execute(sql); - } -} diff --git a/src/samples/adaptive/src/main/java/readLargeData.java b/src/samples/adaptive/src/main/java/readLargeData.java deleted file mode 100644 index f52d5e18c..000000000 --- a/src/samples/adaptive/src/main/java/readLargeData.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ -package adaptive.src.main.java; - -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.io.Reader; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -import com.microsoft.sqlserver.jdbc.SQLServerStatement; - -public class readLargeData { - - public static void main(String[] args) { - - // Declare the JDBC objects. - Connection con = null; - Statement stmt = null; - ResultSet rs = null; - - String serverName = null; - String portNumber = null; - String databaseName = null; - String username = null; - String password = null; - - try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) { - - System.out.print("Enter server name: "); - serverName = br.readLine(); - System.out.print("Enter port number: "); - portNumber = br.readLine(); - System.out.print("Enter database name: "); - databaseName = br.readLine(); - System.out.print("Enter username: "); - username = br.readLine(); - System.out.print("Enter password: "); - password = br.readLine(); - - // Create a variable for the connection string. - String connectionUrl = "jdbc:sqlserver://" + serverName + ":" + portNumber + ";" + "databaseName=" + databaseName + ";username=" - + username + ";password=" + password + ";"; - - // Establish the connection. - Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); - con = DriverManager.getConnection(connectionUrl); - - createTable(con); - - // Create test data as an example. - StringBuffer buffer = new StringBuffer(4000); - for (int i = 0; i < 4000; i++) - buffer.append((char) ('A')); - - PreparedStatement pstmt = con.prepareStatement("UPDATE Document_JDBC_Sample " + "SET DocumentSummary = ? WHERE (DocumentID = 1)"); - - pstmt.setString(1, buffer.toString()); - pstmt.executeUpdate(); - pstmt.close(); - - // In adaptive mode, the application does not have to use a server cursor - // to avoid OutOfMemoryError when the SELECT statement produces very large - // results. - - // Create and execute an SQL statement that returns some data. - String SQL = "SELECT Title, DocumentSummary " + "FROM Document_JDBC_Sample"; - stmt = con.createStatement(); - - // Display the response buffering mode. - SQLServerStatement SQLstmt = (SQLServerStatement) stmt; - System.out.println("Response buffering mode is: " + SQLstmt.getResponseBuffering()); - - // Get the updated data from the database and display it. - rs = stmt.executeQuery(SQL); - - while (rs.next()) { - Reader reader = rs.getCharacterStream(2); - if (reader != null) { - char output[] = new char[40]; - while (reader.read(output) != -1) { - // Print the chunk of the data that was read. - String stringOutput = new String(output); - System.out.println("Document_Summary Data Chunk: " + stringOutput); - } - - System.out.println(rs.getString(1) + " has been accessed for the summary column."); - // Close the stream. - reader.close(); - } - } - } - // Handle any errors that may have occurred. - catch (Exception e) { - e.printStackTrace(); - } - finally { - if (rs != null) - try { - rs.close(); - } - catch (Exception e) { - } - if (stmt != null) - try { - stmt.close(); - } - catch (Exception e) { - } - if (con != null) - try { - con.close(); - } - catch (Exception e) { - } - } - } - - private static void createTable(Connection con) throws SQLException { - Statement stmt = con.createStatement(); - - stmt.execute("if exists (select * from sys.objects where name = 'Document_JDBC_Sample')" + "drop table Document_JDBC_Sample"); - - String sql = "CREATE TABLE Document_JDBC_Sample (" + "[DocumentID] [int] NOT NULL identity," + "[Title] [char](50) NOT NULL," - + "[DocumentSummary] [varchar](max) NULL)"; - - stmt.execute(sql); - - sql = "INSERT Document_JDBC_Sample VALUES ('title1','summary1') "; - stmt.execute(sql); - - sql = "INSERT Document_JDBC_Sample VALUES ('title2','summary2') "; - stmt.execute(sql); - - sql = "INSERT Document_JDBC_Sample VALUES ('title3','summary3') "; - stmt.execute(sql); - } -} diff --git a/src/samples/adaptive/src/main/java/updateLargeData.java b/src/samples/adaptive/src/main/java/updateLargeData.java deleted file mode 100644 index f11c1ccc5..000000000 --- a/src/samples/adaptive/src/main/java/updateLargeData.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ -package adaptive.src.main.java; - -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.io.Reader; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -import com.microsoft.sqlserver.jdbc.SQLServerStatement; - -public class updateLargeData { - - public static void main(String[] args) { - - // Declare the JDBC objects. - Connection con = null; - Statement stmt = null; - ResultSet rs = null; - - String serverName = null; - String portNumber = null; - String databaseName = null; - String username = null; - String password = null; - - Reader reader = null; - - try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) { - - System.out.print("Enter server name: "); - serverName = br.readLine(); - System.out.print("Enter port number: "); - portNumber = br.readLine(); - System.out.print("Enter database name: "); - databaseName = br.readLine(); - System.out.print("Enter username: "); - username = br.readLine(); - System.out.print("Enter password: "); - password = br.readLine(); - - // Create a variable for the connection string. - String connectionUrl = "jdbc:sqlserver://" + serverName + ":" + portNumber + ";" + "databaseName=" + databaseName + ";username=" - + username + ";password=" + password + ";"; - - // Establish the connection. - Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); - con = DriverManager.getConnection(connectionUrl); - - createTable(con); - - stmt = con.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); - - // Since the summaries could be large, we should make sure that - // the driver reads them incrementally from a database, - // even though a server cursor is used for the updatable result sets. - - // The recommended way to access the Microsoft JDBC Driver for SQL Server - // specific methods is to use the JDBC 4.0 Wrapper functionality. - // The following code statement demonstrates how to use the - // Statement.isWrapperFor and Statement.unwrap methods - // to access the driver specific response buffering methods. - - if (stmt.isWrapperFor(com.microsoft.sqlserver.jdbc.SQLServerStatement.class)) { - SQLServerStatement SQLstmt = stmt.unwrap(com.microsoft.sqlserver.jdbc.SQLServerStatement.class); - - SQLstmt.setResponseBuffering("adaptive"); - System.out.println("Response buffering mode has been set to " + SQLstmt.getResponseBuffering()); - } - - // Select all of the document summaries. - rs = stmt.executeQuery("SELECT Title, DocumentSummary FROM Document_JDBC_Sample"); - - // Update each document summary. - while (rs.next()) { - - // Retrieve the original document summary. - reader = rs.getCharacterStream("DocumentSummary"); - - if (reader == null) { - // Update the document summary. - System.out.println("Updating " + rs.getString("Title")); - rs.updateString("DocumentSummary", "Work in progress"); - rs.updateRow(); - } - else { - System.out.println("reading " + rs.getString("Title")); - reader.close(); - reader = null; - } - } - } - // Handle any errors that may have occurred. - catch (Exception e) { - e.printStackTrace(); - } - finally { - if (reader != null) - try { - reader.close(); - } - catch (Exception e) { - } - if (rs != null) - try { - rs.close(); - } - catch (Exception e) { - } - if (stmt != null) - try { - stmt.close(); - } - catch (Exception e) { - } - if (con != null) - try { - con.close(); - } - catch (Exception e) { - } - } - } - - private static void createTable(Connection con) throws SQLException { - Statement stmt = con.createStatement(); - - stmt.execute("if exists (select * from sys.objects where name = 'Document_JDBC_Sample')" + "drop table Document_JDBC_Sample"); - - String sql = "CREATE TABLE Document_JDBC_Sample (" + "[DocumentID] [int] NOT NULL identity," + "[Title] [char](50) NOT NULL," - + "[DocumentSummary] [varchar](max) NULL)"; - - stmt.execute(sql); - - sql = "INSERT Document_JDBC_Sample VALUES ('title1','summary1') "; - stmt.execute(sql); - - sql = "INSERT Document_JDBC_Sample (title) VALUES ('title2') "; - stmt.execute(sql); - - sql = "INSERT Document_JDBC_Sample (title) VALUES ('title3') "; - stmt.execute(sql); - - sql = "INSERT Document_JDBC_Sample VALUES ('title4','summary3') "; - stmt.execute(sql); - } -} diff --git a/src/samples/alwaysencrypted/pom.xml b/src/samples/alwaysencrypted/pom.xml index 2116cfeda..aa764957d 100644 --- a/src/samples/alwaysencrypted/pom.xml +++ b/src/samples/alwaysencrypted/pom.xml @@ -1,34 +1,28 @@ - 4.0.0 - com.microsoft.sqlserver.jdbc alwaysencrypted 0.0.1 - jar - ${project.artifactId} https://github.com/Microsoft/mssql-jdbc/tree/master/src/samples - UTF-8 - com.microsoft.sqlserver mssql-jdbc - 6.4.0.jre9 + 7.0.0.jre10 - AlwaysEncrypted AlwaysEncrypted - org.codehaus.mojo @@ -42,18 +36,16 @@ - org.apache.maven.plugins maven-compiler-plugin - 9 - 9 + 10 + 10 - org.apache.maven.plugins maven-resources-plugin @@ -61,5 +53,4 @@ - diff --git a/src/samples/alwaysencrypted/src/main/java/AlwaysEncrypted.java b/src/samples/alwaysencrypted/src/main/java/AlwaysEncrypted.java index abdd4a970..a8adb8587 100644 --- a/src/samples/alwaysencrypted/src/main/java/AlwaysEncrypted.java +++ b/src/samples/alwaysencrypted/src/main/java/AlwaysEncrypted.java @@ -1,28 +1,24 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package alwaysencrypted.src.main.java; import java.io.BufferedReader; -import java.io.IOException; import java.io.InputStreamReader; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; - import com.microsoft.sqlserver.jdbc.SQLServerColumnEncryptionJavaKeyStoreProvider; import com.microsoft.sqlserver.jdbc.SQLServerColumnEncryptionKeyStoreProvider; import com.microsoft.sqlserver.jdbc.SQLServerException; + /** - * This program demonstrates how to create Column Master Key (CMK) and Column Encryption Key (CEK) CMK is created first and then it is used to create - * CEK + * Sample application to demonstrate how to create Column Master Key and Column Encryption Key for use + * with the Java Key Store for Always Encrypted feature. */ public class AlwaysEncrypted { // Alias of the key stored in the keystore. @@ -41,19 +37,20 @@ public class AlwaysEncrypted { private static char[] keyStoreSecret = null; /** - * Name of the encryption algorithm used to encrypt the value of the column encryption key. The algorithm for the system providers must be - * RSA_OAEP. + * Name of the encryption algorithm used to encrypt the value of the column encryption key. The algorithm for the + * system providers must be RSA_OAEP. */ private static String algorithm = "RSA_OAEP"; - private static String serverName = null; - private static String portNumber = null; - private static String databaseName = null; - private static String username = null; - private static String password = null; - public static void main(String[] args) { - try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) { + + String serverName = null; + String portNumber = null; + String databaseName = null; + String username = null; + String password = null; + + try (InputStreamReader in = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(in)) { System.out.print("Enter server name: "); serverName = br.readLine(); System.out.print("Enter port number: "); @@ -65,34 +62,29 @@ public static void main(String[] args) { System.out.print("Enter password: "); password = br.readLine(); - System.out.print("Enter the location of the keystore: "); // e.g. C:\\Dev\\Always Encrypted\\keystore.jks + System.out.print("Enter the location of the keystore: "); + // e.g. C:\\Dev\\Always Encrypted\\keystore.jks keyStoreLocation = br.readLine(); - System.out.print("Enter the alias of the key stored in the keystore: "); // e.g. lp-e796acea-c3bd-4a27-b657-2bb71e3517d1 + System.out.print("Enter the alias of the key stored in the keystore: "); + // e.g. lp-e796acea-c3bd-4a27-b657-2bb71e3517d1 keyAlias = br.readLine(); System.out.print("Enter the password of the keystore and the key: "); + // keyStoreSecret = br.readLine().toCharArray(); - } - catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - String connectionString = GetConnectionString(); - try { - // Note: if you are not using try-with-resources statements (as here), - // you must remember to call close() on any Connection, Statement, - // ResultSet objects that you create. + String connectionUrl = "jdbc:sqlserver://" + serverName + ":" + portNumber + ";" + "databaseName=" + + databaseName + ";username=" + username + ";password=" + password + ";"; // Open a connection to the database. - Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); - try (Connection sourceConnection = DriverManager.getConnection(connectionString)) { + try (Connection connection = DriverManager.getConnection(connectionUrl); + Statement stmt = connection.createStatement()) { // Instantiate the Java Key Store provider. - SQLServerColumnEncryptionKeyStoreProvider storeProvider = new SQLServerColumnEncryptionJavaKeyStoreProvider(keyStoreLocation, - keyStoreSecret); + SQLServerColumnEncryptionKeyStoreProvider storeProvider = new SQLServerColumnEncryptionJavaKeyStoreProvider( + keyStoreLocation, keyStoreSecret); - dropKeys(sourceConnection); + dropKeys(stmt); System.out.println(); @@ -100,48 +92,44 @@ public static void main(String[] args) { * Create column mater key For details on syntax refer: https://msdn.microsoft.com/library/mt146393.aspx * */ - String createCMKSQL = "CREATE COLUMN MASTER KEY " + columnMasterKeyName + " WITH ( " + " KEY_STORE_PROVIDER_NAME = '" - + storeProvider.getName() + "' , KEY_PATH = '" + keyAlias + "' ) "; + String createCMKSQL = "CREATE COLUMN MASTER KEY " + columnMasterKeyName + " WITH ( " + + " KEY_STORE_PROVIDER_NAME = '" + storeProvider.getName() + "' , KEY_PATH = '" + keyAlias + + "' ) "; - try (Statement cmkStatement = sourceConnection.createStatement()) { - cmkStatement.executeUpdate(createCMKSQL); - System.out.println("Column Master Key created with name : " + columnMasterKeyName); - } + stmt.executeUpdate(createCMKSQL); + System.out.println("Column Master Key created with name : " + columnMasterKeyName); byte[] encryptedCEK = getEncryptedCEK(storeProvider); /** - * Create column encryption key For more details on the syntax refer: https://msdn.microsoft.com/library/mt146372.aspx Encrypted CEK - * first needs to be converted into varbinary_literal from bytes, for which DatatypeConverter.printHexBinary is used + * Create column encryption key For more details on the syntax refer: + * https://msdn.microsoft.com/library/mt146372.aspx Encrypted CEK first needs to be converted into + * varbinary_literal from bytes, for which DatatypeConverter.printHexBinary is used */ - String createCEKSQL = "CREATE COLUMN ENCRYPTION KEY " + columnEncryptionKey + " WITH VALUES ( " + " COLUMN_MASTER_KEY = " - + columnMasterKeyName + " , ALGORITHM = '" + algorithm + "' , ENCRYPTED_VALUE = 0x" - + bytesToHexString(encryptedCEK, encryptedCEK.length) + " ) "; - - try (Statement cekStatement = sourceConnection.createStatement()) { - cekStatement.executeUpdate(createCEKSQL); - System.out.println("CEK created with name : " + columnEncryptionKey); - } + String createCEKSQL = "CREATE COLUMN ENCRYPTION KEY " + columnEncryptionKey + " WITH VALUES ( " + + " COLUMN_MASTER_KEY = " + columnMasterKeyName + " , ALGORITHM = '" + algorithm + + "' , ENCRYPTED_VALUE = 0x" + bytesToHexString(encryptedCEK, encryptedCEK.length) + " ) "; + + stmt.executeUpdate(createCEKSQL); + System.out.println("CEK created with name : " + columnEncryptionKey); } - } - catch (Exception e) { + } catch (Exception e) { // Handle any errors that may have occurred. e.printStackTrace(); } } - + /** * * @param b - * byte value + * byte value * @param length - * length of the array + * length of the array * @return */ final static char[] hexChars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; - private static String bytesToHexString(byte[] b, - int length) { + private static String bytesToHexString(byte[] b, int length) { StringBuilder sb = new StringBuilder(length * 2); for (int i = 0; i < length; i++) { int hexVal = b[i] & 0xFF; @@ -151,20 +139,12 @@ private static String bytesToHexString(byte[] b, return sb.toString(); } - // To avoid storing the sourceConnection String in your code, - // you can retrieve it from a configuration file. - private static String GetConnectionString() { - // Create a variable for the connection string. - String connectionUrl = "jdbc:sqlserver://" + serverName + ":" + portNumber + ";" + "databaseName=" + databaseName + ";username=" + username - + ";password=" + password + ";"; - - return connectionUrl; - } - - private static byte[] getEncryptedCEK(SQLServerColumnEncryptionKeyStoreProvider storeProvider) throws SQLServerException { + private static byte[] getEncryptedCEK( + SQLServerColumnEncryptionKeyStoreProvider storeProvider) throws SQLServerException { /** - * Following arguments needed by SQLServerColumnEncryptionJavaKeyStoreProvider 1) keyStoreLocation : Path where keystore is located, including - * the keystore file name. 2) keyStoreSecret : Password of the keystore and the key. + * Following arguments needed by SQLServerColumnEncryptionJavaKeyStoreProvider 1) keyStoreLocation : Path where + * keystore is located, including the keystore file name. 2) keyStoreSecret : Password of the keystore and the + * key. */ String plainTextKey = "You need to give your plain text"; @@ -177,13 +157,13 @@ private static byte[] getEncryptedCEK(SQLServerColumnEncryptionKeyStoreProvider return encryptedCEK; } - private static void dropKeys(Connection sourceConnection) throws SQLException { - String cekSql = " if exists (SELECT name from sys.column_encryption_keys where name='" + columnEncryptionKey + "')" + " begin" - + " drop column encryption key " + columnEncryptionKey + " end"; - sourceConnection.createStatement().execute(cekSql); + private static void dropKeys(Statement stmt) throws SQLException { + String cekSql = " if exists (SELECT name from sys.column_encryption_keys where name='" + columnEncryptionKey + + "')" + " begin" + " drop column encryption key " + columnEncryptionKey + " end"; + stmt.execute(cekSql); - cekSql = " if exists (SELECT name from sys.column_master_keys where name='" + columnMasterKeyName + "')" + " begin" - + " drop column master key " + columnMasterKeyName + " end"; - sourceConnection.createStatement().execute(cekSql); + cekSql = " if exists (SELECT name from sys.column_master_keys where name='" + columnMasterKeyName + "')" + + " begin" + " drop column master key " + columnMasterKeyName + " end"; + stmt.execute(cekSql); } } diff --git a/src/samples/azureactivedirectoryauthentication/pom.xml b/src/samples/azureactivedirectoryauthentication/pom.xml index 17e4522a8..c51324ef6 100644 --- a/src/samples/azureactivedirectoryauthentication/pom.xml +++ b/src/samples/azureactivedirectoryauthentication/pom.xml @@ -1,34 +1,27 @@ 4.0.0 - com.microsoft.sqlserver.jdbc AzureActiveDirectoryAuthentication 0.0.1 - jar - ${project.artifactId} https://github.com/Microsoft/mssql-jdbc/tree/master/src/samples - UTF-8 - com.microsoft.sqlserver mssql-jdbc - 6.4.0.jre9 + 7.0.0.jre10 - AzureActiveDirectoryAuthentication AzureActiveDirectoryAuthentication - org.codehaus.mojo @@ -42,18 +35,16 @@ - org.apache.maven.plugins maven-compiler-plugin - 1.8 - 1.8 + 10 + 10 - org.apache.maven.plugins maven-resources-plugin @@ -61,5 +52,4 @@ - diff --git a/src/samples/azureactivedirectoryauthentication/src/main/java/AzureActiveDirectoryAuthentication.java b/src/samples/azureactivedirectoryauthentication/src/main/java/AzureActiveDirectoryAuthentication.java index 6436c9da6..0bf544464 100644 --- a/src/samples/azureactivedirectoryauthentication/src/main/java/AzureActiveDirectoryAuthentication.java +++ b/src/samples/azureactivedirectoryauthentication/src/main/java/AzureActiveDirectoryAuthentication.java @@ -1,31 +1,39 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package azureactivedirectoryauthentication.src.main.java; import java.io.BufferedReader; import java.io.InputStreamReader; -import java.sql.CallableStatement; import java.sql.Connection; import java.sql.ResultSet; import java.sql.Statement; import com.microsoft.sqlserver.jdbc.SQLServerDataSource; + +/** + * Sample application that demonstrates how to establidh secure connection to Azure Database, Azure Data Warehouse and + * any other cloud database. Users can use 'ActiveDirectoryPassword' or 'ActiveDirectoryIntegrated' Authentication modes + * as per their needs. + * + * This test can be used to establish connection by both modes on any operating system, if required setup is provided + * for Active Directory Integrated Authentication. + * + * For testing 'ActiveDirectoryIntegrated' Authentication, do one of the following: + * + * 1. Generate Kerberos Ticket and validate its availability with klist tool, or + * + * 2. Place sqljdbc_auth.dll in the same directory as the pom.xml file. (Only applicable for Windows OS) + * + * For testing 'ActiveDirectoryPassword' Authentication, none of the above setup is required. + * + */ public class AzureActiveDirectoryAuthentication { public static void main(String[] args) { - // Declare the JDBC objects. - Connection con = null; - Statement stmt = null; - CallableStatement cstmt = null; - ResultSet rs = null; - String serverName = null; String portNumber = null; String databaseName = null; @@ -34,10 +42,16 @@ public static void main(String[] args) { String authentication = null; String hostNameInCertificate = null; - try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) { + try (InputStreamReader in = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(in)) { - System.out.println("Remember to put sqljdbc_auth.dll in the same directory as the pom.xml file."); + System.out.println("For testing 'ActiveDirectoryIntegrated' Authentication, do one of the following:"); + System.out.println(" 1. Generate Kerberos Ticket and validate its availability with klist tool, or"); + System.out.println(" 2. Place sqljdbc_auth.dll in the same directory as the pom.xml file."); + System.out.println( + "For testing 'ActiveDirectoryPassword' Authentication, none of the above setup is not required.");// + System.out.println(); + // Start capturing database info System.out.print("Enter server name: "); serverName = br.readLine(); System.out.print("Enter port number: "); @@ -48,9 +62,9 @@ public static void main(String[] args) { username = br.readLine(); System.out.print("Enter password: "); password = br.readLine(); - System.out.print("Enter authentication: "); // e.g. ActiveDirectoryPassword + System.out.print("Enter authentication: "); // e.g. ActiveDirectoryPassword / ActiveDirectoryIntegrated authentication = br.readLine(); - System.out.print("Enter host name in certificate: "); // e.g. *.database.windows.net + System.out.print("Enter host name in certificate: "); // e.g. *.database.windows.net hostNameInCertificate = br.readLine(); // Establish the connection. @@ -63,45 +77,24 @@ public static void main(String[] args) { ds.setAuthentication(authentication); ds.setHostNameInCertificate(hostNameInCertificate); - con = ds.getConnection(); + try (Connection con = ds.getConnection(); Statement stmt = con.createStatement();) { + System.out.println(); + System.out.println("Connection established successfully."); - System.out.println(); - System.out.println("Connection established successfully."); - - // Create and execute an SQL statement that returns user name. - String SQL = "SELECT SUSER_SNAME()"; - stmt = con.createStatement(); - rs = stmt.executeQuery(SQL); + // Create and execute an SQL statement that returns user name. + String SQL = "SELECT SUSER_SNAME()"; + try (ResultSet rs = stmt.executeQuery(SQL)) { - // Iterate through the data in the result set and display it. - while (rs.next()) { - System.out.println("user name: " + rs.getString(1)); + // Iterate through the data in the result set and display it. + while (rs.next()) { + System.out.println("user name: " + rs.getString(1)); + } + } } } // Handle any errors that may have occurred. catch (Exception e) { e.printStackTrace(); } - - finally { - if (rs != null) - try { - rs.close(); - } - catch (Exception e) { - } - if (cstmt != null) - try { - cstmt.close(); - } - catch (Exception e) { - } - if (con != null) - try { - con.close(); - } - catch (Exception e) { - } - } } } diff --git a/src/samples/connections/pom.xml b/src/samples/connections/pom.xml index 080bd427f..e80665f3a 100644 --- a/src/samples/connections/pom.xml +++ b/src/samples/connections/pom.xml @@ -1,77 +1,66 @@ 4.0.0 - com.microsoft.sqlserver.jdbc connections 0.0.1 - jar - ${project.artifactId} https://github.com/Microsoft/mssql-jdbc/tree/master/src/samples - UTF-8 - com.microsoft.sqlserver mssql-jdbc - 6.4.0.jre9 + 7.0.0.jre10 - - connectURL + ConnectURL - connectURL - + ConnectURL org.codehaus.mojo exec-maven-plugin 1.2.1 - connections.src.main.java.connectURL + connections.src.main.java.ConnectURL - - connectDS + ConnectDataSource - connectDS - + ConnectDataSource org.codehaus.mojo exec-maven-plugin 1.2.1 - connections.src.main.java.connectDS + connections.src.main.java.ConnectDataSource - org.apache.maven.plugins maven-compiler-plugin - 1.8 - 1.8 + 10 + 10 - org.apache.maven.plugins maven-resources-plugin @@ -79,5 +68,4 @@ - diff --git a/src/samples/connections/src/main/java/ConnectDataSource.java b/src/samples/connections/src/main/java/ConnectDataSource.java new file mode 100644 index 000000000..bc3980064 --- /dev/null +++ b/src/samples/connections/src/main/java/ConnectDataSource.java @@ -0,0 +1,72 @@ +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package connections.src.main.java; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.Statement; + +import com.microsoft.sqlserver.jdbc.SQLServerDataSource; + +/** + * Sample application that demonstrates how to connect to a SQL Server database by + * using a data source object. + */ +public class ConnectDataSource { + + public static void main(String[] args) { + + String serverName = null; + String portNumber = null; + String databaseName = null; + String username = null; + String password = null; + + try (InputStreamReader in = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(in)) { + + System.out.print("Enter server name: "); + serverName = br.readLine(); + System.out.print("Enter port number: "); + portNumber = br.readLine(); + System.out.print("Enter database name: "); + databaseName = br.readLine(); + System.out.print("Enter username: "); + username = br.readLine(); + System.out.print("Enter password: "); + password = br.readLine(); + + // Establish the connection. + SQLServerDataSource ds = new SQLServerDataSource(); + ds.setServerName(serverName); + ds.setPortNumber(Integer.parseInt(portNumber)); + ds.setDatabaseName(databaseName); + ds.setUser(username); + ds.setPassword(password); + + try (Connection con = ds.getConnection(); Statement stmt = con.createStatement();) { + + System.out.println(); + System.out.println("Connection established successfully."); + + // Create and execute an SQL statement that returns user name. + String SQL = "SELECT SUSER_SNAME()"; + + try (ResultSet rs = stmt.executeQuery(SQL)) { + + // Iterate through the data in the result set and display it. + while (rs.next()) { + System.out.println("user name: " + rs.getString(1)); + } + } + } + } + // Handle any errors that may have occurred. + catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/samples/connections/src/main/java/ConnectURL.java b/src/samples/connections/src/main/java/ConnectURL.java new file mode 100644 index 000000000..fa0b11b90 --- /dev/null +++ b/src/samples/connections/src/main/java/ConnectURL.java @@ -0,0 +1,69 @@ +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package connections.src.main.java; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; + + +/** + * Sample application that demonstrates how to connect to a SQL Server database by using a connection URL. + * It also demonstrates how to retrieve data from a SQL Server database by using an SQL statement. + */ +public class ConnectURL { + + public static void main(String[] args) { + + String serverName = null; + String portNumber = null; + String databaseName = null; + String username = null; + String password = null; + + try (InputStreamReader in = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(in)) { + + System.out.print("Enter server name: "); + serverName = br.readLine(); + System.out.print("Enter port number: "); + portNumber = br.readLine(); + System.out.print("Enter database name: "); + databaseName = br.readLine(); + System.out.print("Enter username: "); + username = br.readLine(); + System.out.print("Enter password: "); + password = br.readLine(); + + // Create a variable for the connection string. + String connectionUrl = "jdbc:sqlserver://" + serverName + ":" + portNumber + ";" + "databaseName=" + + databaseName + ";username=" + username + ";password=" + password + ";"; + + // Establish the connection. + try (Connection con = DriverManager.getConnection(connectionUrl); Statement stmt = con.createStatement()) { + + System.out.println(); + System.out.println("Connection established successfully."); + + // Create and execute an SQL statement that returns user name. + String SQL = "SELECT SUSER_SNAME()"; + try (ResultSet rs = stmt.executeQuery(SQL)) { + + // Iterate through the data in the result set and display it. + while (rs.next()) { + System.out.println("user name: " + rs.getString(1)); + } + } + } + } + + // Handle any errors that may have occurred. + catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/samples/connections/src/main/java/connectDS.java b/src/samples/connections/src/main/java/connectDS.java deleted file mode 100644 index d41a37224..000000000 --- a/src/samples/connections/src/main/java/connectDS.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ -package connections.src.main.java; - -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.sql.CallableStatement; -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.Statement; - -import com.microsoft.sqlserver.jdbc.SQLServerDataSource; - -public class connectDS { - - public static void main(String[] args) { - - // Declare the JDBC objects. - Connection con = null; - Statement stmt = null; - CallableStatement cstmt = null; - ResultSet rs = null; - - String serverName = null; - String portNumber = null; - String databaseName = null; - String username = null; - String password = null; - - try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) { - - System.out.print("Enter server name: "); - serverName = br.readLine(); - System.out.print("Enter port number: "); - portNumber = br.readLine(); - System.out.print("Enter database name: "); - databaseName = br.readLine(); - System.out.print("Enter username: "); - username = br.readLine(); - System.out.print("Enter password: "); - password = br.readLine(); - - // Establish the connection. - SQLServerDataSource ds = new SQLServerDataSource(); - ds.setServerName(serverName); - ds.setPortNumber(Integer.parseInt(portNumber)); - ds.setDatabaseName(databaseName); - ds.setUser(username); - ds.setPassword(password); - - con = ds.getConnection(); - - System.out.println(); - System.out.println("Connection established successfully."); - - // Create and execute an SQL statement that returns user name. - String SQL = "SELECT SUSER_SNAME()"; - stmt = con.createStatement(); - rs = stmt.executeQuery(SQL); - - // Iterate through the data in the result set and display it. - while (rs.next()) { - System.out.println("user name: " + rs.getString(1)); - } - } - // Handle any errors that may have occurred. - catch (Exception e) { - e.printStackTrace(); - } - - finally { - if (rs != null) - try { - rs.close(); - } - catch (Exception e) { - } - if (cstmt != null) - try { - cstmt.close(); - } - catch (Exception e) { - } - if (con != null) - try { - con.close(); - } - catch (Exception e) { - } - } - } -} diff --git a/src/samples/connections/src/main/java/connectURL.java b/src/samples/connections/src/main/java/connectURL.java deleted file mode 100644 index 57b40f710..000000000 --- a/src/samples/connections/src/main/java/connectURL.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ -package connections.src.main.java; - -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.Statement; - -public class connectURL { - - public static void main(String[] args) { - - // Declare the JDBC objects. - Connection con = null; - Statement stmt = null; - ResultSet rs = null; - - String serverName = null; - String portNumber = null; - String databaseName = null; - String username = null; - String password = null; - - try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) { - - System.out.print("Enter server name: "); - serverName = br.readLine(); - System.out.print("Enter port number: "); - portNumber = br.readLine(); - System.out.print("Enter database name: "); - databaseName = br.readLine(); - System.out.print("Enter username: "); - username = br.readLine(); - System.out.print("Enter password: "); - password = br.readLine(); - - // Create a variable for the connection string. - String connectionUrl = "jdbc:sqlserver://" + serverName + ":" + portNumber + ";" + "databaseName=" + databaseName + ";username=" - + username + ";password=" + password + ";"; - - // Establish the connection. - Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); - con = DriverManager.getConnection(connectionUrl); - - System.out.println(); - System.out.println("Connection established successfully."); - - // Create and execute an SQL statement that returns user name. - String SQL = "SELECT SUSER_SNAME()"; - stmt = con.createStatement(); - rs = stmt.executeQuery(SQL); - - // Iterate through the data in the result set and display it. - while (rs.next()) { - System.out.println("user name: " + rs.getString(1)); - } - } - - // Handle any errors that may have occurred. - catch (Exception e) { - e.printStackTrace(); - } - - finally { - if (rs != null) - try { - rs.close(); - } - catch (Exception e) { - } - if (stmt != null) - try { - stmt.close(); - } - catch (Exception e) { - } - if (con != null) - try { - con.close(); - } - catch (Exception e) { - } - } - } -} diff --git a/src/samples/constrained/pom.xml b/src/samples/constrained/pom.xml index a40873590..2c374ec1c 100644 --- a/src/samples/constrained/pom.xml +++ b/src/samples/constrained/pom.xml @@ -3,48 +3,40 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - com.microsoft.sqlserver.jdbc constrained 0.0.1 - jar - ${project.artifactId} https://github.com/Microsoft/mssql-jdbc/tree/master/src/samples - UTF-8 - com.microsoft.sqlserver mssql-jdbc - 6.4.0.jre9 + 7.0.0.jre10 - - ConstrainedSample + ConstrainedDelegation - ConstrainedSample - + ConstrainedDelegation org.codehaus.mojo exec-maven-plugin 1.6.0 - constrained.src.main.java.ConstrainedSample + constrained.src.main.java.ConstrainedDelegation - @@ -52,11 +44,10 @@ maven-compiler-plugin 3.6.0 - 1.8 - 1.8 + 10 + 10 - org.apache.maven.plugins maven-resources-plugin @@ -64,5 +55,4 @@ - diff --git a/src/samples/constrained/src/main/java/ConstrainedSample.java b/src/samples/constrained/src/main/java/ConstrainedDelegation.java similarity index 79% rename from src/samples/constrained/src/main/java/ConstrainedSample.java rename to src/samples/constrained/src/main/java/ConstrainedDelegation.java index 59b89ed2a..11f39b611 100644 --- a/src/samples/constrained/src/main/java/ConstrainedSample.java +++ b/src/samples/constrained/src/main/java/ConstrainedDelegation.java @@ -1,3 +1,7 @@ +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ package constrained.src.main.java; import java.security.PrivilegedActionException; @@ -18,32 +22,32 @@ import org.ietf.jgss.GSSName; import org.ietf.jgss.Oid; +import com.sun.security.auth.module.Krb5LoginModule; import com.sun.security.jgss.ExtendedGSSCredential; + /** * * Sample of constrained delegation connection. * - * An intermediate service is necessary to impersonate the client. This service needs to be configured with the - * options: - * "Trust this user for delegation to specified services only" - * "Use any authentication protocol" + * An intermediate service is necessary to impersonate the client. This service needs to be configured with the options: + * "Trust this user for delegation to specified services only" "Use any authentication protocol" * */ -public class ConstrainedSample { +public class ConstrainedDelegation { // Connection properties - private static final String DRIVER_CLASS_NAME ="com.microsoft.sqlserver.jdbc.SQLServerDriver"; - private static final String CONNECTION_URI = "jdbc:sqlserver:// URI of the SQLServer"; + private static final String CONNECTION_URI = "jdbc:sqlserver://:"; private static final String TARGET_USER_NAME = "User to be impersonated"; // Impersonation service properties private static final String SERVICE_PRINCIPAL = "SPN"; - private static final String KEYTAB_ROUTE = "Route to the keytab file"; + private static final String KEYTAB_ROUTE = ""; private static final Properties driverProperties; private static Oid krb5Oid; + private static final String KERBEROS_OID = "1.2.840.113554.1.2.2"; private static Subject serviceSubject; @@ -54,7 +58,7 @@ public class ConstrainedSample { driverProperties.setProperty("authenticationScheme", "JavaKerberos"); try { - krb5Oid = new Oid("1.2.840.113554.1.2.2"); + krb5Oid = new Oid(KERBEROS_OID); } catch (GSSException e) { System.out.println("Error creating Oid: " + e); System.exit(-1); @@ -62,8 +66,6 @@ public class ConstrainedSample { } public static void main(String... args) throws Exception { - - Class.forName(DRIVER_CLASS_NAME).getConstructor().newInstance(); System.out.println("Service subject: " + doInitialLogin()); // Get impersonated user credentials thanks S4U2self mechanism @@ -74,7 +76,6 @@ public static void main(String... args) throws Exception { try (Connection con = createConnection(impersonatedUserCreds)) { System.out.println("Connection succesfully: " + con); } - } /** @@ -82,15 +83,15 @@ public static void main(String... args) throws Exception { * Authenticate the intermediate server that is going to impersonate the client * * @return a subject for the intermediate server with the keytab credentials - * @throws PrivilegedActionException in case of failure + * @throws PrivilegedActionException + * in case of failure */ private static Subject doInitialLogin() throws PrivilegedActionException { serviceSubject = new Subject(); LoginModule krb5Module; try { - krb5Module = (LoginModule) Class.forName("com.sun.security.auth.module.Krb5LoginModule").getConstructor() - .newInstance(); + krb5Module = (LoginModule) new Krb5LoginModule(); } catch (Exception e) { System.out.print("Error loading Krb5LoginModule module: " + e); throw new PrivilegedActionException(e); @@ -113,6 +114,7 @@ private static Subject doInitialLogin() throws PrivilegedActionException { try { krb5Module.login(); krb5Module.commit(); + krb5Module.logout(); } catch (LoginException e) { System.out.print("Error authenticating with Kerberos: " + e); try { @@ -123,7 +125,6 @@ private static Subject doInitialLogin() throws PrivilegedActionException { } throw new PrivilegedActionException(e); } - return serviceSubject; } @@ -131,7 +132,8 @@ private static Subject doInitialLogin() throws PrivilegedActionException { * Generate the impersonated user credentials thanks to the S4U2self mechanism * * @return the client impersonated GSSCredential - * @throws PrivilegedActionException in case of failure + * @throws PrivilegedActionException + * in case of failure */ private static GSSCredential impersonate() throws PrivilegedActionException { return Subject.doAs(serviceSubject, (PrivilegedExceptionAction) () -> { @@ -147,12 +149,14 @@ private static GSSCredential impersonate() throws PrivilegedActionException { /** * Obtains a connection using an impersonated credential * - * @param impersonatedUserCredential impersonated user credentials + * @param impersonatedUserCredential + * impersonated user credentials * @return a connection to the SQL Server opened using the given impersonated credential - * @throws PrivilegedActionException in case of failure + * @throws PrivilegedActionException + * in case of failure */ - private static Connection createConnection(final GSSCredential impersonatedUserCredential) - throws PrivilegedActionException { + private static Connection createConnection( + final GSSCredential impersonatedUserCredential) throws PrivilegedActionException { return Subject.doAs(new Subject(), (PrivilegedExceptionAction) () -> { driverProperties.put("gsscredential", impersonatedUserCredential); diff --git a/src/samples/dataclassification/pom.xml b/src/samples/dataclassification/pom.xml new file mode 100644 index 000000000..5ca668006 --- /dev/null +++ b/src/samples/dataclassification/pom.xml @@ -0,0 +1,58 @@ + + + 4.0.0 + com.microsoft.sqlserver.jdbc + dataclassification + 0.0.1 + jar + ${project.artifactId} + https://github.com/Microsoft/mssql-jdbc/tree/master/src/samples + + UTF-8 + + + + com.microsoft.sqlserver + mssql-jdbc + 7.0.0.jre10 + + + + + DataDiscoveryAndClassification + + DataDiscoveryAndClassification + + + org.codehaus.mojo + exec-maven-plugin + 1.6.0 + + constrained.src.main.java.DataDiscoveryAndClassification + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.0 + + 10 + 10 + + + + org.apache.maven.plugins + maven-resources-plugin + 3.0.2 + + + + diff --git a/src/samples/dataclassification/src/main/java/DataDiscoveryAndClassification.java b/src/samples/dataclassification/src/main/java/DataDiscoveryAndClassification.java new file mode 100644 index 000000000..22b34e07d --- /dev/null +++ b/src/samples/dataclassification/src/main/java/DataDiscoveryAndClassification.java @@ -0,0 +1,185 @@ +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package dataclassification.src.main.java; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.Statement; + +import com.microsoft.sqlserver.jdbc.SQLServerResultSet; +import com.microsoft.sqlserver.jdbc.dataclassification.SensitivityProperty; + + +/** + * Sample test for 'SQL Data Discovery and Classification' feature + * + * SQL Server feature documentation reference: + * https://docs.microsoft.com/en-us/sql/relational-databases/security/sql-data-discovery-and-classification?view=sql-server-2017 + * + */ +public class DataDiscoveryAndClassification { + + private static boolean featureSupported = false; + + public static void main(String[] args) { + + String serverName = null; + String portNumber = null; + String databaseName = null; + String username = null; + String password = null; + + // Provides table name to be used for running test. + String tableName = "JDBC_SQL_DATA_DISCOVERY_CLASSIFICATION"; + + try (InputStreamReader in = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(in)) { + System.out + .println("Provide server credentials that supports 'SQL Discovery and Classification' feature.\n"); + System.out.print("Enter server name: "); + serverName = br.readLine(); + System.out.print("Enter port number: "); + portNumber = br.readLine(); + System.out.print("Enter database name: "); + databaseName = br.readLine(); + System.out.print("Enter username: "); + username = br.readLine(); + System.out.print("Enter password: "); + password = br.readLine(); + System.out.println(); + + // Create a variable for the connection string. + String connectionUrl = "jdbc:sqlserver://" + serverName + ":" + portNumber + ";" + "databaseName=" + + databaseName + ";username=" + username + ";password=" + password + ";"; + + // Establish the connection. + try (Connection con = DriverManager.getConnection(connectionUrl); Statement stmt = con.createStatement()) { + verifySupportability(stmt); + if (featureSupported) { + createTable(stmt, tableName); + runTests(stmt, tableName); + drop_table(stmt, tableName); + } + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * Verifies if SQL Discovery and Classification feature is applicable on target server. + * + * @param stmt + * Statement object to work with + */ + private static void verifySupportability(Statement stmt) { + try { + stmt.execute("SELECT * FROM SYS.SENSITIVITY_CLASSIFICATIONS"); + featureSupported = true; + } catch (SQLException e) { + // Error Code 208 : Object Not Found + if (e.getErrorCode() == 208) { + featureSupported = false; + System.err.println("This feature is not supported on the target SQL Server."); + } + } + } + + /** + * Creates table for the test and sets tags for Sensitivity Classification + * + * @param stmt + * Statement to work with + * @param tableName + * Table to be created + * @throws SQLException + * If an exception occurs + */ + private static void createTable(Statement stmt, String tableName) throws SQLException { + // Creates table for storing Supplier data + stmt.execute("CREATE TABLE " + tableName + " (" + "[Id] [int] IDENTITY(1,1) NOT NULL," + + "[CompanyName] [nvarchar](40) NOT NULL," + "[ContactName] [nvarchar](50) NULL," + + "[ContactTitle] [nvarchar](40) NULL," + "[City] [nvarchar](40) NULL," + + "[Country] [nvarchar](40) NULL," + "[Phone] [nvarchar](30) MASKED WITH (FUNCTION = 'default()') NULL," + + "[Fax] [nvarchar](30) MASKED WITH (FUNCTION = 'default()') NULL," + "CONSTRAINT [PK_" + tableName + + "] PRIMARY KEY CLUSTERED" + "([Id] ASC " + + ")WITH (STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]" + ") ON [PRIMARY]"); + + // Set Sensitivity Classification tags to table columns + stmt.execute("ADD SENSITIVITY CLASSIFICATION TO " + tableName + + ".CompanyName WITH (LABEL='PII', LABEL_ID='L1', INFORMATION_TYPE='Company name', INFORMATION_TYPE_ID='COMPANY')"); + stmt.execute("ADD SENSITIVITY CLASSIFICATION TO " + tableName + + ".ContactName WITH (LABEL='PII', LABEL_ID='L1', INFORMATION_TYPE='Person name', INFORMATION_TYPE_ID='NAME')"); + stmt.execute("ADD SENSITIVITY CLASSIFICATION TO " + tableName + + ".Phone WITH (LABEL='PII', LABEL_ID='L1', INFORMATION_TYPE='Contact Information', INFORMATION_TYPE_ID='CONTACT')"); + stmt.execute("ADD SENSITIVITY CLASSIFICATION TO " + tableName + + ".Fax WITH (LABEL='PII', LABEL_ID='L1', INFORMATION_TYPE='Contact Information', INFORMATION_TYPE_ID='CONTACT')"); + } + + /** + * Runs query to fetch ResultSet from target table + * + * @param stmt + * Statement to work with + * @param tableName + * Name of table to fetch results from + * @throws SQLException + * If an exception occurs + */ + private static void runTests(Statement stmt, String tableName) throws SQLException { + String query = "SELECT * FROM " + tableName; + try (SQLServerResultSet rs = (SQLServerResultSet) stmt.executeQuery(query)) { + printSensitivityClassification(rs); + } + } + + /** + * Prints Sensitivity Classification data as received in ResultSet + * + * @param rs + * Active ResultSet to read data from + * @throws SQLException + * If an exception occurs + */ + private static void printSensitivityClassification(SQLServerResultSet rs) throws SQLException { + if (null != rs.getSensitivityClassification()) { + for (int columnPos = 0; columnPos < rs.getSensitivityClassification().getColumnSensitivities().size(); + columnPos++) { + for (SensitivityProperty sp : rs.getSensitivityClassification().getColumnSensitivities().get(columnPos) + .getSensitivityProperties()) { + if (sp.getLabel() != null) { + System.out.println("Labels received for Column : " + columnPos); + System.out.println("Label ID: " + sp.getLabel().getId()); + System.out.println("Label Name: " + sp.getLabel().getName()); + System.out.println(); + } + + if (sp.getInformationType() != null) { + System.out.println("Information Types received for Column : " + columnPos); + System.out.println("Information Type ID: " + sp.getInformationType().getId()); + System.out.println("Information Type Name: " + sp.getInformationType().getName()); + System.out.println(); + } + } + } + } + } + + /** + * Drops the table created for test + * + * @param stmt + * Statement to work with + * @param tableName + * Table Name to be used + * @throws SQLException + * If an exception occurs + */ + private static void drop_table(Statement stmt, String tableName) throws SQLException { + stmt.execute("DROP TABLE " + tableName); + } +} diff --git a/src/samples/datatypes/pom.xml b/src/samples/datatypes/pom.xml index 687d626e1..f364cbec3 100644 --- a/src/samples/datatypes/pom.xml +++ b/src/samples/datatypes/pom.xml @@ -1,77 +1,83 @@ - 4.0.0 - com.microsoft.sqlserver.jdbc datatypes 0.0.1 - jar - ${project.artifactId} https://github.com/Microsoft/mssql-jdbc/tree/master/src/samples - UTF-8 - com.microsoft.sqlserver mssql-jdbc - 6.4.0.jre9 + 7.0.0.jre10 - - basicDT + BasicDataTypes - basicDT - + BasicDataTypes org.codehaus.mojo exec-maven-plugin 1.2.1 - datatypes.src.main.java.basicDT + datatypes.src.main.java.BasicDataTypes - - sqlxmlExample + SqlXmlDataType - sqlxmlExample - + SqlXmlDataType org.codehaus.mojo exec-maven-plugin 1.2.1 - datatypes.src.main.java.sqlxmlExample + datatypes.src.main.java.SqlXmlDataType + + + + + + + SpatialDataTypes + + SpatialDataTypes + + + org.codehaus.mojo + exec-maven-plugin + 1.2.1 + + datatypes.src.main.java.SpatialDataTypes - org.apache.maven.plugins maven-compiler-plugin - 9 - 9 + 10 + 10 - org.apache.maven.plugins maven-resources-plugin @@ -79,5 +85,4 @@ - diff --git a/src/samples/datatypes/src/main/java/BasicDataTypes.java b/src/samples/datatypes/src/main/java/BasicDataTypes.java new file mode 100644 index 000000000..a87dd42ee --- /dev/null +++ b/src/samples/datatypes/src/main/java/BasicDataTypes.java @@ -0,0 +1,145 @@ +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package datatypes.src.main.java; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.sql.Connection; +import java.sql.Date; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.sql.Time; +import java.sql.Timestamp; + +import com.microsoft.sqlserver.jdbc.SQLServerResultSet; + +import microsoft.sql.DateTimeOffset; + +/** + * Sample application that demonstrates how to use result set getter methods to retrieve + * basic SQL Server data type values, and how to use result set update methods to update those values. + */ +public class BasicDataTypes { + + private static String tableName = "DataTypesTable_JDBC_Sample"; + + public static void main(String[] args) { + + String serverName = null; + String portNumber = null; + String databaseName = null; + String username = null; + String password = null; + + try (InputStreamReader in = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(in)) { + System.out.print("Enter server name: "); + serverName = br.readLine(); + System.out.print("Enter port number: "); + portNumber = br.readLine(); + System.out.print("Enter database name: "); + databaseName = br.readLine(); + System.out.print("Enter username: "); + username = br.readLine(); + System.out.print("Enter password: "); + password = br.readLine(); + + // Create a variable for the connection string. + String connectionUrl = "jdbc:sqlserver://" + serverName + ":" + portNumber + ";" + "databaseName=" + + databaseName + ";username=" + username + ";password=" + password + ";"; + + // Establish the connection. + try (Connection con = DriverManager.getConnection(connectionUrl); Statement stmt = con.createStatement()) { + dropAndCreateTable(stmt); + insertOriginalData(con); + + System.out.println(); + + // Create and execute an SQL statement that returns some data + // and display it. + String SQL = "SELECT * FROM " + tableName; + try (Statement stmt1 = con.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); + ResultSet rs = stmt1.executeQuery(SQL)) { + rs.next(); + displayRow("ORIGINAL DATA", rs); + + // Update the data in the result set. + rs.updateInt(1, 200); + rs.updateString(2, "B"); + rs.updateString(3, "Some updated text."); + rs.updateBoolean(4, true); + rs.updateDouble(5, 77.89); + rs.updateDouble(6, 1000.01); + long timeInMillis = System.currentTimeMillis(); + Timestamp ts = new Timestamp(timeInMillis); + rs.updateTimestamp(7, ts); + rs.updateDate(8, new Date(timeInMillis)); + rs.updateTime(9, new Time(timeInMillis)); + rs.updateTimestamp(10, ts); + + // -480 indicates GMT - 8:00 hrs + ((SQLServerResultSet) rs).updateDateTimeOffset(11, DateTimeOffset.valueOf(ts, -480)); + + rs.updateRow(); + } + // Get the updated data from the database and display it. + try (ResultSet rs = stmt.executeQuery(SQL)) { + rs.next(); + displayRow("UPDATED DATA", rs); + } + } + } + // Handle any errors that may have occurred. + catch (Exception e) { + e.printStackTrace(); + } + } + + private static void displayRow(String title, ResultSet rs) throws SQLException { + System.out.println(title); + System.out.println(rs.getInt(1) + " , " + // SQL integer type. + rs.getString(2) + " , " + // SQL char type. + rs.getString(3) + " , " + // SQL varchar type. + rs.getBoolean(4) + " , " + // SQL bit type. + rs.getDouble(5) + " , " + // SQL decimal type. + rs.getDouble(6) + " , " + // SQL money type. + rs.getTimestamp(7) + " , " + // SQL datetime type. + rs.getDate(8) + " , " + // SQL date type. + rs.getTime(9) + " , " + // SQL time type. + rs.getTimestamp(10) + " , " + // SQL datetime2 type. + ((SQLServerResultSet) rs).getDateTimeOffset(11)); // SQL datetimeoffset type. + System.out.println(); + } + + private static void dropAndCreateTable(Statement stmt) throws SQLException { + stmt.executeUpdate("if object_id('" + tableName + "','U') is not null" + " drop table " + tableName); + + String sql = "create table " + tableName + " (" + "c1 int, " + "c2 char(20), " + "c3 varchar(20), " + "c4 bit, " + + "c5 decimal(10,5), " + "c6 money, " + "c7 datetime, " + "c8 date, " + "c9 time(7), " + + "c10 datetime2(7), " + "c11 datetimeoffset(7), " + ");"; + + stmt.execute(sql); + } + + private static void insertOriginalData(Connection con) throws SQLException { + String sql = "insert into " + tableName + " values( " + "?,?,?,?,?,?,?,?,?,?,?" + ")"; + try (PreparedStatement pstmt = con.prepareStatement(sql)) { + pstmt.setObject(1, 100); + pstmt.setObject(2, "original text"); + pstmt.setObject(3, "original text"); + pstmt.setObject(4, false); + pstmt.setObject(5, 12.34); + pstmt.setObject(6, 56.78); + pstmt.setObject(7, new java.util.Date(1453500034839L)); + pstmt.setObject(8, new java.util.Date(1453500034839L)); + pstmt.setObject(9, new java.util.Date(1453500034839L)); + pstmt.setObject(10, new java.util.Date(1453500034839L)); + pstmt.setObject(11, new java.util.Date(1453500034839L)); + pstmt.execute(); + } + } +} diff --git a/src/samples/datatypes/src/main/java/SpatialDataTypes.java b/src/samples/datatypes/src/main/java/SpatialDataTypes.java new file mode 100644 index 000000000..6a7aae6dc --- /dev/null +++ b/src/samples/datatypes/src/main/java/SpatialDataTypes.java @@ -0,0 +1,90 @@ +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package datatypes.src.main.java; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Statement; +import com.microsoft.sqlserver.jdbc.Geography; +import com.microsoft.sqlserver.jdbc.Geometry; +import com.microsoft.sqlserver.jdbc.SQLServerDataSource; +import com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement; +import com.microsoft.sqlserver.jdbc.SQLServerResultSet; + +/** + * Sample application that demonstrates how to use prepared statement setter methods to + * set values for SQL Server Spatial Datatypes 'Geography' and 'Geometry'. + * + * It also demonstrates how to use result set getter methods to read and parse SQL Server + * Spatial data type values. + */ +public class SpatialDataTypes { + + private static String tableName = "SpatialDataTypesTable_JDBC_Sample"; + + public static void main(String[] args) { + + String serverName = null; + String portNumber = null; + String databaseName = null; + String username = null; + String password = null; + + try (InputStreamReader in = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(in)) { + System.out.print("Enter server name: "); + serverName = br.readLine(); + System.out.print("Enter port number: "); + portNumber = br.readLine(); + System.out.print("Enter database name: "); + databaseName = br.readLine(); + System.out.print("Enter username: "); + username = br.readLine(); + System.out.print("Enter password: "); + password = br.readLine(); + + // Establish the connection. + SQLServerDataSource ds = new SQLServerDataSource(); + ds.setServerName(serverName); + ds.setPortNumber(Integer.parseInt(portNumber)); + ds.setDatabaseName(databaseName); + ds.setUser(username); + ds.setPassword(password); + + // Establish the connection. + try (Connection con = ds.getConnection(); Statement stmt = con.createStatement();) { + dropAndCreateTable(stmt); + + // TODO: Implement Sample code + String geoWKT = "POINT(3 40 5 6)"; + Geometry geomWKT = Geometry.STGeomFromText(geoWKT, 0); + Geography geogWKT = Geography.STGeomFromText(geoWKT, 4326); + + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con + .prepareStatement("insert into " + tableName + " values (?, ?)");) { + pstmt.setGeometry(1, geomWKT); + pstmt.setGeography(2, geogWKT); + pstmt.execute(); + + SQLServerResultSet rs = (SQLServerResultSet) stmt.executeQuery("select * from " + tableName); + rs.next(); + + System.out.println("Geometry data: " + rs.getGeometry(1)); + System.out.println("Geography data: " + rs.getGeography(2)); + } + + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static void dropAndCreateTable(Statement stmt) throws SQLException { + stmt.executeUpdate("if object_id('" + tableName + "','U') is not null" + " drop table " + tableName); + + stmt.executeUpdate("Create table " + tableName + " (c1 geometry, c2 geography)"); + } +} diff --git a/src/samples/datatypes/src/main/java/sqlxmlExample.java b/src/samples/datatypes/src/main/java/SqlXmlDataType.java similarity index 52% rename from src/samples/datatypes/src/main/java/sqlxmlExample.java rename to src/samples/datatypes/src/main/java/SqlXmlDataType.java index 0dc314f48..5f6c627fc 100644 --- a/src/samples/datatypes/src/main/java/sqlxmlExample.java +++ b/src/samples/datatypes/src/main/java/SqlXmlDataType.java @@ -1,18 +1,17 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package datatypes.src.main.java; import java.io.BufferedReader; +import java.io.IOException; import java.io.InputStreamReader; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; +import java.sql.SQLException; import java.sql.SQLXML; import java.sql.Statement; @@ -28,23 +27,21 @@ import org.xml.sax.SAXException; import org.xml.sax.XMLReader; -public class sqlxmlExample { +/** + * Sample application that demonstrates how to store XML data in a relational database, + * how to retrieve XML data from a database, and how to parse XML data with the SQLXML Java data type. + */ +public class SqlXmlDataType { public static void main(String[] args) { - // Declare the JDBC objects. - Connection con = null; - Statement stmt = null; - ResultSet rs = null; - String serverName = null; String portNumber = null; String databaseName = null; String username = null; String password = null; - try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) { - + try (InputStreamReader in = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(in)) { System.out.print("Enter server name: "); serverName = br.readLine(); System.out.print("Enter port number: "); @@ -57,66 +54,46 @@ public static void main(String[] args) { password = br.readLine(); // Create a variable for the connection string. - String connectionUrl = "jdbc:sqlserver://" + serverName + ":" + portNumber + ";" + "databaseName=" + databaseName + ";username=" - + username + ";password=" + password + ";"; + String connectionUrl = "jdbc:sqlserver://" + serverName + ":" + portNumber + ";" + "databaseName=" + + databaseName + ";username=" + username + ";password=" + password + ";"; // Establish the connection. - Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); - con = DriverManager.getConnection(connectionUrl); + try (Connection con = DriverManager.getConnection(connectionUrl); + Statement stmt = con.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE)) { - // Create initial sample data. - createSampleTables(con); + // Create initial sample data. + createSampleTables(stmt); - // The showGetters method demonstrates how to parse the data in the - // SQLXML object by using the SAX, ContentHandler and XMLReader. - showGetters(con); + // The showGetters method demonstrates how to parse the data in the + // SQLXML object by using the SAX, ContentHandler and XMLReader. + showGetters(stmt); - // The showSetters method demonstrates how to set the xml column - // by using the SAX, ContentHandler, and ResultSet. - showSetters(con); + // The showSetters method demonstrates how to set the xml column + // by using the SAX, ContentHandler, and ResultSet. + showSetters(con, stmt); - // The showTransformer method demonstrates how to get an XML data - // from one table and insert that XML data to another table - // by using the SAX and the Transformer. - showTransformer(con); + // The showTransformer method demonstrates how to get an XML data + // from one table and insert that XML data to another table + // by using the SAX and the Transformer. + showTransformer(con, stmt); + } } // Handle any errors that may have occurred. catch (Exception e) { e.printStackTrace(); } - finally { - if (rs != null) - try { - rs.close(); - } - catch (Exception e) { - } - if (stmt != null) - try { - stmt.close(); - } - catch (Exception e) { - } - if (con != null) - try { - con.close(); - } - catch (Exception e) { - } - } } - private static void showGetters(Connection con) { + private static void showGetters(Statement stmt) throws IOException, SAXException, SQLException { + + // Create an instance of the custom content handler. + ExampleContentHandler myHandler = new ExampleContentHandler(); - try { - // Create an instance of the custom content handler. - ExampleContentHandler myHandler = new ExampleContentHandler(); + // Create and execute an SQL statement that returns a + // set of data. + String SQL = "SELECT * FROM TestTable1"; - // Create and execute an SQL statement that returns a - // set of data. - String SQL = "SELECT * FROM TestTable1"; - Statement stmt = con.createStatement(); - ResultSet rs = stmt.executeQuery(SQL); + try (ResultSet rs = stmt.executeQuery(SQL)) { rs.next(); @@ -129,20 +106,14 @@ private static void showGetters(Connection con) { System.out.println("showGetters method: Parse an XML data in TestTable1 => "); xmlReader.parse(sxSource.getInputSource()); - - } - catch (Exception e) { - e.printStackTrace(); } } - private static void showSetters(Connection con) { + private static void showSetters(Connection con, Statement stmt) { - try { - // Create and execute an SQL statement, retrieving an updatable result set. - String SQL = "SELECT * FROM TestTable1;"; - Statement stmt = con.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); - ResultSet rs = stmt.executeQuery(SQL); + // Create and execute an SQL statement, retrieving an updatable result set. + String SQL = "SELECT * FROM TestTable1;"; + try (ResultSet rs = stmt.executeQuery(SQL)) { // Create an empty SQLXML object. SQLXML sqlxml = con.createSQLXML(); @@ -174,20 +145,17 @@ private static void showSetters(Connection con) { SQLXML xml = rs.getSQLXML("Col3"); System.out.println("XML column : " + xml.getString()); } - } - catch (Exception e) { + } catch (Exception e) { e.printStackTrace(); } } - private static void showTransformer(Connection con) { + private static void showTransformer(Connection con, Statement stmt) throws Exception { - try { - // Create and execute an SQL statement that returns a - // set of data. - String SQL = "SELECT * FROM TestTable1"; - Statement stmt = con.createStatement(); - ResultSet rs = stmt.executeQuery(SQL); + // Create and execute an SQL statement that returns a + // set of data. + String SQL = "SELECT * FROM TestTable1"; + try (ResultSet rs = stmt.executeQuery(SQL)) { rs.next(); @@ -207,19 +175,19 @@ private static void showTransformer(Connection con) { SAXTransformerFactory stf = (SAXTransformerFactory) TransformerFactory.newInstance(); Transformer identity = stf.newTransformer(); identity.transform(sxSource, sxResult); - // Insert the destination SQLXML object into the database. - PreparedStatement psmt = con.prepareStatement("INSERT INTO TestTable2" + " (Col2, Col3, Col4, Col5) VALUES (?, ?, ?, ?)"); - psmt.setString(1, "A"); - psmt.setString(2, "Test data"); - psmt.setInt(3, 123); - psmt.setSQLXML(4, xmlDest); - psmt.execute(); - - // Execute the query and display the data. - SQL = "SELECT * FROM TestTable2"; - stmt = con.createStatement(); - rs = stmt.executeQuery(SQL); + try (PreparedStatement psmt = con + .prepareStatement("INSERT INTO TestTable2" + " (Col2, Col3, Col4, Col5) VALUES (?, ?, ?, ?)")) { + psmt.setString(1, "A"); + psmt.setString(2, "Test data"); + psmt.setInt(3, 123); + psmt.setSQLXML(4, xmlDest); + psmt.execute(); + } + } + // Execute the query and display the data. + SQL = "SELECT * FROM TestTable2"; + try (ResultSet rs = stmt.executeQuery(SQL)) { System.out.println("showTransformer method : Display data in TestTable2 => "); while (rs.next()) { @@ -230,57 +198,41 @@ private static void showTransformer(Connection con) { System.out.println("XML column : " + xml.getString()); } } - catch (Exception e) { - e.printStackTrace(); - } } - private static void createSampleTables(Connection con) { - - try { - Statement stmt = con.createStatement(); - - // Drop the tables. - stmt.executeUpdate("if exists (select * from sys.objects where name = 'TestTable1')" + "drop table TestTable1"); + private static void createSampleTables(Statement stmt) throws SQLException { + // Drop the tables. + stmt.executeUpdate("if exists (select * from sys.objects where name = 'TestTable1')" + "drop table TestTable1"); - stmt.executeUpdate("if exists (select * from sys.objects where name = 'TestTable2')" + "drop table TestTable2"); + stmt.executeUpdate("if exists (select * from sys.objects where name = 'TestTable2')" + "drop table TestTable2"); - // Create empty tables. - stmt.execute("CREATE TABLE TestTable1 (Col1 int IDENTITY, Col2 char, Col3 xml)"); - stmt.execute("CREATE TABLE TestTable2 (Col1 int IDENTITY, Col2 char, Col3 varchar(50), Col4 int, Col5 xml)"); + // Create empty tables. + stmt.execute("CREATE TABLE TestTable1 (Col1 int IDENTITY, Col2 char, Col3 xml)"); + stmt.execute("CREATE TABLE TestTable2 (Col1 int IDENTITY, Col2 char, Col3 varchar(50), Col4 int, Col5 xml)"); - // Insert two rows to the TestTable1. - String row1 = "Contact Name 1XXX-XXX-XXXX"; - String row2 = "Contact Name 2YYY-YYY-YYYY"; + // Insert two rows to the TestTable1. + String row1 = "Contact Name 1XXX-XXX-XXXX"; + String row2 = "Contact Name 2YYY-YYY-YYYY"; - stmt.executeUpdate("insert into TestTable1" + " (Col2, Col3) values('A', '" + row1 + "')"); - stmt.executeUpdate("insert into TestTable1" + " (Col2, Col3) values('B', '" + row2 + "')"); - - } - catch (Exception e) { - e.printStackTrace(); - } + stmt.executeUpdate("insert into TestTable1" + " (Col2, Col3) values('A', '" + row1 + "')"); + stmt.executeUpdate("insert into TestTable1" + " (Col2, Col3) values('B', '" + row2 + "')"); } } +/** + * Handles output for XML elements for the test. + */ class ExampleContentHandler implements ContentHandler { - public void startElement(String namespaceURI, - String localName, - String qName, - Attributes atts) throws SAXException { + public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException { System.out.println("startElement method: localName => " + localName); } - public void characters(char[] text, - int start, - int length) throws SAXException { + public void characters(char[] text, int start, int length) throws SAXException { System.out.println("characters method"); } - public void endElement(String namespaceURI, - String localName, - String qName) throws SAXException { + public void endElement(String namespaceURI, String localName, String qName) throws SAXException { System.out.println("endElement method: localName => " + localName); } @@ -296,8 +248,7 @@ public void endDocument() throws SAXException { System.out.println("endDocument method"); } - public void startPrefixMapping(String prefix, - String uri) throws SAXException { + public void startPrefixMapping(String prefix, String uri) throws SAXException { System.out.println("startPrefixMapping method: prefix => " + prefix); } @@ -309,14 +260,11 @@ public void skippedEntity(String name) throws SAXException { System.out.println("skippedEntity method: name => " + name); } - public void ignorableWhitespace(char[] text, - int start, - int length) throws SAXException { + public void ignorableWhitespace(char[] text, int start, int length) throws SAXException { System.out.println("ignorableWhiteSpace method"); } - public void processingInstruction(String target, - String data) throws SAXException { + public void processingInstruction(String target, String data) throws SAXException { System.out.println("processingInstruction method: target => " + target); } } diff --git a/src/samples/datatypes/src/main/java/basicDT.java b/src/samples/datatypes/src/main/java/basicDT.java deleted file mode 100644 index a0cf01cc8..000000000 --- a/src/samples/datatypes/src/main/java/basicDT.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ -package datatypes.src.main.java; - -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.sql.Connection; -import java.sql.Date; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.sql.Time; -import java.sql.Timestamp; - -import com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement; -import com.microsoft.sqlserver.jdbc.SQLServerResultSet; - -import microsoft.sql.DateTimeOffset; - -public class basicDT { - // Declare the JDBC objects. - private static Connection con = null; - private static Statement stmt = null; - private static ResultSet rs = null; - - private static String tableName = "DataTypesTable_JDBC_Sample"; - - public static void main(String[] args) { - - String serverName = null; - String portNumber = null; - String databaseName = null; - String username = null; - String password = null; - - try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) { - - System.out.print("Enter server name: "); - serverName = br.readLine(); - System.out.print("Enter port number: "); - portNumber = br.readLine(); - System.out.print("Enter database name: "); - databaseName = br.readLine(); - System.out.print("Enter username: "); - username = br.readLine(); - System.out.print("Enter password: "); - password = br.readLine(); - - // Create a variable for the connection string. - String connectionUrl = "jdbc:sqlserver://" + serverName + ":" + portNumber + ";" + "databaseName=" + databaseName + ";username=" - + username + ";password=" + password + ";"; - - // Establish the connection. - Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); - con = DriverManager.getConnection(connectionUrl); - - dropAndCreateTable(); - - insertOriginalData(); - - System.out.println(); - - // Create and execute an SQL statement that returns some data - // and display it. - String SQL = "SELECT * FROM " + tableName; - stmt = con.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); - rs = stmt.executeQuery(SQL); - rs.next(); - displayRow("ORIGINAL DATA", rs); - - // Update the data in the result set. - rs.updateInt(1, 200); - rs.updateString(2, "B"); - rs.updateString(3, "Some updated text."); - rs.updateBoolean(4, true); - rs.updateDouble(5, 77.89); - rs.updateDouble(6, 1000.01); - long timeInMillis = System.currentTimeMillis(); - Timestamp ts = new Timestamp(timeInMillis); - rs.updateTimestamp(7, ts); - rs.updateDate(8, new Date(timeInMillis)); - rs.updateTime(9, new Time(timeInMillis)); - rs.updateTimestamp(10, ts); - - // -480 indicates GMT - 8:00 hrs - ((SQLServerResultSet) rs).updateDateTimeOffset(11, DateTimeOffset.valueOf(ts, -480)); - - rs.updateRow(); - - // Get the updated data from the database and display it. - rs = stmt.executeQuery(SQL); - rs.next(); - displayRow("UPDATED DATA", rs); - } - - // Handle any errors that may have occurred. - catch (Exception e) { - e.printStackTrace(); - } - - finally { - if (rs != null) - try { - rs.close(); - } - catch (Exception e) { - } - - if (stmt != null) - try { - stmt.close(); - } - catch (Exception e) { - } - - if (con != null) - try { - con.close(); - } - catch (Exception e) { - } - } - } - - private static void displayRow(String title, - ResultSet rs) { - try { - System.out.println(title); - System.out.println(rs.getInt(1) + " , " + // SQL integer type. - rs.getString(2) + " , " + // SQL char type. - rs.getString(3) + " , " + // SQL varchar type. - rs.getBoolean(4) + " , " + // SQL bit type. - rs.getDouble(5) + " , " + // SQL decimal type. - rs.getDouble(6) + " , " + // SQL money type. - rs.getTimestamp(7) + " , " + // SQL datetime type. - rs.getDate(8) + " , " + // SQL date type. - rs.getTime(9) + " , " + // SQL time type. - rs.getTimestamp(10) + " , " + // SQL datetime2 type. - ((SQLServerResultSet) rs).getDateTimeOffset(11)); // SQL datetimeoffset type. - - System.out.println(); - } - catch (Exception e) { - e.printStackTrace(); - } - } - - private static void dropAndCreateTable() throws SQLException { - con.createStatement().executeUpdate("if object_id('" + tableName + "','U') is not null" + " drop table " + tableName); - - String sql = "create table " + tableName + " (" + "c1 int, " + "c2 char(20), " + "c3 varchar(20), " + "c4 bit, " + "c5 decimal(10,5), " - + "c6 money, " + "c7 datetime, " + "c8 date, " + "c9 time(7), " + "c10 datetime2(7), " + "c11 datetimeoffset(7), " + ");"; - - con.createStatement().execute(sql); - } - - private static void insertOriginalData() throws SQLException { - String sql = "insert into " + tableName + " values( " + "?,?,?,?,?,?,?,?,?,?,?" + ")"; - - SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con.prepareCall(sql); - - pstmt.setObject(1, 100); - pstmt.setObject(2, "origianl text"); - pstmt.setObject(3, "origianl text"); - pstmt.setObject(4, false); - pstmt.setObject(5, 12.34); - pstmt.setObject(6, 56.78); - pstmt.setObject(7, new java.util.Date(1453500034839L)); - pstmt.setObject(8, new java.util.Date(1453500034839L)); - pstmt.setObject(9, new java.util.Date(1453500034839L)); - pstmt.setObject(10, new java.util.Date(1453500034839L)); - pstmt.setObject(11, new java.util.Date(1453500034839L)); - - pstmt.execute(); - pstmt.close(); - } -} diff --git a/src/samples/resultsets/pom.xml b/src/samples/resultsets/pom.xml index d2f466b2e..a2960b72e 100644 --- a/src/samples/resultsets/pom.xml +++ b/src/samples/resultsets/pom.xml @@ -1,95 +1,82 @@ 4.0.0 - com.microsoft.sqlserver.jdbc resultsets 0.0.1 - jar - ${project.artifactId} https://github.com/Microsoft/mssql-jdbc/tree/master/src/samples - UTF-8 - com.microsoft.sqlserver mssql-jdbc - 6.4.0.jre9 + 7.0.0.jre10 - - cacheRS + CacheResultSet - cacheRS - + CacheResultSet org.codehaus.mojo exec-maven-plugin 1.2.1 - resultsets.src.main.java.cacheRS + resultsets.src.main.java.CacheResultSet - - retrieveRS + RetrieveResultSet - retrieveRS - + RetrieveResultSet org.codehaus.mojo exec-maven-plugin 1.2.1 - resultsets.src.main.java.retrieveRS + resultsets.src.main.java.RetrieveResultSet - - updateRS + UpdateResultSet - updateRS - + UpdateResultSet org.codehaus.mojo exec-maven-plugin 1.2.1 - resultsets.src.main.java.updateRS + resultsets.src.main.java.UpdateResultSet - org.apache.maven.plugins maven-compiler-plugin - 9 - 9 + 10 + 10 - org.apache.maven.plugins maven-resources-plugin @@ -97,5 +84,4 @@ - diff --git a/src/samples/resultsets/src/main/java/cacheRS.java b/src/samples/resultsets/src/main/java/CacheResultSet.java similarity index 53% rename from src/samples/resultsets/src/main/java/cacheRS.java rename to src/samples/resultsets/src/main/java/CacheResultSet.java index 8484fc348..06c6588f3 100644 --- a/src/samples/resultsets/src/main/java/cacheRS.java +++ b/src/samples/resultsets/src/main/java/CacheResultSet.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package resultsets.src.main.java; @@ -14,25 +11,31 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import java.util.ArrayList; import com.microsoft.sqlserver.jdbc.SQLServerResultSet; -public class cacheRS { +/** + * Sample application that demonstrates how to use a result set to retrieve a large set + * of data from a SQL Server database. + * + * In addition, it demonstrates how to control the amount of data that is fetched + * from the database and cached on the client. + */ +public class CacheResultSet { + + private static final int ROW_COUNT = 10000; + @SuppressWarnings("serial") public static void main(String[] args) { - // Declare the JDBC objects. - Connection con = null; - Statement stmt = null; - ResultSet rs = null; - String serverName = null; String portNumber = null; String databaseName = null; String username = null; String password = null; - try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) { + try (InputStreamReader in = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(in)) { System.out.print("Enter server name: "); serverName = br.readLine(); @@ -44,77 +47,46 @@ public static void main(String[] args) { username = br.readLine(); System.out.print("Enter password: "); password = br.readLine(); + System.out.println(); // Create a variable for the connection string. - String connectionUrl = "jdbc:sqlserver://" + serverName + ":" + portNumber + ";" + "databaseName=" + databaseName + ";username=" - + username + ";password=" + password + ";"; + String connectionUrl = "jdbc:sqlserver://" + serverName + ":" + portNumber + ";" + "databaseName=" + + databaseName + ";username=" + username + ";password=" + password + ";"; // Establish the connection. - Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); - con = DriverManager.getConnection(connectionUrl); - - createTable(con); - - // Create and execute an SQL statement that returns a large - // set of data and then display it. - String SQL = "SELECT * FROM SalesOrderDetail_JDBC_Sample;"; - stmt = con.createStatement(SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY, +SQLServerResultSet.CONCUR_READ_ONLY); - - // Perform a fetch for every row in the result set. - rs = stmt.executeQuery(SQL); - timerTest(1, rs); - rs.close(); - - // Perform a fetch for every 10th row in the result set. - rs = stmt.executeQuery(SQL); - timerTest(10, rs); - rs.close(); - - // Perform a fetch for every 100th row in the result set. - rs = stmt.executeQuery(SQL); - timerTest(100, rs); - rs.close(); - - // Perform a fetch for every 1000th row in the result set. - rs = stmt.executeQuery(SQL); - timerTest(1000, rs); - rs.close(); - - // Perform a fetch for every 128th row (the default) in the result set. - rs = stmt.executeQuery(SQL); - timerTest(0, rs); - rs.close(); + try (Connection con = DriverManager.getConnection(connectionUrl); Statement stmt = con.createStatement(); + Statement stmt1 = con.createStatement(SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY, + +SQLServerResultSet.CONCUR_READ_ONLY);) { + + createTable(stmt); + + // Create and execute an SQL statement that returns a large + // set of data and then display it. + String SQL = "SELECT * FROM SalesOrderDetail_JDBC_Sample;"; + + for (int n : new ArrayList() { + { + add(1); + add(10); + add(100); + add(1000); + add(0); + } + }) { + // Perform a fetch for every nth row in the result set. + try (ResultSet rs = stmt.executeQuery(SQL)) { + timerTest(n, rs); + } + } + } } - // Handle any errors that may have occurred. catch (Exception e) { e.printStackTrace(); } - - finally { - if (rs != null) - try { - rs.close(); - } - catch (Exception e) { - } - if (stmt != null) - try { - stmt.close(); - } - catch (Exception e) { - } - if (con != null) - try { - con.close(); - } - catch (Exception e) { - } - } } - private static void timerTest(int fetchSize, - ResultSet rs) { + private static void timerTest(int fetchSize, ResultSet rs) { try { // Declare the variables for tracking the row count and elapsed time. @@ -139,17 +111,14 @@ private static void timerTest(int fetchSize, System.out.println("TIME TO EXECUTE: " + runTime); System.out.println(); - } - catch (Exception e) { + } catch (Exception e) { e.printStackTrace(); } } - private static void createTable(Connection con) throws SQLException { - - Statement stmt = con.createStatement(); - - stmt.execute("if exists (select * from sys.objects where name = 'SalesOrderDetail_JDBC_Sample')" + "drop table SalesOrderDetail_JDBC_Sample"); + private static void createTable(Statement stmt) throws SQLException { + stmt.execute("if exists (select * from sys.objects where name = 'SalesOrderDetail_JDBC_Sample')" + + "drop table SalesOrderDetail_JDBC_Sample"); String sql = "CREATE TABLE [SalesOrderDetail_JDBC_Sample](" + "[SalesOrderID] [int] NOT NULL," + "[SalesOrderDetailID] [int] IDENTITY(1,1) NOT NULL," + "[CarrierTrackingNumber] [nvarchar](25) NULL," @@ -160,9 +129,9 @@ private static void createTable(Connection con) throws SQLException { stmt.execute(sql); - for (int i = 0; i < 10000; i++) { + for (int i = 0; i < ROW_COUNT; i++) { sql = "INSERT SalesOrderDetail_JDBC_Sample VALUES ('1','4911-403C-98','5','1','0','10.5555','0.00','5A74C7D2-E641-438E-A7AC-37BF23280301','2011-05-31 00:00:00.000') "; stmt.execute(sql); } } -} \ No newline at end of file +} diff --git a/src/samples/resultsets/src/main/java/retrieveRS.java b/src/samples/resultsets/src/main/java/RetrieveResultSet.java similarity index 52% rename from src/samples/resultsets/src/main/java/retrieveRS.java rename to src/samples/resultsets/src/main/java/RetrieveResultSet.java index f8b6e7b3b..ee1870fc0 100644 --- a/src/samples/resultsets/src/main/java/retrieveRS.java +++ b/src/samples/resultsets/src/main/java/RetrieveResultSet.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package resultsets.src.main.java; @@ -15,22 +12,21 @@ import java.sql.SQLException; import java.sql.Statement; -public class retrieveRS { +/** + * Sample application that demonstrates how to use a result set to retrieve a set of + * data from a SQL Server database. + */ +public class RetrieveResultSet { public static void main(String[] args) { - // Declare the JDBC objects. - Connection con = null; - Statement stmt = null; - ResultSet rs = null; - String serverName = null; String portNumber = null; String databaseName = null; String username = null; String password = null; - try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) { + try (InputStreamReader in = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(in)) { System.out.print("Enter server name: "); serverName = br.readLine(); @@ -42,65 +38,46 @@ public static void main(String[] args) { username = br.readLine(); System.out.print("Enter password: "); password = br.readLine(); + System.out.println(); // Create a variable for the connection string. - String connectionUrl = "jdbc:sqlserver://" + serverName + ":" + portNumber + ";" + "databaseName=" + databaseName + ";username=" - + username + ";password=" + password + ";"; + String connectionUrl = "jdbc:sqlserver://" + serverName + ":" + portNumber + ";" + "databaseName=" + + databaseName + ";username=" + username + ";password=" + password + ";"; // Establish the connection. - Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); - con = DriverManager.getConnection(connectionUrl); - - createTable(con); - - // Create and execute an SQL statement that returns a - // set of data and then display it. - String SQL = "SELECT * FROM Product_JDBC_Sample;"; - stmt = con.createStatement(); - rs = stmt.executeQuery(SQL); - displayRow("PRODUCTS", rs); + try (Connection con = DriverManager.getConnection(connectionUrl); Statement stmt = con.createStatement();) { + createTable(stmt); + + // Create and execute an SQL statement that returns a + // set of data and then display it. + String SQL = "SELECT * FROM Product_JDBC_Sample;"; + try (ResultSet rs = stmt.executeQuery(SQL)) { + displayRow("PRODUCTS", rs); + } + } } // Handle any errors that may have occurred. catch (Exception e) { e.printStackTrace(); } - - finally { - if (rs != null) - try { - rs.close(); - } - catch (Exception e) { - } - if (stmt != null) - try { - stmt.close(); - } - catch (Exception e) { - } - if (con != null) - try { - con.close(); - } - catch (Exception e) { - } - } } - private static void createTable(Connection con) throws SQLException { - Statement stmt = con.createStatement(); - - stmt.execute("if exists (select * from sys.objects where name = 'Product_JDBC_Sample')" + "drop table Product_JDBC_Sample"); + private static void createTable(Statement stmt) throws SQLException { + stmt.execute("if exists (select * from sys.objects where name = 'Product_JDBC_Sample')" + + "drop table Product_JDBC_Sample"); - String sql = "CREATE TABLE [Product_JDBC_Sample](" + "[ProductID] [int] IDENTITY(1,1) NOT NULL," + "[Name] [varchar](30) NOT NULL," - + "[ProductNumber] [nvarchar](25) NOT NULL," + "[MakeFlag] [bit] NOT NULL," + "[FinishedGoodsFlag] [bit] NOT NULL," - + "[Color] [nvarchar](15) NULL," + "[SafetyStockLevel] [smallint] NOT NULL," + "[ReorderPoint] [smallint] NOT NULL," + String sql = "CREATE TABLE [Product_JDBC_Sample](" + "[ProductID] [int] IDENTITY(1,1) NOT NULL," + + "[Name] [varchar](30) NOT NULL," + "[ProductNumber] [nvarchar](25) NOT NULL," + + "[MakeFlag] [bit] NOT NULL," + "[FinishedGoodsFlag] [bit] NOT NULL," + "[Color] [nvarchar](15) NULL," + + "[SafetyStockLevel] [smallint] NOT NULL," + "[ReorderPoint] [smallint] NOT NULL," + "[StandardCost] [money] NOT NULL," + "[ListPrice] [money] NOT NULL," + "[Size] [nvarchar](5) NULL," - + "[SizeUnitMeasureCode] [nchar](3) NULL," + "[WeightUnitMeasureCode] [nchar](3) NULL," + "[Weight] [decimal](8, 2) NULL," - + "[DaysToManufacture] [int] NOT NULL," + "[ProductLine] [nchar](2) NULL," + "[Class] [nchar](2) NULL," + "[Style] [nchar](2) NULL," - + "[ProductSubcategoryID] [int] NULL," + "[ProductModelID] [int] NULL," + "[SellStartDate] [datetime] NOT NULL," - + "[SellEndDate] [datetime] NULL," + "[DiscontinuedDate] [datetime] NULL," + "[rowguid] [uniqueidentifier] ROWGUIDCOL NOT NULL," + + "[SizeUnitMeasureCode] [nchar](3) NULL," + "[WeightUnitMeasureCode] [nchar](3) NULL," + + "[Weight] [decimal](8, 2) NULL," + "[DaysToManufacture] [int] NOT NULL," + + "[ProductLine] [nchar](2) NULL," + "[Class] [nchar](2) NULL," + "[Style] [nchar](2) NULL," + + "[ProductSubcategoryID] [int] NULL," + "[ProductModelID] [int] NULL," + + "[SellStartDate] [datetime] NOT NULL," + "[SellEndDate] [datetime] NULL," + + "[DiscontinuedDate] [datetime] NULL," + "[rowguid] [uniqueidentifier] ROWGUIDCOL NOT NULL," + "[ModifiedDate] [datetime] NOT NULL,)"; stmt.execute(sql); @@ -115,16 +92,14 @@ private static void createTable(Connection con) throws SQLException { stmt.execute(sql); } - private static void displayRow(String title, - ResultSet rs) { + private static void displayRow(String title, ResultSet rs) { try { System.out.println(title); while (rs.next()) { System.out.println(rs.getString("ProductNumber") + " : " + rs.getString("Name")); } - } - catch (Exception e) { + } catch (Exception e) { e.printStackTrace(); } } -} \ No newline at end of file +} diff --git a/src/samples/resultsets/src/main/java/UpdateResultSet.java b/src/samples/resultsets/src/main/java/UpdateResultSet.java new file mode 100644 index 000000000..90942e3b3 --- /dev/null +++ b/src/samples/resultsets/src/main/java/UpdateResultSet.java @@ -0,0 +1,117 @@ +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package resultsets.src.main.java; + +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +/** + * Sample application that demonstrates how to use an updateable result set to insert, + * update, and delete a row of data in a SQL Server database. + */ +public class UpdateResultSet { + + public static void main(String[] args) { + + String serverName = null; + String portNumber = null; + String databaseName = null; + String username = null; + String password = null; + + try (InputStreamReader in = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(in)) { + + System.out.print("Enter server name: "); + serverName = br.readLine(); + System.out.print("Enter port number: "); + portNumber = br.readLine(); + System.out.print("Enter database name: "); + databaseName = br.readLine(); + System.out.print("Enter username: "); + username = br.readLine(); + System.out.print("Enter password: "); + password = br.readLine(); + System.out.println(); + + // Create a variable for the connection string. + String connectionUrl = "jdbc:sqlserver://" + serverName + ":" + portNumber + ";" + "databaseName=" + + databaseName + ";username=" + username + ";password=" + password + ";"; + + // Establish the connection. + try (Connection con = DriverManager.getConnection(connectionUrl); Statement stmt = con.createStatement(); + Statement stmt1 = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, + ResultSet.CONCUR_UPDATABLE)) { + + createTable(stmt); + + // Create and execute an SQL statement, retrieving an updateable result set. + String SQL = "SELECT * FROM Department_JDBC_Sample;"; + + try (ResultSet rs = stmt.executeQuery(SQL)) { + + // Insert a row of data. + rs.moveToInsertRow(); + rs.updateString("Name", "Accounting"); + rs.updateString("GroupName", "Executive General and Administration"); + rs.updateString("ModifiedDate", "08/01/2006"); + rs.insertRow(); + } + + // Retrieve the inserted row of data and display it. + SQL = "SELECT * FROM Department_JDBC_Sample WHERE Name = 'Accounting';"; + try (ResultSet rs = stmt.executeQuery(SQL)) { + displayRow("ADDED ROW", rs); + + // Update the row of data. + rs.first(); + rs.updateString("GroupName", "Finance"); + rs.updateRow(); + } + // Retrieve the updated row of data and display it. + try (ResultSet rs = stmt.executeQuery(SQL)) { + displayRow("UPDATED ROW", rs); + + // Delete the row of data. + rs.first(); + rs.deleteRow(); + System.out.println("ROW DELETED"); + } + } + } + + // Handle any errors that may have occurred. + catch (Exception e) { + e.printStackTrace(); + } + } + + private static void createTable(Statement stmt) throws SQLException { + stmt.execute("if exists (select * from sys.objects where name = 'Department_JDBC_Sample')" + + "drop table Department_JDBC_Sample"); + + String sql = "CREATE TABLE [Department_JDBC_Sample](" + "[DepartmentID] [smallint] IDENTITY(1,1) NOT NULL," + + "[Name] [varchar](50) NOT NULL," + "[GroupName] [varchar](50) NOT NULL," + + "[ModifiedDate] [datetime] NOT NULL,)"; + + stmt.execute(sql); + } + + private static void displayRow(String title, ResultSet rs) { + try { + System.out.println(title); + while (rs.next()) { + System.out.println(rs.getString("Name") + " : " + rs.getString("GroupName")); + System.out.println(); + } + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/samples/resultsets/src/main/java/updateRS.java b/src/samples/resultsets/src/main/java/updateRS.java deleted file mode 100644 index 9b2fd1630..000000000 --- a/src/samples/resultsets/src/main/java/updateRS.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ -package resultsets.src.main.java; - -import java.io.BufferedReader; -import java.io.InputStreamReader; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -public class updateRS { - - public static void main(String[] args) { - - // Declare the JDBC objects. - Connection con = null; - Statement stmt = null; - ResultSet rs = null; - - String serverName = null; - String portNumber = null; - String databaseName = null; - String username = null; - String password = null; - - try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) { - - System.out.print("Enter server name: "); - serverName = br.readLine(); - System.out.print("Enter port number: "); - portNumber = br.readLine(); - System.out.print("Enter database name: "); - databaseName = br.readLine(); - System.out.print("Enter username: "); - username = br.readLine(); - System.out.print("Enter password: "); - password = br.readLine(); - - // Create a variable for the connection string. - String connectionUrl = "jdbc:sqlserver://" + serverName + ":" + portNumber + ";" + "databaseName=" + databaseName + ";username=" - + username + ";password=" + password + ";"; - - // Establish the connection. - Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); - con = DriverManager.getConnection(connectionUrl); - - createTable(con); - - // Create and execute an SQL statement, retrieving an updateable result set. - String SQL = "SELECT * FROM Department_JDBC_Sample;"; - stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); - rs = stmt.executeQuery(SQL); - - // Insert a row of data. - rs.moveToInsertRow(); - rs.updateString("Name", "Accounting"); - rs.updateString("GroupName", "Executive General and Administration"); - rs.updateString("ModifiedDate", "08/01/2006"); - rs.insertRow(); - - if (rs != null) { - rs.close(); - } - - // Retrieve the inserted row of data and display it. - SQL = "SELECT * FROM Department_JDBC_Sample WHERE Name = 'Accounting';"; - rs = stmt.executeQuery(SQL); - displayRow("ADDED ROW", rs); - - // Update the row of data. - rs.first(); - rs.updateString("GroupName", "Finance"); - rs.updateRow(); - - // Retrieve the updated row of data and display it. - rs = stmt.executeQuery(SQL); - displayRow("UPDATED ROW", rs); - - // Delete the row of data. - rs.first(); - rs.deleteRow(); - System.out.println("ROW DELETED"); - } - - // Handle any errors that may have occurred. - catch (Exception e) { - e.printStackTrace(); - } - - finally { - if (rs != null) - try { - rs.close(); - } - catch (Exception e) { - } - if (stmt != null) - try { - stmt.close(); - } - catch (Exception e) { - } - if (con != null) - try { - con.close(); - } - catch (Exception e) { - } - } - } - - private static void createTable(Connection con) throws SQLException { - Statement stmt = con.createStatement(); - - stmt.execute("if exists (select * from sys.objects where name = 'Department_JDBC_Sample')" + "drop table Department_JDBC_Sample"); - - String sql = "CREATE TABLE [Department_JDBC_Sample](" + "[DepartmentID] [smallint] IDENTITY(1,1) NOT NULL," + "[Name] [varchar](50) NOT NULL," - + "[GroupName] [varchar](50) NOT NULL," + "[ModifiedDate] [datetime] NOT NULL,)"; - - stmt.execute(sql); - } - - private static void displayRow(String title, - ResultSet rs) { - try { - System.out.println(title); - while (rs.next()) { - System.out.println(rs.getString("Name") + " : " + rs.getString("GroupName")); - System.out.println(); - } - } - catch (Exception e) { - e.printStackTrace(); - } - } -} \ No newline at end of file diff --git a/src/samples/sparse/pom.xml b/src/samples/sparse/pom.xml index fc45c69a4..4d557cf05 100644 --- a/src/samples/sparse/pom.xml +++ b/src/samples/sparse/pom.xml @@ -1,34 +1,27 @@ 4.0.0 - com.microsoft.sqlserver.jdbc sparse 0.0.1 - jar - ${project.artifactId} https://github.com/Microsoft/mssql-jdbc/tree/master/src/samples - UTF-8 - com.microsoft.sqlserver mssql-jdbc - 6.4.0.jre9 + 7.0.0.jre10 - SparseColumns SparseColumns - org.codehaus.mojo @@ -42,18 +35,16 @@ - org.apache.maven.plugins maven-compiler-plugin - 9 - 9 + 10 + 10 - org.apache.maven.plugins maven-resources-plugin @@ -61,5 +52,4 @@ - diff --git a/src/samples/sparse/src/main/java/SparseColumns.java b/src/samples/sparse/src/main/java/SparseColumns.java index 8e03a5ea0..71ae1564a 100644 --- a/src/samples/sparse/src/main/java/SparseColumns.java +++ b/src/samples/sparse/src/main/java/SparseColumns.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package sparse.src.main.java; @@ -25,22 +22,21 @@ import org.w3c.dom.NodeList; import org.xml.sax.InputSource; +/** + * Sample application that demonstrates how to detect column sets. It also shows a technique for + * parsing a column set's XML output, to get the data from the sparse columns. + */ public class SparseColumns { public static void main(String args[]) { - // Declare the JDBC objects. - Connection con = null; - Statement stmt = null; - ResultSet rs = null; - String serverName = null; String portNumber = null; String databaseName = null; String username = null; String password = null; - try (BufferedReader br = new BufferedReader(new InputStreamReader(System.in))) { + try (InputStreamReader in = new InputStreamReader(System.in); BufferedReader br = new BufferedReader(in)) { System.out.print("Enter server name: "); serverName = br.readLine(); @@ -54,115 +50,83 @@ public static void main(String args[]) { password = br.readLine(); // Create a variable for the connection string. - String connectionUrl = "jdbc:sqlserver://" + serverName + ":" + portNumber + ";" + "databaseName=" + databaseName + ";username=" - + username + ";password=" + password + ";"; + String connectionUrl = "jdbc:sqlserver://" + serverName + ":" + portNumber + ";" + "databaseName=" + + databaseName + ";username=" + username + ";password=" + password + ";"; - // Establish the connection. - Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); - con = DriverManager.getConnection(connectionUrl); + try (Connection con = DriverManager.getConnection(connectionUrl); Statement stmt = con.createStatement()) { - createColdCallingTable(con); + createColdCallingTable(stmt); - stmt = con.createStatement(); - // Determine the column set column - String columnSetColName = null; - String strCmd = "SELECT name FROM sys.columns WHERE object_id=(SELECT OBJECT_ID('ColdCalling')) AND is_column_set = 1"; - rs = stmt.executeQuery(strCmd); + // Determine the column set column + String columnSetColName = null; + String strCmd = "SELECT name FROM sys.columns WHERE object_id=(SELECT OBJECT_ID('ColdCalling')) AND is_column_set = 1"; - if (rs.next()) { - columnSetColName = rs.getString(1); - System.out.println(columnSetColName + " is the column set column!"); - } - rs.close(); - - rs = null; - - strCmd = "SELECT * FROM ColdCalling"; - rs = stmt.executeQuery(strCmd); - - // Iterate through the result set - ResultSetMetaData rsmd = rs.getMetaData(); - - DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); - DocumentBuilder db = dbf.newDocumentBuilder(); - InputSource is = new InputSource(); - while (rs.next()) { - // Iterate through the columns - for (int i = 1; i <= rsmd.getColumnCount(); ++i) { - String name = rsmd.getColumnName(i); - String value = rs.getString(i); - - // If this is the column set column - if (name.equalsIgnoreCase(columnSetColName)) { - System.out.println(name); - - // Instead of printing the raw XML, parse it - if (value != null) { - // Add artificial root node "sparse" to ensure XML is well formed - String xml = "" + value + ""; - - is.setCharacterStream(new StringReader(xml)); - Document doc = db.parse(is); - - // Extract the NodeList from the artificial root node that was added - NodeList list = doc.getChildNodes(); - Node root = list.item(0); // This is the node - NodeList sparseColumnList = root.getChildNodes(); // These are the xml column nodes - - // Iterate through the XML document - for (int n = 0; n < sparseColumnList.getLength(); ++n) { - Node sparseColumnNode = sparseColumnList.item(n); - String columnName = sparseColumnNode.getNodeName(); - // Note that the column value is not in the sparseColumNode, it is the value of the first child of it - Node sparseColumnValueNode = sparseColumnNode.getFirstChild(); - String columnValue = sparseColumnValueNode.getNodeValue(); - - System.out.println("\t" + columnName + "\t: " + columnValue); + try (ResultSet rs = stmt.executeQuery(strCmd)) { + if (rs.next()) { + columnSetColName = rs.getString(1); + System.out.println(columnSetColName + " is the column set column!"); + } + } + + strCmd = "SELECT * FROM ColdCalling"; + try (ResultSet rs = stmt.executeQuery(strCmd)) { + + // Iterate through the result set + ResultSetMetaData rsmd = rs.getMetaData(); + + DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); + DocumentBuilder db = dbf.newDocumentBuilder(); + InputSource is = new InputSource(); + while (rs.next()) { + // Iterate through the columns + for (int i = 1; i <= rsmd.getColumnCount(); ++i) { + String name = rsmd.getColumnName(i); + String value = rs.getString(i); + + // If this is the column set column + if (name.equalsIgnoreCase(columnSetColName)) { + System.out.println(name); + + // Instead of printing the raw XML, parse it + if (value != null) { + // Add artificial root node "sparse" to ensure XML is well formed + String xml = "" + value + ""; + + is.setCharacterStream(new StringReader(xml)); + Document doc = db.parse(is); + + // Extract the NodeList from the artificial root node that was added + NodeList list = doc.getChildNodes(); + Node root = list.item(0); // This is the node + NodeList sparseColumnList = root.getChildNodes(); // These are the xml column nodes + + // Iterate through the XML document + for (int n = 0; n < sparseColumnList.getLength(); ++n) { + Node sparseColumnNode = sparseColumnList.item(n); + String columnName = sparseColumnNode.getNodeName(); + // Note that the column value is not in the sparseColumNode, it is the value of + // the + // first child of it + Node sparseColumnValueNode = sparseColumnNode.getFirstChild(); + String columnValue = sparseColumnValueNode.getNodeValue(); + + System.out.println("\t" + columnName + "\t: " + columnValue); + } + } + } else { // Just print the name + value of non-sparse columns + System.out.println(name + "\t: " + value); } } - } - else { // Just print the name + value of non-sparse columns - System.out.println(name + "\t: " + value); + System.out.println();// New line between rows } } - System.out.println();// New line between rows } - } - catch (Exception e) { + } catch (Exception e) { e.printStackTrace(); } - finally { - if (rs != null) { - try { - rs.close(); - } - catch (Exception e) { - e.printStackTrace(); - } - } - if (stmt != null) { - try { - stmt.close(); - } - catch (Exception e) { - e.printStackTrace(); - } - } - if (con != null) { - try { - con.close(); - } - catch (Exception e) { - e.printStackTrace(); - } - } - } } - private static void createColdCallingTable(Connection con) throws SQLException { - - Statement stmt = con.createStatement(); - + private static void createColdCallingTable(Statement stmt) throws SQLException { stmt.execute("if exists (select * from sys.objects where name = 'ColdCalling')" + "drop table ColdCalling"); String sql = "CREATE TABLE ColdCalling ( ID int IDENTITY(1,1) PRIMARY KEY, [Date] date, [Time] time, PositiveFirstName nvarchar(50) SPARSE, PositiveLastName nvarchar(50) SPARSE, SpecialPurposeColumns XML COLUMN_SET FOR ALL_SPARSE_COLUMNS );"; 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 2bb77e477..42552b5ff 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java @@ -1,12 +1,12 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.AlwaysEncrypted; +import static org.junit.jupiter.api.Assertions.fail; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + import java.io.BufferedReader; import java.io.File; import java.io.FileReader; @@ -21,7 +21,6 @@ import java.util.LinkedList; import java.util.Properties; - import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.platform.runner.JUnitPlatform; @@ -43,13 +42,11 @@ import microsoft.sql.DateTimeOffset; -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) @@ -86,43 +83,43 @@ public class AESetup extends AbstractTest { * @throws TestAbortedException */ @BeforeAll - static void setUpConnection() throws TestAbortedException, Exception { + public static void setUpConnection() throws TestAbortedException, Exception { assumeTrue(13 <= new DBConnection(connectionString).getServerVersion(), TestResource.getResource("R_Incompat_SQLServerVersion")); String AETestConenctionString = connectionString + ";sendTimeAsDateTime=false"; readFromFile(javaKeyStoreInputFile, "Alias name"); - - try(SQLServerConnection con = (SQLServerConnection) DriverManager.getConnection(AETestConenctionString); - SQLServerStatement stmt = (SQLServerStatement) con.createStatement()) { - dropCEK(stmt); - dropCMK(stmt); + + try (SQLServerConnection con = (SQLServerConnection) DriverManager.getConnection(AETestConenctionString); + SQLServerStatement stmt = (SQLServerStatement) con.createStatement()) { + dropCEK(stmt); + dropCMK(stmt); } - + 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(AETestConenctionString, info); stmt = (SQLServerStatement) con.createStatement(); createCMK(keyStoreName, javaKeyAliases); - createCEK(storeProvider); + createCEK(storeProvider); } /** - * Dropping all CMKs and CEKs and any open resources. Technically, dropAll depends on the state of the class so it shouldn't be static, but the - * AfterAll annotation requires it to be static. + * Dropping all CMKs and CEKs and any open resources. Technically, dropAll depends on the state of the class so it + * shouldn't be static, but the AfterAll annotation requires it to be static. * * @throws SQLException */ @AfterAll - private static void dropAll() throws SQLException { + public static void dropAll() throws SQLException { dropTables(stmt); dropCEK(stmt); dropCMK(stmt); @@ -130,32 +127,31 @@ private static void dropAll() throws SQLException { } /** - * 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 */ - private static void readFromFile(String inputFile, - String lookupValue) throws IOException { + private static void readFromFile(String inputFile, String lookupValue) throws IOException { filePath = Utils.getCurrentClassPath(); try { File f = new File(filePath + inputFile); assumeTrue(f.exists(), TestResource.getResource("R_noKeyStore")); - try(BufferedReader buffer = new BufferedReader(new FileReader(f))) { - String readLine = ""; - String[] linecontents; - - while ((readLine = buffer.readLine()) != null) { - if (readLine.trim().contains(lookupValue)) { - linecontents = readLine.split(" "); - javaKeyAliases = linecontents[2]; - break; - } - } + try (BufferedReader buffer = new BufferedReader(new FileReader(f))) { + String readLine = ""; + String[] linecontents; + + while ((readLine = buffer.readLine()) != null) { + if (readLine.trim().contains(lookupValue)) { + linecontents = readLine.split(" "); + javaKeyAliases = linecontents[2]; + break; + } + } } - } - catch (IOException e) { + } catch (IOException e) { fail(e.toString()); } } @@ -201,8 +197,7 @@ protected static void createBinaryTable() throws SQLException { try { stmt.execute(sql); stmt.execute("DBCC FREEPROCCACHE"); - } - catch (SQLException e) { + } catch (SQLException e) { fail(e.toString()); } } @@ -272,8 +267,7 @@ protected static void createCharTable() throws SQLException { try { stmt.execute(sql); stmt.execute("DBCC FREEPROCCACHE"); - } - catch (SQLException e) { + } catch (SQLException e) { fail(e.toString()); } } @@ -325,8 +319,7 @@ protected void createDateTable() throws SQLException { try { stmt.execute(sql); stmt.execute("DBCC FREEPROCCACHE"); - } - catch (SQLException e) { + } catch (SQLException e) { fail(e.toString()); } } @@ -340,10 +333,10 @@ protected void createDatePrecisionTable(int scale) throws SQLException { String sql = "create table " + dateTable + " (" // 1 + "PlainDatetime2 datetime2(" + scale + ") null," + "RandomizedDatetime2 datetime2(" + scale - + ") ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + cekName - + ") NULL," + "DeterministicDatetime2 datetime2(" + scale - + ") ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + cekName - + ") NULL," + + ") ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + "DeterministicDatetime2 datetime2(" + scale + + ") ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," // 4 + "PlainDatetime2Default datetime2 null," @@ -368,25 +361,25 @@ protected void createDatePrecisionTable(int scale) throws SQLException { // 13 + "PlainTime time(" + scale + ") null," + "RandomizedTime time(" + scale - + ") ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + cekName - + ") NULL," + "DeterministicTime time(" + scale - + ") ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + cekName - + ") NULL," + + ") ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + "DeterministicTime time(" + scale + + ") ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," // 16 - + "PlainDatetimeoffset datetimeoffset(" + scale + ") null," + "RandomizedDatetimeoffset datetimeoffset(" + scale - + ") ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + cekName - + ") NULL," + "DeterministicDatetimeoffset datetimeoffset(" + scale - + ") ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + cekName - + ") NULL," + + "PlainDatetimeoffset datetimeoffset(" + scale + ") null," + "RandomizedDatetimeoffset datetimeoffset(" + + scale + + ") ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + "DeterministicDatetimeoffset datetimeoffset(" + scale + + ") 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) { + } catch (SQLException e) { fail(e.toString()); } } @@ -422,8 +415,7 @@ protected static void createDateScaleTable() throws SQLException { try { stmt.execute(sql); stmt.execute("DBCC FREEPROCCACHE"); - } - catch (SQLException e) { + } catch (SQLException e) { fail(e.toString()); } } @@ -535,8 +527,7 @@ protected static void createNumericTable() throws SQLException { try { stmt.execute(sql); stmt.execute("DBCC FREEPROCCACHE"); - } - catch (SQLException e) { + } catch (SQLException e) { fail(e.toString()); } } @@ -546,35 +537,34 @@ protected static void createNumericTable() throws SQLException { * * @throws SQLException */ - protected void createNumericPrecisionTable(int floatPrecision, - int precision, - int scale) throws SQLException { - String sql = "create table " + numericTable + " (" + "PlainFloat float(" + floatPrecision + ") null," + "RandomizedFloat float(" - + floatPrecision - + ") ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + cekName - + ") NULL," + "DeterministicFloat float(" + floatPrecision - + ") ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + cekName - + ") NULL," - - + "PlainDecimal decimal(" + precision + "," + scale + ") null," + "RandomizedDecimal decimal(" + precision + "," + scale - + ") ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + cekName - + ") NULL," + "DeterministicDecimal decimal(" + precision + "," + scale - + ") ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + cekName - + ") NULL," - - + "PlainNumeric numeric(" + precision + "," + scale + ") null," + "RandomizedNumeric numeric(" + precision + "," + scale - + ") ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + cekName - + ") NULL," + "DeterministicNumeric numeric(" + precision + "," + scale - + ") ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + cekName - + ") NULL" + protected void createNumericPrecisionTable(int floatPrecision, int precision, int scale) throws SQLException { + String sql = "create table " + numericTable + " (" + "PlainFloat float(" + floatPrecision + ") null," + + "RandomizedFloat float(" + floatPrecision + + ") ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + "DeterministicFloat float(" + floatPrecision + + ") ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainDecimal decimal(" + precision + "," + scale + ") null," + "RandomizedDecimal decimal(" + + precision + "," + scale + + ") ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + "DeterministicDecimal decimal(" + precision + "," + scale + + ") ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + + + "PlainNumeric numeric(" + precision + "," + scale + ") null," + "RandomizedNumeric numeric(" + + precision + "," + scale + + ") ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + + cekName + ") NULL," + "DeterministicNumeric numeric(" + precision + "," + scale + + ") 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) { + } catch (SQLException e) { fail(e.toString()); } } @@ -622,7 +612,8 @@ protected static String[] createCharValues(boolean nullable) { 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}; + String[] values = {char20.trim(), varchar50, varcharmax, nchar30, nvarchar60, nvarcharmax, uid, varchar8000, + nvarchar4000}; return values; } @@ -651,9 +642,10 @@ protected static String[] createNumericValues(boolean 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}; + String[] numericValues = {"" + boolValue, "" + tinyIntValue, "" + smallIntValue, "" + intValue, + "" + bigintValue, "" + floatValue, "" + floatValuewithPrecision, "" + realValue, "" + decimal, + "" + decimalPrecisionScale, "" + numeric, "" + numericPrecisionScale, "" + smallMoney, "" + money, + "" + decimalPrecisionScale2, "" + numericPrecisionScale2}; return numericValues; } @@ -690,10 +682,10 @@ protected static LinkedList createTemporalTypes(boolean nullable) { * @param keyPath * @throws SQLException */ - private static void createCMK(String keyStoreName, - String keyPath) throws SQLException { - String sql = " if not exists (SELECT name from sys.column_master_keys where name='" + cmkName + "')" + " begin" + " CREATE COLUMN MASTER KEY " - + cmkName + " WITH (KEY_STORE_PROVIDER_NAME = '" + keyStoreName + "', KEY_PATH = '" + keyPath + "')" + " end"; + private static void createCMK(String keyStoreName, String keyPath) throws SQLException { + String sql = " if not exists (SELECT name from sys.column_master_keys where name='" + cmkName + "')" + " begin" + + " CREATE COLUMN MASTER KEY " + cmkName + " WITH (KEY_STORE_PROVIDER_NAME = '" + keyStoreName + + "', KEY_PATH = '" + keyPath + "')" + " end"; stmt.execute(sql); } @@ -733,61 +725,58 @@ protected static void dropTables(SQLServerStatement statement) throws SQLExcepti * @throws SQLException */ protected static void populateBinaryNormalCase(LinkedList byteValues) throws SQLException { - String sql = "insert into " + binaryTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; - - try(SQLServerPreparedStatement 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)); - } - } - - // 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(); + String sql = "insert into " + binaryTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + + ")"; + + try (SQLServerPreparedStatement 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)); + } + } + + // 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(); } } @@ -798,61 +787,58 @@ protected static void populateBinaryNormalCase(LinkedList byteValues) th * @throws SQLException */ protected static void populateBinarySetObject(LinkedList byteValues) throws SQLException { - String sql = "insert into " + binaryTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; - - try(SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting)) { - - // binary(20) - for (int i = 1; i <= 3; i++) { - if (null == byteValues) { - pstmt.setObject(i, null, java.sql.Types.BINARY); - } - else { - pstmt.setObject(i, byteValues.get(0)); - } - } - - // 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(); + String sql = "insert into " + binaryTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + + ")"; + + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, + stmtColEncSetting)) { + + // binary(20) + for (int i = 1; i <= 3; i++) { + if (null == byteValues) { + pstmt.setObject(i, null, java.sql.Types.BINARY); + } else { + pstmt.setObject(i, byteValues.get(0)); + } + } + + // 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(); } } @@ -863,61 +849,58 @@ protected static void populateBinarySetObject(LinkedList byteValues) thr * @throws SQLException */ protected static void populateBinarySetObjectWithJDBCType(LinkedList byteValues) throws SQLException { - String sql = "insert into " + binaryTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; - - try(SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting)) { - - // 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); - } - } - - // 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); - } - } - - // 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(); + String sql = "insert into " + binaryTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + + ")"; + + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, + stmtColEncSetting)) { + + // 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); + } + } + + // 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); + } + } + + // 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(); } } @@ -927,31 +910,33 @@ protected static void populateBinarySetObjectWithJDBCType(LinkedList byt * @throws SQLException */ protected static void populateBinaryNullCase() throws SQLException { - String sql = "insert into " + binaryTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; - - try(SQLServerPreparedStatement 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(); + String sql = "insert into " + binaryTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + + ")"; + + try (SQLServerPreparedStatement 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(); } } @@ -962,62 +947,62 @@ protected static void populateBinaryNullCase() throws SQLException { * @throws SQLException */ protected static void populateCharNormalCase(String[] charValues) throws SQLException { - String sql = "insert into " + charTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," - + "?,?,?" + ")"; + String sql = "insert into " + charTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; + + try (SQLServerPreparedStatement 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); + } + } - try(SQLServerPreparedStatement 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(); + // 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(); } } @@ -1028,57 +1013,58 @@ protected static void populateCharNormalCase(String[] charValues) throws SQLExce * @throws SQLException */ protected static void populateCharSetObject(String[] charValues) throws SQLException { - String sql = "insert into " + charTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," - + "?,?,?" + ")"; + String sql = "insert into " + charTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; + + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, + stmtColEncSetting)) { - try(SQLServerPreparedStatement 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(); + // 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(); } } @@ -1089,57 +1075,58 @@ protected static void populateCharSetObject(String[] charValues) throws SQLExcep * @throws SQLException */ protected static void populateCharSetObjectWithJDBCTypes(String[] charValues) throws SQLException { - String sql = "insert into " + charTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," - + "?,?,?" + ")"; + String sql = "insert into " + charTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; + + try (SQLServerPreparedStatement 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); + } - try(SQLServerPreparedStatement 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(); + // vnarchar4000 + for (int i = 25; i <= 27; i++) { + pstmt.setObject(i, charValues[8], JDBCType.NVARCHAR); + } + + pstmt.execute(); } } @@ -1149,48 +1136,49 @@ protected static void populateCharSetObjectWithJDBCTypes(String[] charValues) th * @throws SQLException */ protected static void populateCharNullCase() throws SQLException { - String sql = "insert into " + charTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," - + "?,?,?" + ")"; + String sql = "insert into " + charTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; + + try (SQLServerPreparedStatement 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); + } - try(SQLServerPreparedStatement 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(); + // 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(); } } @@ -1201,41 +1189,43 @@ protected static void populateCharNullCase() throws SQLException { * @throws SQLException */ protected static void populateDateNormalCase(LinkedList dateValues) throws SQLException { - String sql = "insert into " + dateTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; - - try(SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting)) { - - // date - for (int i = 1; i <= 3; i++) { - pstmt.setDate(i, (Date) dateValues.get(0)); - } - - // datetime2 default - for (int i = 4; i <= 6; i++) { - pstmt.setTimestamp(i, (Timestamp) dateValues.get(1)); - } - - // datetimeoffset default - for (int i = 7; i <= 9; i++) { - pstmt.setDateTimeOffset(i, (DateTimeOffset) dateValues.get(2)); - } - - // time default - for (int i = 10; i <= 12; i++) { - pstmt.setTime(i, (Time) dateValues.get(3)); - } - - // datetime - for (int i = 13; i <= 15; i++) { - pstmt.setDateTime(i, (Timestamp) dateValues.get(4)); - } - - // smalldatetime - for (int i = 16; i <= 18; i++) { - pstmt.setSmallDateTime(i, (Timestamp) dateValues.get(5)); - } - - pstmt.execute(); + String sql = "insert into " + dateTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?" + ")"; + + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, + stmtColEncSetting)) { + + // date + for (int i = 1; i <= 3; i++) { + pstmt.setDate(i, (Date) dateValues.get(0)); + } + + // datetime2 default + for (int i = 4; i <= 6; i++) { + pstmt.setTimestamp(i, (Timestamp) dateValues.get(1)); + } + + // datetimeoffset default + for (int i = 7; i <= 9; i++) { + pstmt.setDateTimeOffset(i, (DateTimeOffset) dateValues.get(2)); + } + + // time default + for (int i = 10; i <= 12; i++) { + pstmt.setTime(i, (Time) dateValues.get(3)); + } + + // datetime + for (int i = 13; i <= 15; i++) { + pstmt.setDateTime(i, (Timestamp) dateValues.get(4)); + } + + // smalldatetime + for (int i = 16; i <= 18; i++) { + pstmt.setSmallDateTime(i, (Timestamp) dateValues.get(5)); + } + + pstmt.execute(); } } @@ -1248,24 +1238,25 @@ protected static void populateDateNormalCase(LinkedList dateValues) thro protected static void populateDateScaleNormalCase(LinkedList dateValues) throws SQLException { String sql = "insert into " + scaleDateTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?" + ")"; - try(SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting)) { - - // datetime2(2) - for (int i = 1; i <= 3; i++) { - pstmt.setTimestamp(i, (Timestamp) dateValues.get(4), 2); - } - - // time(2) - for (int i = 4; i <= 6; i++) { - pstmt.setTime(i, (Time) dateValues.get(5), 2); - } - - // datetimeoffset(2) - for (int i = 7; i <= 9; i++) { - pstmt.setDateTimeOffset(i, (DateTimeOffset) dateValues.get(6), 2); - } - - pstmt.execute(); + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, + stmtColEncSetting)) { + + // datetime2(2) + for (int i = 1; i <= 3; i++) { + pstmt.setTimestamp(i, (Timestamp) dateValues.get(4), 2); + } + + // time(2) + for (int i = 4; i <= 6; i++) { + pstmt.setTime(i, (Time) dateValues.get(5), 2); + } + + // datetimeoffset(2) + for (int i = 7; i <= 9; i++) { + pstmt.setDateTimeOffset(i, (DateTimeOffset) dateValues.get(6), 2); + } + + pstmt.execute(); } } @@ -1276,67 +1267,68 @@ protected static void populateDateScaleNormalCase(LinkedList dateValues) * @param setter * @throws SQLException */ - protected static void populateDateSetObject(LinkedList dateValues, - String setter) throws SQLException { + protected static void populateDateSetObject(LinkedList dateValues, String setter) throws SQLException { if (setter.equalsIgnoreCase("setwithJDBCType")) { skipTestForJava7(); } - String sql = "insert into " + dateTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; - - try(SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting)) { - - // date - for (int i = 1; i <= 3; i++) { - if (setter.equalsIgnoreCase("setwithJavaType")) - pstmt.setObject(i, (Date) dateValues.get(0), java.sql.Types.DATE); - else if (setter.equalsIgnoreCase("setwithJDBCType")) - pstmt.setObject(i, (Date) dateValues.get(0), JDBCType.DATE); - else - pstmt.setObject(i, (Date) dateValues.get(0)); - } - - // datetime2 default - for (int i = 4; i <= 6; i++) { - if (setter.equalsIgnoreCase("setwithJavaType")) - pstmt.setObject(i, (Timestamp) dateValues.get(1), java.sql.Types.TIMESTAMP); - else if (setter.equalsIgnoreCase("setwithJDBCType")) - pstmt.setObject(i, (Timestamp) dateValues.get(1), JDBCType.TIMESTAMP); - else - pstmt.setObject(i, (Timestamp) dateValues.get(1)); - } - - // datetimeoffset default - for (int i = 7; i <= 9; i++) { - if (setter.equalsIgnoreCase("setwithJavaType")) - pstmt.setObject(i, (DateTimeOffset) dateValues.get(2), microsoft.sql.Types.DATETIMEOFFSET); - else if (setter.equalsIgnoreCase("setwithJDBCType")) - pstmt.setObject(i, (DateTimeOffset) dateValues.get(2), microsoft.sql.Types.DATETIMEOFFSET); - else - pstmt.setObject(i, (DateTimeOffset) dateValues.get(2)); - } - - // time default - for (int i = 10; i <= 12; i++) { - if (setter.equalsIgnoreCase("setwithJavaType")) - pstmt.setObject(i, (Time) dateValues.get(3), java.sql.Types.TIME); - else if (setter.equalsIgnoreCase("setwithJDBCType")) - pstmt.setObject(i, (Time) dateValues.get(3), JDBCType.TIME); - else - pstmt.setObject(i, (Time) dateValues.get(3)); - } - - // datetime - for (int i = 13; i <= 15; i++) { - pstmt.setObject(i, (Timestamp) dateValues.get(4), microsoft.sql.Types.DATETIME); - } - - // smalldatetime - for (int i = 16; i <= 18; i++) { - pstmt.setObject(i, (Timestamp) dateValues.get(5), microsoft.sql.Types.SMALLDATETIME); - } - - pstmt.execute(); + String sql = "insert into " + dateTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?" + ")"; + + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, + stmtColEncSetting)) { + + // date + for (int i = 1; i <= 3; i++) { + if (setter.equalsIgnoreCase("setwithJavaType")) + pstmt.setObject(i, (Date) dateValues.get(0), java.sql.Types.DATE); + else if (setter.equalsIgnoreCase("setwithJDBCType")) + pstmt.setObject(i, (Date) dateValues.get(0), JDBCType.DATE); + else + pstmt.setObject(i, (Date) dateValues.get(0)); + } + + // datetime2 default + for (int i = 4; i <= 6; i++) { + if (setter.equalsIgnoreCase("setwithJavaType")) + pstmt.setObject(i, (Timestamp) dateValues.get(1), java.sql.Types.TIMESTAMP); + else if (setter.equalsIgnoreCase("setwithJDBCType")) + pstmt.setObject(i, (Timestamp) dateValues.get(1), JDBCType.TIMESTAMP); + else + pstmt.setObject(i, (Timestamp) dateValues.get(1)); + } + + // datetimeoffset default + for (int i = 7; i <= 9; i++) { + if (setter.equalsIgnoreCase("setwithJavaType")) + pstmt.setObject(i, (DateTimeOffset) dateValues.get(2), microsoft.sql.Types.DATETIMEOFFSET); + else if (setter.equalsIgnoreCase("setwithJDBCType")) + pstmt.setObject(i, (DateTimeOffset) dateValues.get(2), microsoft.sql.Types.DATETIMEOFFSET); + else + pstmt.setObject(i, (DateTimeOffset) dateValues.get(2)); + } + + // time default + for (int i = 10; i <= 12; i++) { + if (setter.equalsIgnoreCase("setwithJavaType")) + pstmt.setObject(i, (Time) dateValues.get(3), java.sql.Types.TIME); + else if (setter.equalsIgnoreCase("setwithJDBCType")) + pstmt.setObject(i, (Time) dateValues.get(3), JDBCType.TIME); + else + pstmt.setObject(i, (Time) dateValues.get(3)); + } + + // datetime + for (int i = 13; i <= 15; i++) { + pstmt.setObject(i, (Timestamp) dateValues.get(4), microsoft.sql.Types.DATETIME); + } + + // smalldatetime + for (int i = 16; i <= 18; i++) { + pstmt.setObject(i, (Timestamp) dateValues.get(5), microsoft.sql.Types.SMALLDATETIME); + } + + pstmt.execute(); } } @@ -1346,41 +1338,43 @@ else if (setter.equalsIgnoreCase("setwithJDBCType")) * @throws SQLException */ protected void populateDateSetObjectNull() throws SQLException { - String sql = "insert into " + dateTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; - - try(SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting)) { - - // date - for (int i = 1; i <= 3; i++) { - pstmt.setObject(i, null, java.sql.Types.DATE); - } - - // datetime2 default - for (int i = 4; i <= 6; i++) { - pstmt.setObject(i, null, java.sql.Types.TIMESTAMP); - } - - // datetimeoffset default - for (int i = 7; i <= 9; i++) { - pstmt.setObject(i, null, microsoft.sql.Types.DATETIMEOFFSET); - } - - // time default - for (int i = 10; i <= 12; i++) { - pstmt.setObject(i, null, java.sql.Types.TIME); - } - - // datetime - for (int i = 13; i <= 15; i++) { - pstmt.setObject(i, null, microsoft.sql.Types.DATETIME); - } - - // smalldatetime - for (int i = 16; i <= 18; i++) { - pstmt.setObject(i, null, microsoft.sql.Types.SMALLDATETIME); - } - - pstmt.execute(); + String sql = "insert into " + dateTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?" + ")"; + + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, + stmtColEncSetting)) { + + // date + for (int i = 1; i <= 3; i++) { + pstmt.setObject(i, null, java.sql.Types.DATE); + } + + // datetime2 default + for (int i = 4; i <= 6; i++) { + pstmt.setObject(i, null, java.sql.Types.TIMESTAMP); + } + + // datetimeoffset default + for (int i = 7; i <= 9; i++) { + pstmt.setObject(i, null, microsoft.sql.Types.DATETIMEOFFSET); + } + + // time default + for (int i = 10; i <= 12; i++) { + pstmt.setObject(i, null, java.sql.Types.TIME); + } + + // datetime + for (int i = 13; i <= 15; i++) { + pstmt.setObject(i, null, microsoft.sql.Types.DATETIME); + } + + // smalldatetime + for (int i = 16; i <= 18; i++) { + pstmt.setObject(i, null, microsoft.sql.Types.SMALLDATETIME); + } + + pstmt.execute(); } } @@ -1390,41 +1384,43 @@ protected void populateDateSetObjectNull() throws SQLException { * @throws SQLException */ protected static void populateDateNullCase() throws SQLException { - String sql = "insert into " + dateTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; - - try(SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting)) { - - // date - for (int i = 1; i <= 3; i++) { - pstmt.setNull(i, java.sql.Types.DATE); - } - - // datetime2 default - for (int i = 4; i <= 6; i++) { - pstmt.setNull(i, java.sql.Types.TIMESTAMP); - } - - // datetimeoffset default - for (int i = 7; i <= 9; i++) { - pstmt.setNull(i, microsoft.sql.Types.DATETIMEOFFSET); - } - - // time default - for (int i = 10; i <= 12; i++) { - pstmt.setNull(i, java.sql.Types.TIME); - } - - // datetime - for (int i = 13; i <= 15; i++) { - pstmt.setNull(i, microsoft.sql.Types.DATETIME); - } - - // smalldatetime - for (int i = 16; i <= 18; i++) { - pstmt.setNull(i, microsoft.sql.Types.SMALLDATETIME); - } - - pstmt.execute(); + String sql = "insert into " + dateTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?" + ")"; + + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, + stmtColEncSetting)) { + + // date + for (int i = 1; i <= 3; i++) { + pstmt.setNull(i, java.sql.Types.DATE); + } + + // datetime2 default + for (int i = 4; i <= 6; i++) { + pstmt.setNull(i, java.sql.Types.TIMESTAMP); + } + + // datetimeoffset default + for (int i = 7; i <= 9; i++) { + pstmt.setNull(i, microsoft.sql.Types.DATETIMEOFFSET); + } + + // time default + for (int i = 10; i <= 12; i++) { + pstmt.setNull(i, java.sql.Types.TIME); + } + + // datetime + for (int i = 13; i <= 15; i++) { + pstmt.setNull(i, microsoft.sql.Types.DATETIME); + } + + // smalldatetime + for (int i = 16; i <= 18; i++) { + pstmt.setNull(i, microsoft.sql.Types.SMALLDATETIME); + } + + pstmt.execute(); } } @@ -1435,103 +1431,104 @@ protected static void populateDateNullCase() throws SQLException { * @throws SQLException */ protected static void populateNumeric(String[] values) throws SQLException { - String sql = "insert into " + numericTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," - + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; - - try(SQLServerPreparedStatement 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(); + String sql = "insert into " + numericTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?," + "?,?,?" + ")"; + + try (SQLServerPreparedStatement 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(); } } @@ -1542,103 +1539,104 @@ protected static void populateNumeric(String[] values) throws SQLException { * @throws SQLException */ protected static void populateNumericSetObject(String[] values) throws SQLException { - String sql = "insert into " + numericTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," - + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; - - try(SQLServerPreparedStatement 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(); + String sql = "insert into " + numericTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?," + "?,?,?" + ")"; + + try (SQLServerPreparedStatement 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(); } } @@ -1649,103 +1647,104 @@ protected static void populateNumericSetObject(String[] values) throws SQLExcept * @throws SQLException */ protected static void populateNumericSetObjectWithJDBCTypes(String[] values) throws SQLException { - String sql = "insert into " + numericTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," - + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; - - try(SQLServerPreparedStatement 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(); + String sql = "insert into " + numericTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?," + "?,?,?" + ")"; + + try (SQLServerPreparedStatement 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(); } } @@ -1755,92 +1754,94 @@ protected static void populateNumericSetObjectWithJDBCTypes(String[] values) thr * @throws SQLException */ protected static void populateNumericSetObjectNull() throws SQLException { - String sql = "insert into " + numericTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," - + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; - - try(SQLServerPreparedStatement 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(); + String sql = "insert into " + numericTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?," + "?,?,?" + ")"; + + try (SQLServerPreparedStatement 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(); } } @@ -1851,93 +1852,95 @@ protected static void populateNumericSetObjectNull() throws SQLException { * @throws SQLException */ protected static void populateNumericNullCase(String[] values) throws SQLException { - String sql = "insert into " + numericTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," - + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + String sql = "insert into " + numericTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?," + "?,?,?" + ")"; - try(SQLServerPreparedStatement 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(); + try (SQLServerPreparedStatement 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(); } } @@ -1948,109 +1951,108 @@ protected static void populateNumericNullCase(String[] values) throws SQLExcepti * @throws SQLException */ protected static void populateNumericNormalCase(String[] numericValues) throws SQLException { - String sql = "insert into " + numericTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," - + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + String sql = "insert into " + numericTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?," + "?,?,?" + ")"; - try(SQLServerPreparedStatement 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(); + try (SQLServerPreparedStatement 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(); } } @@ -2060,8 +2062,8 @@ protected static void populateNumericNormalCase(String[] numericValues) throws S * @throws SQLException */ private static void dropCEK(SQLServerStatement stmt) throws SQLException { - String cekSql = " if exists (SELECT name from sys.column_encryption_keys where name='" + cekName + "')" + " begin" - + " drop column encryption key " + cekName + " end"; + String cekSql = " if exists (SELECT name from sys.column_encryption_keys where name='" + cekName + "')" + + " begin" + " drop column encryption key " + cekName + " end"; stmt.execute(cekSql); } @@ -2071,8 +2073,8 @@ private static void dropCEK(SQLServerStatement stmt) throws SQLException { * @throws SQLException */ private static void dropCMK(SQLServerStatement stmt) throws SQLException { - String cekSql = " if exists (SELECT name from sys.column_master_keys where name='" + cmkName + "')" + " begin" + " drop column master key " - + cmkName + " end"; + String cekSql = " if exists (SELECT name from sys.column_master_keys where name='" + cmkName + "')" + " begin" + + " drop column master key " + cmkName + " end"; stmt.execute(cekSql); } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/CallableStatementTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/CallableStatementTest.java index 8ab4ec012..815e7486e 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/CallableStatementTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/CallableStatementTest.java @@ -1,21 +1,12 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.AlwaysEncrypted; -import static org.junit.jupiter.api.Assertions.fail; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertEquals; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.platform.runner.JUnitPlatform; -import org.junit.runner.RunWith; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; import java.math.BigDecimal; import java.sql.Date; @@ -25,6 +16,12 @@ import java.sql.Timestamp; import java.util.LinkedList; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.platform.runner.JUnitPlatform; +import org.junit.runner.RunWith; + import com.microsoft.sqlserver.jdbc.SQLServerCallableStatement; import com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement; import com.microsoft.sqlserver.jdbc.SQLServerResultSet; @@ -35,6 +32,7 @@ import microsoft.sql.DateTimeOffset; + /** * Test cases related to SQLServerCallableStatement. * @@ -81,7 +79,8 @@ public class CallableStatementTest extends AESetup { private static boolean nullable = false; /** - * Initialize the tables for this class. This method will execute AFTER the parent class (AESetup) finishes initializing. + * Initialize the tables for this class. This method will execute AFTER the parent class (AESetup) finishes + * initializing. * * @throws SQLException */ @@ -112,7 +111,7 @@ public static void initCallableStatementTest() throws SQLException { } @AfterAll - private static void dropAll() throws SQLException { + public static void dropAll() throws SQLException { dropTables(); } @@ -193,7 +192,8 @@ public void testUnencryptedIOParams() throws SQLException { public void testVariousIOParams() throws SQLException { createMixedProcedureNumericPrcisionScale(); testMixedProcedureNumericPrcisionScaleInorder("{call " + mixedProcedureNumericPrcisionScale + "(?,?,?,?)}"); - testMixedProcedureNumericPrcisionScaleParameterName("{call " + mixedProcedureNumericPrcisionScale + "(?,?,?,?)}"); + testMixedProcedureNumericPrcisionScaleParameterName( + "{call " + mixedProcedureNumericPrcisionScale + "(?,?,?,?)}"); } @Test @@ -207,7 +207,8 @@ public void testOutputProcedureChar() throws SQLException { public void testOutputProcedureNumeric() throws SQLException { createOutputProcedureNumeric(); testOutputProcedureNumericInorder("{call " + outputProcedureNumeric + "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)}"); - testcoerctionsOutputProcedureNumericInorder("{call " + outputProcedureNumeric + "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)}"); + testcoerctionsOutputProcedureNumericInorder( + "{call " + outputProcedureNumeric + "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)}"); } @Test @@ -282,8 +283,7 @@ private static void createTables() throws SQLException { try { stmt.execute(sql); - } - catch (SQLException e) { + } catch (SQLException e) { fail(e.toString()); } @@ -303,8 +303,7 @@ private static void createTables() throws SQLException { try { stmt.execute(sql); - } - catch (SQLException e) { + } catch (SQLException e) { fail(e.toString()); } @@ -414,8 +413,7 @@ private static void createTables() throws SQLException { try { stmt.execute(sql); - } - catch (SQLException e) { + } catch (SQLException e) { fail(e.toString()); } @@ -427,8 +425,7 @@ private static void createTables() throws SQLException { try { stmt.execute(sql); - } - catch (SQLException e) { + } catch (SQLException e) { fail(e.toString()); } @@ -442,8 +439,7 @@ private static void createTables() throws SQLException { try { stmt.execute(sql); - } - catch (SQLException e) { + } catch (SQLException e) { fail(e.toString()); } @@ -457,8 +453,7 @@ private static void createTables() throws SQLException { try { stmt.execute(sql); - } - catch (SQLException e) { + } catch (SQLException e) { fail(e.toString()); } } @@ -466,119 +461,121 @@ private static void createTables() throws SQLException { private static void populateTable4() throws SQLException { String sql = "insert into " + table4 + " values( " + "?,?,?" + ")"; - try(SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting)) { + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, + stmtColEncSetting)) { + + // bit + for (int i = 1; i <= 3; i++) { + pstmt.setInt(i, Integer.parseInt(numericValues[3])); + } - // bit - for (int i = 1; i <= 3; i++) { - pstmt.setInt(i, Integer.parseInt(numericValues[3])); - } - - pstmt.execute(); + pstmt.execute(); } } private static void populateTable3() throws SQLException { - String sql = "insert into " + table3 + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," - + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; - - try(SQLServerPreparedStatement 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++) { - pstmt.setShort(i, Short.valueOf(numericValues[1])); - } - - // smallint - for (int i = 7; i <= 9; i++) { - pstmt.setShort(i, Short.parseShort(numericValues[2])); - } - - // int - for (int i = 10; i <= 12; i++) { - pstmt.setInt(i, Integer.parseInt(numericValues[3])); - } - - // bigint - for (int i = 13; i <= 15; i++) { - pstmt.setLong(i, Long.parseLong(numericValues[4])); - } - - // float default - for (int i = 16; i <= 18; i++) { - pstmt.setDouble(i, Double.parseDouble(numericValues[5])); - } - - // float(30) - for (int i = 19; i <= 21; i++) { - pstmt.setDouble(i, Double.parseDouble(numericValues[6])); - } - - // real - for (int i = 22; i <= 24; i++) { - pstmt.setFloat(i, Float.parseFloat(numericValues[7])); - } - - // decimal default - for (int i = 25; i <= 27; i++) { - if (numericValues[8].equalsIgnoreCase("0")) - pstmt.setBigDecimal(i, new BigDecimal(numericValues[8]), 18, 0); - else - 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++) { - if (numericValues[10].equalsIgnoreCase("0")) - pstmt.setBigDecimal(i, new BigDecimal(numericValues[10]), 18, 0); - else - 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); - } - - // int2 - for (int i = 37; i <= 39; i++) { - pstmt.setInt(i, Integer.parseInt(numericValues[3])); - } - // smallmoney - for (int i = 40; i <= 42; i++) { - pstmt.setSmallMoney(i, new BigDecimal(numericValues[12])); - } - - // money - for (int i = 43; i <= 45; i++) { - pstmt.setMoney(i, new BigDecimal(numericValues[13])); - } - - // decimal(28,4) - for (int i = 46; i <= 48; i++) { - pstmt.setBigDecimal(i, new BigDecimal(numericValues[14]), 28, 4); - } - - // numeric(28,4) - for (int i = 49; i <= 51; i++) { - pstmt.setBigDecimal(i, new BigDecimal(numericValues[15]), 28, 4); - } - - pstmt.execute(); + String sql = "insert into " + table3 + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?," + "?,?,?," + "?,?,?" + ")"; + + try (SQLServerPreparedStatement 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++) { + pstmt.setShort(i, Short.valueOf(numericValues[1])); + } + + // smallint + for (int i = 7; i <= 9; i++) { + pstmt.setShort(i, Short.parseShort(numericValues[2])); + } + + // int + for (int i = 10; i <= 12; i++) { + pstmt.setInt(i, Integer.parseInt(numericValues[3])); + } + + // bigint + for (int i = 13; i <= 15; i++) { + pstmt.setLong(i, Long.parseLong(numericValues[4])); + } + + // float default + for (int i = 16; i <= 18; i++) { + pstmt.setDouble(i, Double.parseDouble(numericValues[5])); + } + + // float(30) + for (int i = 19; i <= 21; i++) { + pstmt.setDouble(i, Double.parseDouble(numericValues[6])); + } + + // real + for (int i = 22; i <= 24; i++) { + pstmt.setFloat(i, Float.parseFloat(numericValues[7])); + } + + // decimal default + for (int i = 25; i <= 27; i++) { + if (numericValues[8].equalsIgnoreCase("0")) + pstmt.setBigDecimal(i, new BigDecimal(numericValues[8]), 18, 0); + else + 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++) { + if (numericValues[10].equalsIgnoreCase("0")) + pstmt.setBigDecimal(i, new BigDecimal(numericValues[10]), 18, 0); + else + 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); + } + + // int2 + for (int i = 37; i <= 39; i++) { + pstmt.setInt(i, Integer.parseInt(numericValues[3])); + } + // smallmoney + for (int i = 40; i <= 42; i++) { + pstmt.setSmallMoney(i, new BigDecimal(numericValues[12])); + } + + // money + for (int i = 43; i <= 45; i++) { + pstmt.setMoney(i, new BigDecimal(numericValues[13])); + } + + // decimal(28,4) + for (int i = 46; i <= 48; i++) { + pstmt.setBigDecimal(i, new BigDecimal(numericValues[14]), 28, 4); + } + + // numeric(28,4) + for (int i = 49; i <= 51; i++) { + pstmt.setBigDecimal(i, new BigDecimal(numericValues[15]), 28, 4); + } + + pstmt.execute(); } } @@ -587,10 +584,11 @@ private void createMultiInsertionSelection() throws SQLException { + "') and OBJECTPROPERTY(id, N'IsProcedure') = 1)" + " DROP PROCEDURE " + multiStatementsProcedure; stmt.execute(sql); - sql = "CREATE PROCEDURE " + multiStatementsProcedure + " (@p0 char(20) = null, @p1 char(20) = null, @p2 char(20) = null, " - + "@p3 varchar(50) = null, @p4 varchar(50) = null, @p5 varchar(50) = null)" + " AS" + " INSERT INTO " + table1 - + " values (@p0,@p1,@p2,@p3,@p4,@p5)" + " INSERT INTO " + table2 + " values (@p0,@p1,@p2,@p3,@p4,@p5)" + " SELECT * FROM " + table1 - + " SELECT * FROM " + table2; + sql = "CREATE PROCEDURE " + multiStatementsProcedure + + " (@p0 char(20) = null, @p1 char(20) = null, @p2 char(20) = null, " + + "@p3 varchar(50) = null, @p4 varchar(50) = null, @p5 varchar(50) = null)" + " AS" + " INSERT INTO " + + table1 + " values (@p0,@p1,@p2,@p3,@p4,@p5)" + " INSERT INTO " + table2 + + " values (@p0,@p1,@p2,@p3,@p4,@p5)" + " SELECT * FROM " + table1 + " SELECT * FROM " + table2; stmt.execute(sql); } @@ -598,43 +596,42 @@ private void MultiInsertionSelection() throws SQLException { try { String sql = "{call " + multiStatementsProcedure + " (?,?,?,?,?,?)}"; - try(SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { - - // char, varchar - for (int i = 1; i <= 3; i++) { - callableStatement.setString(i, charValues[0]); - } - - for (int i = 4; i <= 6; i++) { - callableStatement.setString(i, charValues[1]); - } - - boolean results = callableStatement.execute(); - - // skip update count which is given by insertion - while (false == results && (-1) != callableStatement.getUpdateCount()) { - results = callableStatement.getMoreResults(); - } - - while (results) { - try(ResultSet rs = callableStatement.getResultSet()) { - int numberOfColumns = rs.getMetaData().getColumnCount(); - - while (rs.next()) { - testGetString(rs, numberOfColumns); - } - } - results = callableStatement.getMoreResults(); - } + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, + sql, stmtColEncSetting)) { + + // char, varchar + for (int i = 1; i <= 3; i++) { + callableStatement.setString(i, charValues[0]); + } + + for (int i = 4; i <= 6; i++) { + callableStatement.setString(i, charValues[1]); + } + + boolean results = callableStatement.execute(); + + // skip update count which is given by insertion + while (false == results && (-1) != callableStatement.getUpdateCount()) { + results = callableStatement.getMoreResults(); + } + + while (results) { + try (ResultSet rs = callableStatement.getResultSet()) { + int numberOfColumns = rs.getMetaData().getColumnCount(); + + while (rs.next()) { + testGetString(rs, numberOfColumns); + } + } + results = callableStatement.getMoreResults(); + } } - } - catch (SQLException e) { + } catch (SQLException e) { fail(e.toString()); } } - private void testGetString(ResultSet rs, - int numberOfColumns) throws SQLException { + private void testGetString(ResultSet rs, int numberOfColumns) throws SQLException { for (int i = 1; i <= numberOfColumns; i = i + 3) { String stringValue1 = "" + rs.getString(i); @@ -642,7 +639,8 @@ private void testGetString(ResultSet rs, String stringValue3 = "" + rs.getString(i + 2); assertTrue(stringValue1.equalsIgnoreCase(stringValue2) && stringValue2.equalsIgnoreCase(stringValue3), - "Decryption failed with getString(): " + stringValue1 + ", " + stringValue2 + ", " + stringValue3 + ".\n"); + "Decryption failed with getString(): " + stringValue1 + ", " + stringValue2 + ", " + stringValue3 + + ".\n"); } } @@ -655,20 +653,21 @@ private void createInputProcedure() throws SQLException { sql = "CREATE PROCEDURE " + inputProcedure + " @p0 int, @p1 decimal(18, 0), " + "@p2 float, @p3 real, @p4 numeric(18, 0), @p5 smallmoney, @p6 money," + "@p7 bit, @p8 smallint, @p9 bigint, @p10 float(30), @p11 decimal(10,5), @p12 numeric(8,2), " - + "@p13 decimal(28,4), @p14 numeric(28,4) " + " AS" + " SELECT top 1 RandomizedInt FROM " + numericTable - + " where DeterministicInt=@p0 and DeterministicDecimalDefault=@p1 and " + + "@p13 decimal(28,4), @p14 numeric(28,4) " + " AS" + " SELECT top 1 RandomizedInt FROM " + + numericTable + " where DeterministicInt=@p0 and DeterministicDecimalDefault=@p1 and " + " DeterministicFloatDefault=@p2 and DeterministicReal=@p3 and DeterministicNumericDefault=@p4 and" + " DeterministicSmallMoney=@p5 and DeterministicMoney=@p6 and DeterministicBit=@p7 and" + " DeterministicSmallint=@p8 and DeterministicBigint=@p9 and DeterministicFloat=@p10 and" - + " DeterministicDecimal=@p11 and DeterministicNumeric=@p12 and DeterministicDecimal2=@p13 and" + " DeterministicNumeric2=@p14 "; + + " DeterministicDecimal=@p11 and DeterministicNumeric=@p12 and DeterministicDecimal2=@p13 and" + + " DeterministicNumeric2=@p14 "; stmt.execute(sql); } - private void testInputProcedure(String sql, - String[] values) throws SQLException { + private void testInputProcedure(String sql, String[] values) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.setInt(1, Integer.parseInt(values[3])); if (RandomData.returnZero) @@ -696,11 +695,10 @@ private void testInputProcedure(String sql, callableStatement.setBigDecimal(15, new BigDecimal(values[15]), 28, 4); try (SQLServerResultSet rs = (SQLServerResultSet) callableStatement.executeQuery()) { - rs.next(); - assertEquals(rs.getString(1), values[3], "" + TestResource.getResource("R_inputParamFailed")); + rs.next(); + assertEquals(rs.getString(1), values[3], "" + TestResource.getResource("R_inputParamFailed")); } - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } @@ -714,15 +712,16 @@ private void createInputProcedure2() throws SQLException { + " @p0 varchar(50), @p1 uniqueidentifier, @p2 varchar(max), @p3 nchar(30), @p4 nvarchar(60), @p5 nvarchar(max), " + " @p6 varchar(8000), @p7 nvarchar(4000)" + " AS" + " SELECT top 1 RandomizedVarchar, DeterministicUniqueidentifier, DeterministicVarcharMax, RandomizedNchar, " - + " DeterministicNvarchar, DeterministicNvarcharMax, DeterministicVarchar8000, RandomizedNvarchar4000 FROM " + charTable - + " where DeterministicVarchar = @p0 and DeterministicUniqueidentifier =@p1"; + + " DeterministicNvarchar, DeterministicNvarcharMax, DeterministicVarchar8000, RandomizedNvarchar4000 FROM " + + charTable + " where DeterministicVarchar = @p0 and DeterministicUniqueidentifier =@p1"; stmt.execute(sql); } private void testInputProcedure2(String sql) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.setString(1, charValues[1]); callableStatement.setUniqueIdentifier(2, charValues[6]); @@ -734,18 +733,18 @@ private void testInputProcedure2(String sql) throws SQLException { callableStatement.setNString(8, charValues[8]); try (SQLServerResultSet rs = (SQLServerResultSet) callableStatement.executeQuery()) { - rs.next(); - assertEquals(rs.getString(1).trim(), charValues[1], TestResource.getResource("R_inputParamFailed")); - assertEquals(rs.getUniqueIdentifier(2), charValues[6].toUpperCase(), TestResource.getResource("R_inputParamFailed")); - assertEquals(rs.getString(3).trim(), charValues[2], TestResource.getResource("R_inputParamFailed")); - assertEquals(rs.getString(4).trim(), charValues[3], TestResource.getResource("R_inputParamFailed")); - assertEquals(rs.getString(5).trim(), charValues[4], TestResource.getResource("R_inputParamFailed")); - assertEquals(rs.getString(6).trim(), charValues[5], TestResource.getResource("R_inputParamFailed")); - assertEquals(rs.getString(7).trim(), charValues[7], TestResource.getResource("R_inputParamFailed")); - assertEquals(rs.getString(8).trim(), charValues[8], TestResource.getResource("R_inputParamFailed")); + rs.next(); + assertEquals(rs.getString(1).trim(), charValues[1], TestResource.getResource("R_inputParamFailed")); + assertEquals(rs.getUniqueIdentifier(2), charValues[6].toUpperCase(), + TestResource.getResource("R_inputParamFailed")); + assertEquals(rs.getString(3).trim(), charValues[2], TestResource.getResource("R_inputParamFailed")); + assertEquals(rs.getString(4).trim(), charValues[3], TestResource.getResource("R_inputParamFailed")); + assertEquals(rs.getString(5).trim(), charValues[4], TestResource.getResource("R_inputParamFailed")); + assertEquals(rs.getString(6).trim(), charValues[5], TestResource.getResource("R_inputParamFailed")); + assertEquals(rs.getString(7).trim(), charValues[7], TestResource.getResource("R_inputParamFailed")); + assertEquals(rs.getString(8).trim(), charValues[8], TestResource.getResource("R_inputParamFailed")); } - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } @@ -755,15 +754,17 @@ private void createOutputProcedure3() throws SQLException { + "') and OBJECTPROPERTY(id, N'IsProcedure') = 1)" + " DROP PROCEDURE " + outputProcedure3; stmt.execute(sql); - sql = "CREATE PROCEDURE " + outputProcedure3 + " @p0 int OUTPUT, @p1 int OUTPUT " + " AS" + " SELECT top 1 @p0=DeterministicInt FROM " - + table3 + " SELECT top 1 @p1=RandomizedInt FROM " + table4; + sql = "CREATE PROCEDURE " + outputProcedure3 + " @p0 int OUTPUT, @p1 int OUTPUT " + " AS" + + " SELECT top 1 @p0=DeterministicInt FROM " + table3 + " SELECT top 1 @p1=RandomizedInt FROM " + + table4; stmt.execute(sql); } private void testOutputProcedure3RandomOrder(String sql) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.registerOutParameter(1, java.sql.Types.INTEGER); callableStatement.registerOutParameter(2, java.sql.Types.INTEGER); @@ -784,15 +785,15 @@ private void testOutputProcedure3RandomOrder(String sql) throws SQLException { int intValue5 = callableStatement.getInt(1); assertEquals("" + intValue5, numericValues[3], TestResource.getResource("R_outputParamFailed")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } private void testOutputProcedure3Inorder(String sql) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.registerOutParameter(1, java.sql.Types.INTEGER); callableStatement.registerOutParameter(2, java.sql.Types.INTEGER); @@ -804,15 +805,15 @@ private void testOutputProcedure3Inorder(String sql) throws SQLException { int intValue2 = callableStatement.getInt(2); assertEquals("" + intValue2, numericValues[3], TestResource.getResource("R_outputParamFailed")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } private void testOutputProcedure3ReverseOrder(String sql) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.registerOutParameter(1, java.sql.Types.INTEGER); callableStatement.registerOutParameter(2, java.sql.Types.INTEGER); @@ -824,8 +825,7 @@ private void testOutputProcedure3ReverseOrder(String sql) throws SQLException { int intValue = callableStatement.getInt(1); assertEquals("" + intValue, numericValues[3], TestResource.getResource("R_outputParamFailed")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } @@ -845,10 +845,10 @@ private void createOutputProcedure2() throws SQLException { stmt.execute(sql); } - private void testOutputProcedure2RandomOrder(String sql, - String[] values) throws SQLException { + private void testOutputProcedure2RandomOrder(String sql, String[] values) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.registerOutParameter(1, java.sql.Types.INTEGER); callableStatement.registerOutParameter(2, java.sql.Types.INTEGER); @@ -892,16 +892,15 @@ private void testOutputProcedure2RandomOrder(String sql, int encryptedInt = callableStatement.getInt(2); assertEquals("" + encryptedInt, values[3], TestResource.getResource("R_outputParamFailed")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } - private void testOutputProcedure2Inorder(String sql, - String[] values) throws SQLException { + private void testOutputProcedure2Inorder(String sql, String[] values) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.registerOutParameter(1, java.sql.Types.INTEGER); callableStatement.registerOutParameter(2, java.sql.Types.INTEGER); @@ -945,16 +944,15 @@ private void testOutputProcedure2Inorder(String sql, BigDecimal encryptedMoney = callableStatement.getMoney(10); assertEquals("" + encryptedMoney, values[13], TestResource.getResource("R_outputParamFailed")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } - private void testOutputProcedure2ReverseOrder(String sql, - String[] values) throws SQLException { + private void testOutputProcedure2ReverseOrder(String sql, String[] values) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.registerOutParameter(1, java.sql.Types.INTEGER); callableStatement.registerOutParameter(2, java.sql.Types.INTEGER); @@ -998,8 +996,7 @@ private void testOutputProcedure2ReverseOrder(String sql, int intValue = callableStatement.getInt(1); assertEquals("" + intValue, values[3], TestResource.getResource("R_outputParamFailed")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } @@ -1012,15 +1009,16 @@ private void createOutputProcedure() throws SQLException { sql = "CREATE PROCEDURE " + outputProcedure + " @p0 int OUTPUT, @p1 float OUTPUT, @p2 smallint OUTPUT, " + "@p3 bigint OUTPUT, @p4 tinyint OUTPUT, @p5 smallmoney OUTPUT, @p6 money OUTPUT " + " AS" + " SELECT top 1 @p0=RandomizedInt, @p1=DeterministicFloatDefault, @p2=RandomizedSmallint," - + " @p3=RandomizedBigint, @p4=DeterministicTinyint, @p5=DeterministicSmallMoney, @p6=DeterministicMoney FROM " + table3; + + " @p3=RandomizedBigint, @p4=DeterministicTinyint, @p5=DeterministicSmallMoney, @p6=DeterministicMoney FROM " + + table3; stmt.execute(sql); } - private void testOutputProcedureRandomOrder(String sql, - String[] values) throws SQLException { + private void testOutputProcedureRandomOrder(String sql, String[] values) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.registerOutParameter(1, java.sql.Types.INTEGER); callableStatement.registerOutParameter(2, java.sql.Types.DOUBLE); @@ -1060,16 +1058,15 @@ private void testOutputProcedureRandomOrder(String sql, assertEquals("" + smallmoney1, "" + values[12], TestResource.getResource("R_outputParamFailed")); BigDecimal money1 = callableStatement.getMoney(7); assertEquals("" + money1, "" + values[13], TestResource.getResource("R_outputParamFailed")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } - private void testOutputProcedureInorder(String sql, - String[] values) throws SQLException { + private void testOutputProcedureInorder(String sql, String[] values) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.registerOutParameter(1, java.sql.Types.INTEGER); callableStatement.registerOutParameter(2, java.sql.Types.DOUBLE); @@ -1102,16 +1099,15 @@ private void testOutputProcedureInorder(String sql, BigDecimal money1 = callableStatement.getMoney(7); assertEquals("" + money1, values[13], TestResource.getResource("R_outputParamFailed")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } - private void testOutputProcedureReverseOrder(String sql, - String[] values) throws SQLException { + private void testOutputProcedureReverseOrder(String sql, String[] values) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.registerOutParameter(1, java.sql.Types.INTEGER); callableStatement.registerOutParameter(2, java.sql.Types.DOUBLE); @@ -1143,8 +1139,7 @@ private void testOutputProcedureReverseOrder(String sql, int intValue2 = callableStatement.getInt(1); assertEquals("" + intValue2, values[3], TestResource.getResource("R_outputParamFailed")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } @@ -1154,15 +1149,16 @@ private void createInOutProcedure() throws SQLException { + "') and OBJECTPROPERTY(id, N'IsProcedure') = 1)" + " DROP PROCEDURE " + inoutProcedure; stmt.execute(sql); - sql = "CREATE PROCEDURE " + inoutProcedure + " @p0 int OUTPUT" + " AS" + " SELECT top 1 @p0=DeterministicInt FROM " + table3 - + " where DeterministicInt=@p0"; + sql = "CREATE PROCEDURE " + inoutProcedure + " @p0 int OUTPUT" + " AS" + + " SELECT top 1 @p0=DeterministicInt FROM " + table3 + " where DeterministicInt=@p0"; stmt.execute(sql); } private void testInOutProcedure(String sql) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.setInt(1, Integer.parseInt(numericValues[3])); callableStatement.registerOutParameter(1, java.sql.Types.INTEGER); @@ -1171,8 +1167,7 @@ private void testInOutProcedure(String sql) throws SQLException { int intValue = callableStatement.getInt(1); assertEquals("" + intValue, numericValues[3], "Test for Inout parameter fails.\n"); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } @@ -1191,7 +1186,8 @@ private void createMixedProcedure() throws SQLException { private void testMixedProcedure(String sql) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.registerOutParameter(1, java.sql.Types.INTEGER); callableStatement.setInt(2, Integer.parseInt(numericValues[3])); @@ -1211,8 +1207,7 @@ private void testMixedProcedure(String sql) throws SQLException { int returnedValue = callableStatement.getInt(1); assertEquals("" + returnedValue, "" + 123, "Test for Inout parameter fails.\n"); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } @@ -1231,7 +1226,8 @@ private void createMixedProcedure2() throws SQLException { private void testMixedProcedure2RandomOrder(String sql) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.registerOutParameter(1, java.sql.Types.INTEGER); callableStatement.registerOutParameter(2, java.sql.Types.FLOAT); @@ -1257,15 +1253,15 @@ private void testMixedProcedure2RandomOrder(String sql) throws SQLException { double floatValue3 = callableStatement.getDouble(2); assertEquals("" + floatValue3, numericValues[5], TestResource.getResource("R_outputParamFailed")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } private void testMixedProcedure2Inorder(String sql) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.registerOutParameter(1, java.sql.Types.INTEGER); callableStatement.registerOutParameter(2, java.sql.Types.FLOAT); @@ -1278,8 +1274,7 @@ private void testMixedProcedure2Inorder(String sql) throws SQLException { double floatValue = callableStatement.getDouble(2); assertEquals("" + floatValue, numericValues[5], TestResource.getResource("R_outputParamFailed")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } @@ -1289,15 +1284,18 @@ private void createMixedProcedure3() throws SQLException { + "') and OBJECTPROPERTY(id, N'IsProcedure') = 1)" + " DROP PROCEDURE " + mixedProcedure3; stmt.execute(sql); - sql = "CREATE PROCEDURE " + mixedProcedure3 + " @p0 bigint OUTPUT, @p1 float OUTPUT, @p2 int OUTPUT, @p3 smallint" + " AS" - + " SELECT top 1 @p0=PlainBigint, @p1=PlainFloatDefault FROM " + table3 + " where PlainInt=@p2 and PlainSmallint=@p3"; + sql = "CREATE PROCEDURE " + mixedProcedure3 + + " @p0 bigint OUTPUT, @p1 float OUTPUT, @p2 int OUTPUT, @p3 smallint" + " AS" + + " SELECT top 1 @p0=PlainBigint, @p1=PlainFloatDefault FROM " + table3 + + " where PlainInt=@p2 and PlainSmallint=@p3"; stmt.execute(sql); } private void testMixedProcedure3RandomOrder(String sql) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.registerOutParameter(1, java.sql.Types.BIGINT); callableStatement.registerOutParameter(2, java.sql.Types.FLOAT); @@ -1323,15 +1321,15 @@ private void testMixedProcedure3RandomOrder(String sql) throws SQLException { long bigintValue3 = callableStatement.getLong(1); assertEquals("" + bigintValue3, numericValues[4], TestResource.getResource("R_outputParamFailed")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } private void testMixedProcedure3Inorder(String sql) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.registerOutParameter(1, java.sql.Types.BIGINT); callableStatement.registerOutParameter(2, java.sql.Types.FLOAT); @@ -1344,15 +1342,15 @@ private void testMixedProcedure3Inorder(String sql) throws SQLException { double floatValue = callableStatement.getDouble(2); assertEquals("" + floatValue, numericValues[5], TestResource.getResource("R_outputParamFailed")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } private void testMixedProcedure3ReverseOrder(String sql) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.registerOutParameter(1, java.sql.Types.BIGINT); callableStatement.registerOutParameter(2, java.sql.Types.FLOAT); @@ -1365,20 +1363,20 @@ private void testMixedProcedure3ReverseOrder(String sql) throws SQLException { long bigintValue = callableStatement.getLong(1); assertEquals("" + bigintValue, numericValues[4], TestResource.getResource("R_outputParamFailed")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } private void createMixedProcedureNumericPrcisionScale() throws SQLException { String sql = " IF EXISTS (select * from sysobjects where id = object_id(N'" + mixedProcedureNumericPrcisionScale - + "') and OBJECTPROPERTY(id, N'IsProcedure') = 1)" + " DROP PROCEDURE " + mixedProcedureNumericPrcisionScale; + + "') and OBJECTPROPERTY(id, N'IsProcedure') = 1)" + " DROP PROCEDURE " + + mixedProcedureNumericPrcisionScale; stmt.execute(sql); sql = "CREATE PROCEDURE " + mixedProcedureNumericPrcisionScale - + " @p1 decimal(18,0) OUTPUT, @p2 decimal(10,5) OUTPUT, @p3 numeric(18, 0) OUTPUT, @p4 numeric(8,2) OUTPUT " + " AS" - + " SELECT top 1 @p1=RandomizedDecimalDefault, @p2=DeterministicDecimal," + + " @p1 decimal(18,0) OUTPUT, @p2 decimal(10,5) OUTPUT, @p3 numeric(18, 0) OUTPUT, @p4 numeric(8,2) OUTPUT " + + " AS" + " SELECT top 1 @p1=RandomizedDecimalDefault, @p2=DeterministicDecimal," + " @p3=RandomizedNumericDefault, @p4=DeterministicNumeric FROM " + table3 + " where DeterministicDecimal=@p2 and DeterministicNumeric=@p4" + " return 123"; @@ -1387,7 +1385,8 @@ private void createMixedProcedureNumericPrcisionScale() throws SQLException { private void testMixedProcedureNumericPrcisionScaleInorder(String sql) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.registerOutParameter(1, java.sql.Types.DECIMAL, 18, 0); callableStatement.registerOutParameter(2, java.sql.Types.DECIMAL, 10, 5); @@ -1409,15 +1408,15 @@ private void testMixedProcedureNumericPrcisionScaleInorder(String sql) throws SQ BigDecimal value4 = callableStatement.getBigDecimal(4); assertEquals(value4, new BigDecimal(numericValues[11]), "Test for input output parameter fails.\n"); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } private void testMixedProcedureNumericPrcisionScaleParameterName(String sql) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.registerOutParameter("p1", java.sql.Types.DECIMAL, 18, 0); callableStatement.registerOutParameter("p2", java.sql.Types.DECIMAL, 10, 5); @@ -1439,8 +1438,7 @@ private void testMixedProcedureNumericPrcisionScaleParameterName(String sql) thr BigDecimal value4 = callableStatement.getBigDecimal(4); assertEquals(value4, new BigDecimal(numericValues[11]), "Test for input output parameter fails.\n"); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } @@ -1450,18 +1448,21 @@ private void createOutputProcedureChar() throws SQLException { + "') and OBJECTPROPERTY(id, N'IsProcedure') = 1)" + " DROP PROCEDURE " + outputProcedureChar; stmt.execute(sql); - sql = "CREATE PROCEDURE " + outputProcedureChar + " @p0 char(20) OUTPUT,@p1 varchar(50) OUTPUT,@p2 nchar(30) OUTPUT," + sql = "CREATE PROCEDURE " + outputProcedureChar + + " @p0 char(20) OUTPUT,@p1 varchar(50) OUTPUT,@p2 nchar(30) OUTPUT," + "@p3 nvarchar(60) OUTPUT, @p4 uniqueidentifier OUTPUT, @p5 varchar(max) OUTPUT, @p6 nvarchar(max) OUTPUT, @p7 varchar(8000) OUTPUT, @p8 nvarchar(4000) OUTPUT" + " AS" + " SELECT top 1 @p0=DeterministicChar,@p1=RandomizedVarChar,@p2=RandomizedNChar," + " @p3=DeterministicNVarChar, @p4=DeterministicUniqueidentifier, @p5=DeterministicVarcharMax," - + " @p6=DeterministicNvarcharMax, @p7=DeterministicVarchar8000, @p8=RandomizedNvarchar4000 FROM " + charTable; + + " @p6=DeterministicNvarcharMax, @p7=DeterministicVarchar8000, @p8=RandomizedNvarchar4000 FROM " + + charTable; stmt.execute(sql); } private void testOutputProcedureCharInorder(String sql) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.registerOutParameter(1, java.sql.Types.CHAR, 20, 0); callableStatement.registerOutParameter(2, java.sql.Types.VARCHAR, 50, 0); callableStatement.registerOutParameter(3, java.sql.Types.NCHAR, 30, 0); @@ -1486,7 +1487,8 @@ private void testOutputProcedureCharInorder(String sql) throws SQLException { assertEquals(nvarcharValue, charValues[4], TestResource.getResource("R_outputParamFailed")); String uniqueIdentifierValue = callableStatement.getString(5).trim(); - assertEquals(uniqueIdentifierValue.toLowerCase(), charValues[6], TestResource.getResource("R_outputParamFailed")); + assertEquals(uniqueIdentifierValue.toLowerCase(), charValues[6], + TestResource.getResource("R_outputParamFailed")); String varcharValuemax = callableStatement.getString(6).trim(); assertEquals(varcharValuemax, charValues[2], TestResource.getResource("R_outputParamFailed")); @@ -1500,15 +1502,15 @@ private void testOutputProcedureCharInorder(String sql) throws SQLException { String nvarcharValue4000 = callableStatement.getNString(9).trim(); assertEquals(nvarcharValue4000, charValues[8], TestResource.getResource("R_outputParamFailed")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } private void testOutputProcedureCharInorderObject(String sql) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.registerOutParameter(1, java.sql.Types.CHAR, 20, 0); callableStatement.registerOutParameter(2, java.sql.Types.VARCHAR, 50, 0); callableStatement.registerOutParameter(3, java.sql.Types.NCHAR, 30, 0); @@ -1534,7 +1536,8 @@ private void testOutputProcedureCharInorderObject(String sql) throws SQLExceptio assertEquals(nvarcharValue.trim(), charValues[4], TestResource.getResource("R_outputParamFailed")); String uniqueIdentifierValue = (String) callableStatement.getObject(5); - assertEquals(uniqueIdentifierValue.toLowerCase(), charValues[6], TestResource.getResource("R_outputParamFailed")); + assertEquals(uniqueIdentifierValue.toLowerCase(), charValues[6], + TestResource.getResource("R_outputParamFailed")); String varcharValuemax = (String) callableStatement.getObject(6); @@ -1550,8 +1553,7 @@ private void testOutputProcedureCharInorderObject(String sql) throws SQLExceptio String nvarcharValue4000 = (String) callableStatement.getObject(9); assertEquals(nvarcharValue4000, charValues[8], TestResource.getResource("R_outputParamFailed")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } @@ -1561,7 +1563,8 @@ private void createOutputProcedureNumeric() throws SQLException { + "') and OBJECTPROPERTY(id, N'IsProcedure') = 1)" + " DROP PROCEDURE " + outputProcedureNumeric; stmt.execute(sql); - sql = "CREATE PROCEDURE " + outputProcedureNumeric + " @p0 bit OUTPUT, @p1 tinyint OUTPUT, @p2 smallint OUTPUT, @p3 int OUTPUT," + sql = "CREATE PROCEDURE " + outputProcedureNumeric + + " @p0 bit OUTPUT, @p1 tinyint OUTPUT, @p2 smallint OUTPUT, @p3 int OUTPUT," + " @p4 bigint OUTPUT, @p5 float OUTPUT, @p6 float(30) output, @p7 real output, @p8 decimal(18, 0) output, @p9 decimal(10,5) output," + " @p10 numeric(18, 0) output, @p11 numeric(8,2) output, @p12 smallmoney output, @p13 money output, @p14 decimal(28,4) output, @p15 numeric(28,4) output" + " AS" + " SELECT top 1 @p0=DeterministicBit, @p1=RandomizedTinyint, @p2=DeterministicSmallint," @@ -1575,7 +1578,8 @@ private void createOutputProcedureNumeric() throws SQLException { private void testOutputProcedureNumericInorder(String sql) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.registerOutParameter(1, java.sql.Types.BIT); callableStatement.registerOutParameter(2, java.sql.Types.TINYINT); callableStatement.registerOutParameter(3, java.sql.Types.SMALLINT); @@ -1623,38 +1627,46 @@ private void testOutputProcedureNumericInorder(String sql) throws SQLException { assertEquals("" + realValue, numericValues[7], TestResource.getResource("R_outputParamFailed")); BigDecimal decimalDefault = callableStatement.getBigDecimal(9); - assertEquals(decimalDefault, new BigDecimal(numericValues[8]), TestResource.getResource("R_outputParamFailed")); + assertEquals(decimalDefault, new BigDecimal(numericValues[8]), + TestResource.getResource("R_outputParamFailed")); BigDecimal decimalValue = callableStatement.getBigDecimal(10); - assertEquals(decimalValue, new BigDecimal(numericValues[9]), TestResource.getResource("R_outputParamFailed")); + assertEquals(decimalValue, new BigDecimal(numericValues[9]), + TestResource.getResource("R_outputParamFailed")); BigDecimal numericDefault = callableStatement.getBigDecimal(11); - assertEquals(numericDefault, new BigDecimal(numericValues[10]), TestResource.getResource("R_outputParamFailed")); + assertEquals(numericDefault, new BigDecimal(numericValues[10]), + TestResource.getResource("R_outputParamFailed")); BigDecimal numericValue = callableStatement.getBigDecimal(12); - assertEquals(numericValue, new BigDecimal(numericValues[11]), TestResource.getResource("R_outputParamFailed")); + assertEquals(numericValue, new BigDecimal(numericValues[11]), + TestResource.getResource("R_outputParamFailed")); BigDecimal smallMoneyValue = callableStatement.getSmallMoney(13); - assertEquals(smallMoneyValue, new BigDecimal(numericValues[12]), TestResource.getResource("R_outputParamFailed")); + assertEquals(smallMoneyValue, new BigDecimal(numericValues[12]), + TestResource.getResource("R_outputParamFailed")); BigDecimal moneyValue = callableStatement.getMoney(14); - assertEquals(moneyValue, new BigDecimal(numericValues[13]), TestResource.getResource("R_outputParamFailed")); + assertEquals(moneyValue, new BigDecimal(numericValues[13]), + TestResource.getResource("R_outputParamFailed")); BigDecimal decimalValue2 = callableStatement.getBigDecimal(15); - assertEquals(decimalValue2, new BigDecimal(numericValues[14]), TestResource.getResource("R_outputParamFailed")); + assertEquals(decimalValue2, new BigDecimal(numericValues[14]), + TestResource.getResource("R_outputParamFailed")); BigDecimal numericValue2 = callableStatement.getBigDecimal(16); - assertEquals(numericValue2, new BigDecimal(numericValues[15]), TestResource.getResource("R_outputParamFailed")); + assertEquals(numericValue2, new BigDecimal(numericValues[15]), + TestResource.getResource("R_outputParamFailed")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } private void testcoerctionsOutputProcedureNumericInorder(String sql) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.registerOutParameter(1, java.sql.Types.BIT); callableStatement.registerOutParameter(2, java.sql.Types.TINYINT); callableStatement.registerOutParameter(3, java.sql.Types.SMALLINT); @@ -1674,8 +1686,8 @@ private void testcoerctionsOutputProcedureNumericInorder(String sql) throws SQLE callableStatement.execute(); - Class[] boolean_coercions = {Object.class, Short.class, Integer.class, Long.class, Float.class, Double.class, BigDecimal.class, - String.class}; + Class[] boolean_coercions = {Object.class, Short.class, Integer.class, Long.class, Float.class, + Double.class, BigDecimal.class, String.class}; for (int i = 0; i < boolean_coercions.length; i++) { Object value = getxxx(1, boolean_coercions[i], callableStatement); Object boolVal = null; @@ -1685,8 +1697,8 @@ else if (value.toString().equals("0") || value.equals(false) || value.toString() boolVal = false; assertEquals("" + boolVal, numericValues[0], TestResource.getResource("R_outputParamFailed")); } - Class[] tinyint_coercions = {Object.class, Short.class, Integer.class, Long.class, Float.class, Double.class, BigDecimal.class, - String.class}; + Class[] tinyint_coercions = {Object.class, Short.class, Integer.class, Long.class, Float.class, + Double.class, BigDecimal.class, String.class}; for (int i = 0; i < tinyint_coercions.length; i++) { Object tinyIntValue = getxxx(2, tinyint_coercions[i], callableStatement); @@ -1698,8 +1710,8 @@ else if (value.toString().equals("0") || value.equals(false) || value.toString() assertEquals(tinyIntValue, x, TestResource.getResource("R_outputParamFailed")); } - Class[] smallint_coercions = {Object.class, Short.class, Integer.class, Long.class, Float.class, Double.class, BigDecimal.class, - String.class}; + Class[] smallint_coercions = {Object.class, Short.class, Integer.class, Long.class, Float.class, + Double.class, BigDecimal.class, String.class}; for (int i = 0; i < smallint_coercions.length; i++) { Object smallIntValue = getxxx(3, smallint_coercions[i], callableStatement); Object x = createValue(smallint_coercions[i], 2); @@ -1710,7 +1722,8 @@ else if (value.toString().equals("0") || value.equals(false) || value.toString() assertEquals(smallIntValue, x, TestResource.getResource("R_outputParamFailed")); } - Class[] int_coercions = {Object.class, Short.class, Integer.class, Long.class, Float.class, Double.class, BigDecimal.class, String.class}; + Class[] int_coercions = {Object.class, Short.class, Integer.class, Long.class, Float.class, Double.class, + BigDecimal.class, String.class}; for (int i = 0; i < int_coercions.length; i++) { Object IntValue = getxxx(4, int_coercions[i], callableStatement); Object x = createValue(int_coercions[i], 3); @@ -1722,8 +1735,8 @@ else if (value.toString().equals("0") || value.equals(false) || value.toString() } } - Class[] bigint_coercions = {Object.class, Short.class, Integer.class, Long.class, Float.class, Double.class, BigDecimal.class, - String.class}; + Class[] bigint_coercions = {Object.class, Short.class, Integer.class, Long.class, Float.class, Double.class, + BigDecimal.class, String.class}; for (int i = 0; i < int_coercions.length; i++) { Object bigIntValue = getxxx(5, bigint_coercions[i], callableStatement); Object x = createValue(bigint_coercions[i], 4); @@ -1735,8 +1748,8 @@ else if (value.toString().equals("0") || value.equals(false) || value.toString() } } - Class[] float_coercions = {Object.class, Short.class, Integer.class, Long.class, Float.class, Double.class, BigDecimal.class, - String.class}; + Class[] float_coercions = {Object.class, Short.class, Integer.class, Long.class, Float.class, Double.class, + BigDecimal.class, String.class}; for (int i = 0; i < float_coercions.length; i++) { Object floatDefaultValue = getxxx(6, float_coercions[i], callableStatement); Object x = createValue(float_coercions[i], 5); @@ -1759,7 +1772,8 @@ else if (value.toString().equals("0") || value.equals(false) || value.toString() } } - Class[] real_coercions = {Object.class, Short.class, Integer.class, Long.class, Float.class, BigDecimal.class, String.class}; + Class[] real_coercions = {Object.class, Short.class, Integer.class, Long.class, Float.class, + BigDecimal.class, String.class}; for (int i = 0; i < real_coercions.length; i++) { Object realValue = getxxx(8, real_coercions[i], callableStatement); @@ -1773,8 +1787,8 @@ else if (value.toString().equals("0") || value.equals(false) || value.toString() } } - Class[] decimalDefault_coercions = {Object.class, Short.class, Integer.class, Long.class, Float.class, Double.class, BigDecimal.class, - String.class}; + Class[] decimalDefault_coercions = {Object.class, Short.class, Integer.class, Long.class, Float.class, + Double.class, BigDecimal.class, String.class}; for (int i = 0; i < decimalDefault_coercions.length; i++) { Object decimalDefaultValue = getxxx(9, decimalDefault_coercions[i], callableStatement); Object x = createValue(decimalDefault_coercions[i], 8); @@ -1862,14 +1876,12 @@ else if (value.toString().equals("0") || value.equals(false) || value.toString() } } - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } - private Object createValue(Class coercion, - int index) { + private Object createValue(Class coercion, int index) { try { if (coercion == Float.class) return Float.parseFloat(numericValues[index]); @@ -1887,62 +1899,44 @@ private Object createValue(Class coercion, return Double.parseDouble(numericValues[index]); if (coercion == BigDecimal.class) return new BigDecimal(numericValues[index]); - } - catch (java.lang.NumberFormatException e) { - } + } catch (java.lang.NumberFormatException e) {} return null; } - private Object getxxx(int ordinal, - Class coercion, + private Object getxxx(int ordinal, Class coercion, SQLServerCallableStatement callableStatement) throws SQLException { if (coercion == null || coercion == Object.class) { return callableStatement.getObject(ordinal); - } - else if (coercion == String.class) { + } else if (coercion == String.class) { return callableStatement.getString(ordinal); - } - else if (coercion == Boolean.class) { + } else if (coercion == Boolean.class) { return Boolean.valueOf(callableStatement.getBoolean(ordinal)); - } - else if (coercion == Byte.class) { + } else if (coercion == Byte.class) { return Byte.valueOf(callableStatement.getByte(ordinal)); - } - else if (coercion == Short.class) { + } else if (coercion == Short.class) { return Short.valueOf(callableStatement.getShort(ordinal)); - } - else if (coercion == Integer.class) { + } else if (coercion == Integer.class) { return Integer.valueOf(callableStatement.getInt(ordinal)); - } - else if (coercion == Long.class) { + } else if (coercion == Long.class) { return Long.valueOf(callableStatement.getLong(ordinal)); - } - else if (coercion == Float.class) { + } else if (coercion == Float.class) { return Float.valueOf(callableStatement.getFloat(ordinal)); - } - else if (coercion == Double.class) { + } else if (coercion == Double.class) { return Double.valueOf(callableStatement.getDouble(ordinal)); - } - else if (coercion == BigDecimal.class) { + } else if (coercion == BigDecimal.class) { return callableStatement.getBigDecimal(ordinal); - } - else if (coercion == byte[].class) { + } else if (coercion == byte[].class) { return callableStatement.getBytes(ordinal); - } - else if (coercion == java.sql.Date.class) { + } else if (coercion == java.sql.Date.class) { return callableStatement.getDate(ordinal); - } - else if (coercion == Time.class) { + } else if (coercion == Time.class) { return callableStatement.getTime(ordinal); - } - else if (coercion == Timestamp.class) { + } else if (coercion == Timestamp.class) { return callableStatement.getTimestamp(ordinal); - } - else if (coercion == microsoft.sql.DateTimeOffset.class) { + } else if (coercion == microsoft.sql.DateTimeOffset.class) { return callableStatement.getDateTimeOffset(ordinal); - } - else { + } else { // Otherwise fail("Unhandled type: " + coercion); } @@ -1955,7 +1949,8 @@ private void createOutputProcedureBinary() throws SQLException { + "') and OBJECTPROPERTY(id, N'IsProcedure') = 1)" + " DROP PROCEDURE " + outputProcedureBinary; stmt.execute(sql); - sql = "CREATE PROCEDURE " + outputProcedureBinary + " @p0 binary(20) OUTPUT,@p1 varbinary(50) OUTPUT,@p2 varbinary(max) OUTPUT," + sql = "CREATE PROCEDURE " + outputProcedureBinary + + " @p0 binary(20) OUTPUT,@p1 varbinary(50) OUTPUT,@p2 varbinary(max) OUTPUT," + " @p3 binary(512) OUTPUT,@p4 varbinary(8000) OUTPUT " + " AS" + " SELECT top 1 @p0=RandomizedBinary,@p1=DeterministicVarbinary,@p2=DeterministicVarbinaryMax," + " @p3=DeterministicBinary512,@p4=DeterministicBinary8000 FROM " + binaryTable; @@ -1965,7 +1960,8 @@ private void createOutputProcedureBinary() throws SQLException { private void testOutputProcedureBinaryInorder(String sql) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.registerOutParameter(1, java.sql.Types.BINARY, 20, 0); callableStatement.registerOutParameter(2, java.sql.Types.VARBINARY, 50, 0); callableStatement.registerOutParameter(3, java.sql.Types.LONGVARBINARY); @@ -2003,15 +1999,15 @@ private void testOutputProcedureBinaryInorder(String sql) throws SQLException { for (int i = 0; i < expected.length; i++) { assertEquals(received5[i], expected[i], TestResource.getResource("R_outputParamFailed")); } - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } private void testOutputProcedureBinaryInorderObject(String sql) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.registerOutParameter(1, java.sql.Types.BINARY, 20, 0); callableStatement.registerOutParameter(2, java.sql.Types.VARBINARY, 50, 0); callableStatement.registerOutParameter(3, java.sql.Types.LONGVARBINARY); @@ -2029,27 +2025,28 @@ private void testOutputProcedureBinaryInorderObject(String sql) throws SQLExcept try { if (null != byteValues.get(i)) { for (int j = 0; j < expected.length; j++) { - assertEquals(expected[j] == binaryValue[j] && expected[j] == binaryValue[j] && expected[j] == binaryValue[j], true, - "Decryption failed with getObject(): " + binaryValue + ", " + binaryValue + ", " + binaryValue + ".\n"); + assertEquals( + expected[j] == binaryValue[j] && expected[j] == binaryValue[j] + && expected[j] == binaryValue[j], + true, "Decryption failed with getObject(): " + binaryValue + ", " + binaryValue + + ", " + binaryValue + ".\n"); } } - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); - } - finally { + } finally { index++; } } - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } private void testOutputProcedureBinaryInorderString(String sql) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.registerOutParameter(1, java.sql.Types.BINARY, 20, 0); callableStatement.registerOutParameter(2, java.sql.Types.VARBINARY, 50, 0); callableStatement.registerOutParameter(3, java.sql.Types.LONGVARBINARY); @@ -2069,18 +2066,15 @@ private void testOutputProcedureBinaryInorderString(String sql) throws SQLExcept expected.append(String.format("%02X", b)); } expectedStr = "" + expected.toString(); - } - else { + } else { expectedStr = "null"; } try { - assertEquals(stringValue1.startsWith(expectedStr), true, - "\nDecryption failed with getString(): " + stringValue1 + ".\nExpected Value: " + expectedStr); - } - catch (Exception e) { + assertEquals(stringValue1.startsWith(expectedStr), true, "\nDecryption failed with getString(): " + + stringValue1 + ".\nExpected Value: " + expectedStr); + } catch (Exception e) { fail(e.toString()); - } - finally { + } finally { index++; } } @@ -2147,8 +2141,7 @@ protected static void createDateTableCallableStatement() throws SQLException { try { stmt.execute(sql); stmt.execute("DBCC FREEPROCCACHE"); - } - catch (SQLException e) { + } catch (SQLException e) { fail(e.toString()); } } @@ -2181,10 +2174,11 @@ private static LinkedList createTemporalTypesCallableStatement(boolean n } private static void populateDateNormalCase() throws SQLException { - String sql = "insert into " + dateTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," - + "?,?,?" + ")"; + String sql = "insert into " + dateTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; - SQLServerPreparedStatement sqlPstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting); + SQLServerPreparedStatement sqlPstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, + stmtColEncSetting); // date for (int i = 1; i <= 3; i++) { @@ -2238,12 +2232,14 @@ private void createOutputProcedureDate() throws SQLException { + "') and OBJECTPROPERTY(id, N'IsProcedure') = 1)" + " DROP PROCEDURE " + outputProcedureDate; stmt.execute(sql); - sql = "CREATE PROCEDURE " + outputProcedureDate + " @p0 date OUTPUT, @p01 date OUTPUT, @p1 datetime2 OUTPUT, @p11 datetime2 OUTPUT," + sql = "CREATE PROCEDURE " + outputProcedureDate + + " @p0 date OUTPUT, @p01 date OUTPUT, @p1 datetime2 OUTPUT, @p11 datetime2 OUTPUT," + " @p2 datetimeoffset OUTPUT, @p21 datetimeoffset OUTPUT, @p3 time OUTPUT, @p31 time OUTPUT, @p4 datetime OUTPUT, @p41 datetime OUTPUT," + " @p5 smalldatetime OUTPUT, @p51 smalldatetime OUTPUT, @p6 datetime2(2) OUTPUT, @p61 datetime2(2) OUTPUT, @p7 time(2) OUTPUT, @p71 time(2) OUTPUT, " + " @p8 datetimeoffset(2) OUTPUT, @p81 datetimeoffset(2) OUTPUT " + " AS" + " SELECT top 1 @p0=PlainDate,@p01=RandomizedDate,@p1=PlainDatetime2Default,@p11=RandomizedDatetime2Default," - + " @p2=PlainDatetimeoffsetDefault,@p21=DeterministicDatetimeoffsetDefault," + " @p3=PlainTimeDefault,@p31=DeterministicTimeDefault," + + " @p2=PlainDatetimeoffsetDefault,@p21=DeterministicDatetimeoffsetDefault," + + " @p3=PlainTimeDefault,@p31=DeterministicTimeDefault," + " @p4=PlainDateTime,@p41=DeterministicDateTime, @p5=PlainSmallDateTime,@p51=RandomizedSmallDateTime, " + " @p6=PlainDatetime2,@p61=RandomizedDatetime2, @p7=PlainTime,@p71=Deterministictime, " + " @p8=PlainDatetimeoffset, @p81=RandomizedDatetimeoffset" + " FROM " + dateTable; @@ -2253,7 +2249,8 @@ private void createOutputProcedureDate() throws SQLException { private void testOutputProcedureDateInorder(String sql) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.registerOutParameter(1, java.sql.Types.DATE); callableStatement.registerOutParameter(2, java.sql.Types.DATE); callableStatement.registerOutParameter(3, java.sql.Types.TIMESTAMP); @@ -2274,30 +2271,38 @@ private void testOutputProcedureDateInorder(String sql) throws SQLException { callableStatement.registerOutParameter(18, microsoft.sql.Types.DATETIMEOFFSET, 2); callableStatement.execute(); - assertEquals(callableStatement.getDate(1), callableStatement.getDate(2), TestResource.getResource("R_outputParamFailed")); + assertEquals(callableStatement.getDate(1), callableStatement.getDate(2), + TestResource.getResource("R_outputParamFailed")); - assertEquals(callableStatement.getTimestamp(3), callableStatement.getTimestamp(4), TestResource.getResource("R_outputParamFailed")); + assertEquals(callableStatement.getTimestamp(3), callableStatement.getTimestamp(4), + TestResource.getResource("R_outputParamFailed")); - assertEquals(callableStatement.getDateTimeOffset(5), callableStatement.getDateTimeOffset(6), TestResource.getResource("R_outputParamFailed")); + assertEquals(callableStatement.getDateTimeOffset(5), callableStatement.getDateTimeOffset(6), + TestResource.getResource("R_outputParamFailed")); - assertEquals(callableStatement.getTime(7), callableStatement.getTime(8), TestResource.getResource("R_outputParamFailed")); + assertEquals(callableStatement.getTime(7), callableStatement.getTime(8), + TestResource.getResource("R_outputParamFailed")); assertEquals(callableStatement.getDateTime(9), // actual plain callableStatement.getDateTime(10), // received expected enc TestResource.getResource("R_outputParamFailed")); - assertEquals(callableStatement.getSmallDateTime(11), callableStatement.getSmallDateTime(12), TestResource.getResource("R_outputParamFailed")); - assertEquals(callableStatement.getTimestamp(13), callableStatement.getTimestamp(14), TestResource.getResource("R_outputParamFailed")); - assertEquals(callableStatement.getTime(15).getTime(), callableStatement.getTime(16).getTime(), TestResource.getResource("R_outputParamFailed")); - assertEquals(callableStatement.getDateTimeOffset(17), callableStatement.getDateTimeOffset(18), TestResource.getResource("R_outputParamFailed")); + assertEquals(callableStatement.getSmallDateTime(11), callableStatement.getSmallDateTime(12), + TestResource.getResource("R_outputParamFailed")); + assertEquals(callableStatement.getTimestamp(13), callableStatement.getTimestamp(14), + TestResource.getResource("R_outputParamFailed")); + assertEquals(callableStatement.getTime(15).getTime(), callableStatement.getTime(16).getTime(), + TestResource.getResource("R_outputParamFailed")); + assertEquals(callableStatement.getDateTimeOffset(17), callableStatement.getDateTimeOffset(18), + TestResource.getResource("R_outputParamFailed")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } private void testOutputProcedureDateInorderObject(String sql) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.registerOutParameter(1, java.sql.Types.DATE); callableStatement.registerOutParameter(2, java.sql.Types.DATE); callableStatement.registerOutParameter(3, java.sql.Types.TIMESTAMP); @@ -2318,23 +2323,30 @@ private void testOutputProcedureDateInorderObject(String sql) throws SQLExceptio callableStatement.registerOutParameter(18, microsoft.sql.Types.DATETIMEOFFSET, 2); callableStatement.execute(); - assertEquals(callableStatement.getObject(1), callableStatement.getObject(2), TestResource.getResource("R_outputParamFailed")); + assertEquals(callableStatement.getObject(1), callableStatement.getObject(2), + TestResource.getResource("R_outputParamFailed")); - assertEquals(callableStatement.getObject(3), callableStatement.getObject(4), TestResource.getResource("R_outputParamFailed")); + assertEquals(callableStatement.getObject(3), callableStatement.getObject(4), + TestResource.getResource("R_outputParamFailed")); - assertEquals(callableStatement.getObject(5), callableStatement.getObject(6), TestResource.getResource("R_outputParamFailed")); + assertEquals(callableStatement.getObject(5), callableStatement.getObject(6), + TestResource.getResource("R_outputParamFailed")); - assertEquals(callableStatement.getObject(7), callableStatement.getObject(8), TestResource.getResource("R_outputParamFailed")); + assertEquals(callableStatement.getObject(7), callableStatement.getObject(8), + TestResource.getResource("R_outputParamFailed")); assertEquals(callableStatement.getObject(9), // actual plain callableStatement.getObject(10), // received expected enc TestResource.getResource("R_outputParamFailed")); - assertEquals(callableStatement.getObject(11), callableStatement.getObject(12), TestResource.getResource("R_outputParamFailed")); - assertEquals(callableStatement.getObject(13), callableStatement.getObject(14), TestResource.getResource("R_outputParamFailed")); - assertEquals(callableStatement.getObject(15), callableStatement.getObject(16), TestResource.getResource("R_outputParamFailed")); - assertEquals(callableStatement.getObject(17), callableStatement.getObject(18), TestResource.getResource("R_outputParamFailed")); + assertEquals(callableStatement.getObject(11), callableStatement.getObject(12), + TestResource.getResource("R_outputParamFailed")); + assertEquals(callableStatement.getObject(13), callableStatement.getObject(14), + TestResource.getResource("R_outputParamFailed")); + assertEquals(callableStatement.getObject(15), callableStatement.getObject(16), + TestResource.getResource("R_outputParamFailed")); + assertEquals(callableStatement.getObject(17), callableStatement.getObject(18), + TestResource.getResource("R_outputParamFailed")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } @@ -2346,16 +2358,19 @@ private void createOutputProcedureBatch() throws SQLException { // If a procedure contains more than one SQL statement, it is considered // to be a batch of SQL statements. - sql = "CREATE PROCEDURE " + outputProcedureBatch + " @p0 int OUTPUT, @p1 float OUTPUT, @p2 smallint OUTPUT, @p3 smallmoney OUTPUT " + " AS" - + " select top 1 @p0=RandomizedInt FROM " + table3 + " select top 1 @p1=DeterministicFloatDefault FROM " + table3 - + " select top 1 @p2=RandomizedSmallint FROM " + table3 + " select top 1 @p3=DeterministicSmallMoney FROM " + table3; + sql = "CREATE PROCEDURE " + outputProcedureBatch + + " @p0 int OUTPUT, @p1 float OUTPUT, @p2 smallint OUTPUT, @p3 smallmoney OUTPUT " + " AS" + + " select top 1 @p0=RandomizedInt FROM " + table3 + " select top 1 @p1=DeterministicFloatDefault FROM " + + table3 + " select top 1 @p2=RandomizedSmallint FROM " + table3 + + " select top 1 @p3=DeterministicSmallMoney FROM " + table3; stmt.execute(sql); } private void testOutputProcedureBatchInorder(String sql) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.registerOutParameter(1, java.sql.Types.INTEGER); callableStatement.registerOutParameter(2, java.sql.Types.DOUBLE); @@ -2374,8 +2389,7 @@ private void testOutputProcedureBatchInorder(String sql) throws SQLException { BigDecimal smallmoneyValue = callableStatement.getSmallMoney(4); assertEquals("" + smallmoneyValue, numericValues[12], TestResource.getResource("R_outputParamFailed")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } @@ -2387,8 +2401,9 @@ private void createOutputProcedure4() throws SQLException { sql = "create procedure " + outputProcedure4 + " @in1 int, @in2 smallint, @in3 bigint, @in4 int, @in5 smallint, @in6 bigint, @out1 int output, @out2 smallint output, @out3 bigint output, @out4 int output, @out5 smallint output, @out6 bigint output" - + " as " + " insert into " + table5 + " values (@in1, @in2, @in3)" + " insert into " + table6 + " values (@in4, @in5, @in6)" - + " select * from " + table5 + " select * from " + table6 + " select @out1 = c1, @out2=c2, @out3=c3 from " + table5 + + " as " + " insert into " + table5 + " values (@in1, @in2, @in3)" + " insert into " + table6 + + " values (@in4, @in5, @in6)" + " select * from " + table5 + " select * from " + table6 + + " select @out1 = c1, @out2=c2, @out3=c3 from " + table5 + " select @out4 = c1, @out5=c2, @out6=c3 from " + table6; stmt.execute(sql); @@ -2400,7 +2415,8 @@ private void createMixedProcedureDateScale() throws SQLException { stmt.execute(sql); sql = "CREATE PROCEDURE " + MixedProcedureDateScale + " @p1 datetime2(2) OUTPUT, @p2 datetime2(2) OUTPUT," - + " @p3 time(2) OUTPUT, @p4 time(2) OUTPUT, @p5 datetimeoffset(2) OUTPUT, @p6 datetimeoffset(2) OUTPUT " + " AS" + + " @p3 time(2) OUTPUT, @p4 time(2) OUTPUT, @p5 datetimeoffset(2) OUTPUT, @p6 datetimeoffset(2) OUTPUT " + + " AS" + " SELECT top 1 @p1=DeterministicDatetime2,@p2=RandomizedDatetime2,@p3=DeterministicTime,@p4=RandomizedTime," + " @p5=DeterministicDatetimeoffset,@p6=RandomizedDatetimeoffset " + " FROM " + scaleDateTable + " where DeterministicDatetime2 = @p1 and DeterministicTime = @p3 and DeterministicDatetimeoffset=@p5"; @@ -2410,7 +2426,8 @@ private void createMixedProcedureDateScale() throws SQLException { private void testMixedProcedureDateScaleInorder(String sql) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.registerOutParameter(1, java.sql.Types.TIMESTAMP, 2); callableStatement.registerOutParameter(2, java.sql.Types.TIMESTAMP, 2); callableStatement.registerOutParameter(3, java.sql.Types.TIME, 2); @@ -2422,21 +2439,24 @@ private void testMixedProcedureDateScaleInorder(String sql) throws SQLException callableStatement.setDateTimeOffset(5, (DateTimeOffset) dateValues.get(6), 2); callableStatement.execute(); - assertEquals(callableStatement.getTimestamp(1), callableStatement.getTimestamp(2), TestResource.getResource("R_outputParamFailed")); + assertEquals(callableStatement.getTimestamp(1), callableStatement.getTimestamp(2), + TestResource.getResource("R_outputParamFailed")); - assertEquals(callableStatement.getTime(3), callableStatement.getTime(4), TestResource.getResource("R_outputParamFailed")); + assertEquals(callableStatement.getTime(3), callableStatement.getTime(4), + TestResource.getResource("R_outputParamFailed")); - assertEquals(callableStatement.getDateTimeOffset(5), callableStatement.getDateTimeOffset(6), TestResource.getResource("R_outputParamFailed")); + assertEquals(callableStatement.getDateTimeOffset(5), callableStatement.getDateTimeOffset(6), + TestResource.getResource("R_outputParamFailed")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } private void testMixedProcedureDateScaleWithParameterName(String sql) throws SQLException { - try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, stmtColEncSetting)) { + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) Util.getCallableStmt(con, sql, + stmtColEncSetting)) { callableStatement.registerOutParameter("p1", java.sql.Types.TIMESTAMP, 2); callableStatement.registerOutParameter("p2", java.sql.Types.TIMESTAMP, 2); callableStatement.registerOutParameter("p3", java.sql.Types.TIME, 2); @@ -2448,14 +2468,16 @@ private void testMixedProcedureDateScaleWithParameterName(String sql) throws SQL callableStatement.setDateTimeOffset("p5", (DateTimeOffset) dateValues.get(6), 2); callableStatement.execute(); - assertEquals(callableStatement.getTimestamp(1), callableStatement.getTimestamp(2), TestResource.getResource("R_outputParamFailed")); + assertEquals(callableStatement.getTimestamp(1), callableStatement.getTimestamp(2), + TestResource.getResource("R_outputParamFailed")); - assertEquals(callableStatement.getTime(3), callableStatement.getTime(4), TestResource.getResource("R_outputParamFailed")); + assertEquals(callableStatement.getTime(3), callableStatement.getTime(4), + TestResource.getResource("R_outputParamFailed")); - assertEquals(callableStatement.getDateTimeOffset(5), callableStatement.getDateTimeOffset(6), TestResource.getResource("R_outputParamFailed")); + assertEquals(callableStatement.getDateTimeOffset(5), callableStatement.getDateTimeOffset(6), + TestResource.getResource("R_outputParamFailed")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } 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 36ec08da9..5c0fe7d6b 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/JDBCEncryptionDecryptionTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/JDBCEncryptionDecryptionTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.AlwaysEncrypted; @@ -27,6 +24,7 @@ import com.microsoft.sqlserver.testframework.util.RandomData; import com.microsoft.sqlserver.testframework.util.Util; + /** * Tests Decryption and encryption of values * @@ -411,12 +409,14 @@ public void testNumericSetObjectWithJDBCTypes() 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"}; + 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(stmt); createNumericTable(); @@ -432,12 +432,14 @@ public void testNumericSpecificSetterMaxValue() 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"}; + 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(stmt); createNumericTable(); @@ -499,10 +501,12 @@ public void testNumericSpecificSetterSetObjectNull() 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"}; + 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(stmt); createNumericTable(); populateNumericNormalCase(numericValuesNormalization); @@ -510,54 +514,53 @@ public void testNumericNormalization() throws SQLException { testNumeric(null, numericValuesNormalization2, false); } - private void testChar(SQLServerStatement stmt, - String[] values) throws SQLException { + private void testChar(SQLServerStatement stmt, String[] values) throws SQLException { String sql = "select * from " + charTable; - try(SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting)) { - try(ResultSet rs = (stmt == null) ? pstmt.executeQuery() : stmt.executeQuery(sql)) { - int numberOfColumns = rs.getMetaData().getColumnCount(); - while (rs.next()) { - testGetString(rs, numberOfColumns, values); - testGetObject(rs, numberOfColumns, values); - } - } + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, + stmtColEncSetting)) { + try (ResultSet rs = (stmt == null) ? pstmt.executeQuery() : stmt.executeQuery(sql)) { + int numberOfColumns = rs.getMetaData().getColumnCount(); + while (rs.next()) { + testGetString(rs, numberOfColumns, values); + testGetObject(rs, numberOfColumns, values); + } + } } } - private void testBinary(SQLServerStatement stmt, - LinkedList values) throws SQLException { + private void testBinary(SQLServerStatement stmt, LinkedList values) throws SQLException { String sql = "select * from " + binaryTable; - try(SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting)) { - try(ResultSet rs = (stmt == null) ? pstmt.executeQuery() : stmt.executeQuery(sql)) { - int numberOfColumns = rs.getMetaData().getColumnCount(); - while (rs.next()) { - testGetStringForBinary(rs, numberOfColumns, values); - testGetBytes(rs, numberOfColumns, values); - testGetObjectForBinary(rs, numberOfColumns, values); - } - } + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, + stmtColEncSetting)) { + try (ResultSet rs = (stmt == null) ? pstmt.executeQuery() : stmt.executeQuery(sql)) { + int numberOfColumns = rs.getMetaData().getColumnCount(); + while (rs.next()) { + testGetStringForBinary(rs, numberOfColumns, values); + testGetBytes(rs, numberOfColumns, values); + testGetObjectForBinary(rs, numberOfColumns, values); + } + } } } - private void testDate(SQLServerStatement stmt, - LinkedList values1) throws SQLException { + private void testDate(SQLServerStatement stmt, LinkedList values1) throws SQLException { String sql = "select * from " + dateTable; - try(SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting)) { - try(ResultSet rs = (stmt == null) ? pstmt.executeQuery() : 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); - } - } + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, + stmtColEncSetting)) { + try (ResultSet rs = (stmt == null) ? pstmt.executeQuery() : 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); + } + } } } - private void testGetObject(ResultSet rs, - int numberOfColumns, - String[] values) throws SQLException { + private void testGetObject(ResultSet rs, int numberOfColumns, String[] values) throws SQLException { int index = 0; for (int i = 1; i <= numberOfColumns; i = i + 3) { try { @@ -565,26 +568,27 @@ private void testGetObject(ResultSet rs, String objectValue2 = ("" + rs.getObject(i + 1)).trim(); String objectValue3 = ("" + rs.getObject(i + 2)).trim(); - boolean matches = objectValue1.equalsIgnoreCase("" + values[index]) && objectValue2.equalsIgnoreCase("" + values[index]) + boolean matches = objectValue1.equalsIgnoreCase("" + values[index]) + && objectValue2.equalsIgnoreCase("" + values[index]) && objectValue3.equalsIgnoreCase("" + values[index]); if (("" + values[index]).length() >= 1000) { - assertTrue(matches, TestResource.getResource("R_decryptionFailed") + "getObject(): " + i + ", " + (i + 1) + ", " + (i + 2) - + ".\n" + TestResource.getResource("R_expectedValueAtIndex") + index); - } - else { - assertTrue(matches, TestResource.getResource("R_decryptionFailed") + "getObject(): " + objectValue1 + ", " + objectValue2 + ", " + objectValue3 - + ".\n" + TestResource.getResource("R_expectedValue") + values[index]); + assertTrue(matches, + TestResource.getResource("R_decryptionFailed") + "getObject(): " + i + ", " + (i + 1) + ", " + + (i + 2) + ".\n" + TestResource.getResource("R_expectedValueAtIndex") + index); + } else { + assertTrue(matches, + TestResource.getResource("R_decryptionFailed") + "getObject(): " + objectValue1 + ", " + + objectValue2 + ", " + objectValue3 + ".\n" + + TestResource.getResource("R_expectedValue") + values[index]); } - } - finally { + } finally { index++; } } } - private void testGetObjectForTemporal(ResultSet rs, - int numberOfColumns, + private void testGetObjectForTemporal(ResultSet rs, int numberOfColumns, LinkedList values) throws SQLException { int index = 0; for (int i = 1; i <= numberOfColumns; i = i + 3) { @@ -596,26 +600,24 @@ private void testGetObjectForTemporal(ResultSet rs, Object expected = null; if (rs.getMetaData().getColumnTypeName(i).equalsIgnoreCase("smalldatetime")) { expected = Util.roundSmallDateTimeValue(values.get(index)); - } - else if (rs.getMetaData().getColumnTypeName(i).equalsIgnoreCase("datetime")) { + } else if (rs.getMetaData().getColumnTypeName(i).equalsIgnoreCase("datetime")) { expected = Util.roundDatetimeValue(values.get(index)); - } - else { + } else { expected = values.get(index); } assertTrue( objectValue1.equalsIgnoreCase("" + expected) && objectValue2.equalsIgnoreCase("" + expected) && objectValue3.equalsIgnoreCase("" + expected), - TestResource.getResource("R_decryptionFailed") + "getObject(): " + objectValue1 + ", " + objectValue2 + ", " + objectValue3 + ".\n" + TestResource.getResource("R_expectedValue") + expected); - } - finally { + TestResource.getResource("R_decryptionFailed") + "getObject(): " + objectValue1 + ", " + + objectValue2 + ", " + objectValue3 + ".\n" + + TestResource.getResource("R_expectedValue") + expected); + } finally { index++; } } } - private void testGetObjectForBinary(ResultSet rs, - int numberOfColumns, + private void testGetObjectForBinary(ResultSet rs, int numberOfColumns, LinkedList values) throws SQLException { int index = 0; for (int i = 1; i <= numberOfColumns; i = i + 3) { @@ -632,20 +634,20 @@ private void testGetObjectForBinary(ResultSet rs, 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], - TestResource.getResource("R_decryptionFailed") + "getObject(): " + objectValue1 + ", " + objectValue2 + ", " + objectValue3 + ".\n"); + assertTrue( + expectedBytes[j] == objectValue1[j] && expectedBytes[j] == objectValue2[j] + && expectedBytes[j] == objectValue3[j], + TestResource.getResource("R_decryptionFailed") + "getObject(): " + objectValue1 + ", " + + objectValue2 + ", " + objectValue3 + ".\n"); } } - } - finally { + } finally { index++; } } } - private void testGetBigDecimal(ResultSet rs, - int numberOfColumns, - String[] values) throws SQLException { + private void testGetBigDecimal(ResultSet rs, int numberOfColumns, String[] values) throws SQLException { int index = 0; for (int i = 1; i <= numberOfColumns; i = i + 3) { @@ -654,12 +656,13 @@ private void testGetBigDecimal(ResultSet rs, String decimalValue2 = "" + rs.getBigDecimal(i + 1); String decimalValue3 = "" + rs.getBigDecimal(i + 2); - if (decimalValue1.equalsIgnoreCase("0") && (values[index].equalsIgnoreCase("true") || values[index].equalsIgnoreCase("false"))) { + 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"))) { + } else if (decimalValue1.equalsIgnoreCase("1") + && (values[index].equalsIgnoreCase("true") || values[index].equalsIgnoreCase("false"))) { decimalValue1 = "true"; decimalValue2 = "true"; decimalValue3 = "true"; @@ -668,35 +671,32 @@ else if (decimalValue1.equalsIgnoreCase("1") && (values[index].equalsIgnoreCase( if (null != values[index]) { if (values[index].equalsIgnoreCase("1.79E308")) { values[index] = "1.79E+308"; - } - else if (values[index].equalsIgnoreCase("3.4E38")) { + } 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")) { + } else if (values[index].equalsIgnoreCase("-3.4E38")) { values[index] = "-3.4E+38"; } } try { assertTrue( - decimalValue1.equalsIgnoreCase("" + values[index]) && decimalValue2.equalsIgnoreCase("" + values[index]) + decimalValue1.equalsIgnoreCase("" + values[index]) + && decimalValue2.equalsIgnoreCase("" + values[index]) && decimalValue3.equalsIgnoreCase("" + values[index]), - TestResource.getResource("R_decryptionFailed") + "getBigDecimal(): " + decimalValue1 + ", " + decimalValue2 + ", " + decimalValue3 - + ".\n" + TestResource.getResource("R_expectedValue") + values[index]); - } - finally { + TestResource.getResource("R_decryptionFailed") + "getBigDecimal(): " + decimalValue1 + ", " + + decimalValue2 + ", " + decimalValue3 + ".\n" + + TestResource.getResource("R_expectedValue") + values[index]); + } finally { index++; } } } - private void testGetString(ResultSet rs, - int numberOfColumns, - String[] values) throws SQLException { + private void testGetString(ResultSet rs, int numberOfColumns, String[] values) throws SQLException { int index = 0; for (int i = 1; i <= numberOfColumns; i = i + 3) { @@ -704,31 +704,33 @@ private void testGetString(ResultSet rs, 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"))) { + 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"))) { + } 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]) + boolean matches = stringValue1.equalsIgnoreCase("" + values[index]) + && stringValue2.equalsIgnoreCase("" + values[index]) && stringValue3.equalsIgnoreCase("" + values[index]); if (("" + values[index]).length() >= 1000) { - assertTrue(matches, TestResource.getResource("R_decryptionFailed") + "getString():" + i + ", " + (i + 1) + ", " + (i + 2) - + ".\n" + TestResource.getResource("R_expectedValue") + index); - } - else { - assertTrue(matches, TestResource.getResource("R_decryptionFailed") + "getString(): " + stringValue1 + ", " + stringValue2 + ", " + stringValue3 - + ".\n" + TestResource.getResource("R_expectedValue") + values[index]); + assertTrue(matches, TestResource.getResource("R_decryptionFailed") + "getString():" + i + ", " + + (i + 1) + ", " + (i + 2) + ".\n" + TestResource.getResource("R_expectedValue") + index); + } else { + assertTrue(matches, + TestResource.getResource("R_decryptionFailed") + "getString(): " + stringValue1 + ", " + + stringValue2 + ", " + stringValue3 + ".\n" + + TestResource.getResource("R_expectedValue") + values[index]); } - } - finally { + } finally { index++; } } @@ -736,8 +738,7 @@ else if (stringValue1.equalsIgnoreCase("1") && (values[index].equalsIgnoreCase(" // not testing this for now. @SuppressWarnings("unused") - private void testGetStringForDate(ResultSet rs, - int numberOfColumns, + private void testGetStringForDate(ResultSet rs, int numberOfColumns, LinkedList values) throws SQLException { int index = 0; @@ -749,46 +750,48 @@ private void testGetStringForDate(ResultSet rs, try { if (index == 3) { assertTrue( - stringValue1.contains("" + values.get(index)) && stringValue2.contains("" + values.get(index)) + stringValue1.contains("" + values.get(index)) + && stringValue2.contains("" + values.get(index)) && stringValue3.contains("" + values.get(index)), - TestResource.getResource("R_decryptionFailed") + "getString(): " + stringValue1 + ", " + stringValue2 + ", " + stringValue3 - + ".\n" + TestResource.getResource("R_expectedValue") + values.get(index)); - } - else if (index == 4) // round value for datetime + TestResource.getResource("R_decryptionFailed") + "getString(): " + stringValue1 + ", " + + stringValue2 + ", " + stringValue3 + ".\n" + + TestResource.getResource("R_expectedValue") + 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) + stringValue1.equalsIgnoreCase("" + datetimeValue) + && stringValue2.equalsIgnoreCase("" + datetimeValue) && stringValue3.equalsIgnoreCase("" + datetimeValue), - TestResource.getResource("R_decryptionFailed") + "getString(): " + stringValue1 + ", " + stringValue2 + ", " + stringValue3 - + ".\n" + TestResource.getResource("R_expectedValue") + datetimeValue); - } - else if (index == 5) // round value for smalldatetime + TestResource.getResource("R_decryptionFailed") + "getString(): " + stringValue1 + ", " + + stringValue2 + ", " + stringValue3 + ".\n" + + TestResource.getResource("R_expectedValue") + datetimeValue); + } else if (index == 5) // round value for smalldatetime { Object smalldatetimeValue = "" + Util.roundSmallDateTimeValue(values.get(index)); assertTrue( - stringValue1.equalsIgnoreCase("" + smalldatetimeValue) && stringValue2.equalsIgnoreCase("" + smalldatetimeValue) + stringValue1.equalsIgnoreCase("" + smalldatetimeValue) + && stringValue2.equalsIgnoreCase("" + smalldatetimeValue) && stringValue3.equalsIgnoreCase("" + smalldatetimeValue), - TestResource.getResource("R_decryptionFailed") + "getString(): " + stringValue1 + ", " + stringValue2 + ", " + stringValue3 - + ".\n" + TestResource.getResource("R_expectedValue") + smalldatetimeValue); - } - else { + TestResource.getResource("R_decryptionFailed") + "getString(): " + stringValue1 + ", " + + stringValue2 + ", " + stringValue3 + ".\n" + + TestResource.getResource("R_expectedValue") + smalldatetimeValue); + } else { assertTrue( - stringValue1.contains("" + values.get(index)) && stringValue2.contains("" + values.get(index)) + stringValue1.contains("" + values.get(index)) + && stringValue2.contains("" + values.get(index)) && stringValue3.contains("" + values.get(index)), - TestResource.getResource("R_decryptionFailed") + "getString(): " + stringValue1 + ", " + stringValue2 + ", " + stringValue3 - + ".\n" + TestResource.getResource("R_expectedValue") + values.get(index)); + TestResource.getResource("R_decryptionFailed") + "getString(): " + stringValue1 + ", " + + stringValue2 + ", " + stringValue3 + ".\n" + + TestResource.getResource("R_expectedValue") + values.get(index)); } - } - finally { + } finally { index++; } } } - private void testGetBytes(ResultSet rs, - int numberOfColumns, - LinkedList values) throws SQLException { + 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); @@ -805,18 +808,17 @@ private void testGetBytes(ResultSet rs, 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], - TestResource.getResource("R_decryptionFailed") + "getObject(): " + b1 + ", " + b2 + ", " + b3 + ".\n"); + TestResource.getResource("R_decryptionFailed") + "getObject(): " + b1 + ", " + b2 + ", " + + b3 + ".\n"); } } - } - finally { + } finally { index++; } } } - private void testGetStringForBinary(ResultSet rs, - int numberOfColumns, + private void testGetStringForBinary(ResultSet rs, int numberOfColumns, LinkedList values) throws SQLException { int index = 0; @@ -833,25 +835,24 @@ private void testGetStringForBinary(ResultSet rs, expected.append(String.format("%02X", b)); } expectedStr = "" + expected.toString(); - } - else { + } else { expectedStr = "null"; } try { - assertTrue(stringValue1.startsWith(expectedStr) && stringValue2.startsWith(expectedStr) && stringValue3.startsWith(expectedStr), - TestResource.getResource("R_decryptionFailed") + "getString(): " + stringValue1 + ", " + stringValue2 + ", " + stringValue3 + ".\n" + TestResource.getResource("R_expectedValue") - + expectedStr); - } - finally { + assertTrue( + stringValue1.startsWith(expectedStr) && stringValue2.startsWith(expectedStr) + && stringValue3.startsWith(expectedStr), + TestResource.getResource("R_decryptionFailed") + "getString(): " + stringValue1 + ", " + + stringValue2 + ", " + stringValue3 + ".\n" + + TestResource.getResource("R_expectedValue") + expectedStr); + } finally { index++; } } } - private void testGetDate(ResultSet rs, - int numberOfColumns, - LinkedList values) throws SQLException { + private void testGetDate(ResultSet rs, int numberOfColumns, LinkedList values) throws SQLException { for (int i = 1; i <= numberOfColumns; i = i + 3) { if (rs instanceof SQLServerResultSet) { @@ -910,9 +911,11 @@ private void testGetDate(ResultSet rs, } assertTrue( - stringValue1.equalsIgnoreCase(expected) && stringValue2.equalsIgnoreCase(expected) && stringValue3.equalsIgnoreCase(expected), - TestResource.getResource("R_decryptionFailed") + "testGetDate: " + stringValue1 + ", " + stringValue2 + ", " + stringValue3 + ".\n" + TestResource.getResource("R_expectedValue") - + expected); + stringValue1.equalsIgnoreCase(expected) && stringValue2.equalsIgnoreCase(expected) + && stringValue3.equalsIgnoreCase(expected), + TestResource.getResource("R_decryptionFailed") + "testGetDate: " + stringValue1 + ", " + + stringValue2 + ", " + stringValue3 + ".\n" + + TestResource.getResource("R_expectedValue") + expected); } else { @@ -921,30 +924,30 @@ private void testGetDate(ResultSet rs, } } - private void testNumeric(Statement stmt, - String[] numericValues, - boolean isNull) throws SQLException { + private void testNumeric(Statement stmt, String[] numericValues, boolean isNull) throws SQLException { String sql = "select * from " + numericTable; - try(SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting)) { - try(SQLServerResultSet rs = (stmt == null) ? (SQLServerResultSet) pstmt.executeQuery() : (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); - } - } - } + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, + stmtColEncSetting)) { + try (SQLServerResultSet rs = (stmt == null) ? (SQLServerResultSet) pstmt.executeQuery() + : (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); + } + } + } } } - private void testWithSpecifiedtype(SQLServerResultSet rs, - int numberOfColumns, + private void testWithSpecifiedtype(SQLServerResultSet rs, int numberOfColumns, String[] values) throws SQLException { String value1, value2, value3, expectedValue = null; @@ -1095,23 +1098,18 @@ private void testWithSpecifiedtype(SQLServerResultSet rs, index++; } - private void Compare(String expectedValue, - String value1, - String value2, - String value3) { + 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")) { + } 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")) { + } else if (expectedValue.equalsIgnoreCase("-3.4E+38")) { expectedValue = "-3.4E38"; } } @@ -1119,7 +1117,8 @@ else if (expectedValue.equalsIgnoreCase("-3.4E+38")) { assertTrue( value1.equalsIgnoreCase("" + expectedValue) && value2.equalsIgnoreCase("" + expectedValue) && value3.equalsIgnoreCase("" + expectedValue), - TestResource.getResource("R_decryptionFailed") + "getBigDecimal(): " + value1 + ", " + value2+ ", " + value3 + ".\n" + TestResource.getResource("R_expectedValue")); + TestResource.getResource("R_decryptionFailed") + "getBigDecimal(): " + value1 + ", " + value2 + ", " + + value3 + ".\n" + TestResource.getResource("R_expectedValue")); } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/PrecisionScaleTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/PrecisionScaleTest.java index 0a28036f9..36ccd8848 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/PrecisionScaleTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/PrecisionScaleTest.java @@ -1,14 +1,10 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.AlwaysEncrypted; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; import java.math.BigDecimal; import java.sql.ResultSet; @@ -29,6 +25,7 @@ import com.microsoft.sqlserver.jdbc.TestResource; import com.microsoft.sqlserver.testframework.util.Util; + /** * Tests datatypes that have precision and/or scale. * @@ -48,8 +45,10 @@ public class PrecisionScaleTest extends AESetup { TimeZone tz = TimeZone.getDefault(); offsetFromGMT = tz.getOffset(1450812362177L); - // since the Date object already accounts for timezone, subtracting the timezone difference will always give us the - // GMT version of the Date object. I can't make this PST because there are datetimeoffset tests, so I have to use GMT. + // since the Date object already accounts for timezone, subtracting the timezone difference will always give us + // the + // GMT version of the Date object. I can't make this PST because there are datetimeoffset tests, so I have to + // use GMT. date = new Date(1450812362177L - offsetFromGMT); // Cannot use date.toGMTString() here directly since the date object is used elsewhere for population of data. @@ -78,10 +77,11 @@ public void testNumericPrecision8Scale2() throws Exception { public void testDateScale2() throws Exception { dropTables(stmt); - String[] dateNormalCase = {GMTDate + ".18", GMTDate + ".1770000", dateTimeOffsetExpectedValue + ".1770000 +00:01", - GMTDateWithoutDate + ".1770000", GMTDateWithoutDate + ".18", dateTimeOffsetExpectedValue + ".18 +00:01"}; - String[] dateSetObject = {GMTDate + ".18", GMTDate + ".177", dateTimeOffsetExpectedValue + ".177 +00:01", GMTDateWithoutDate, - GMTDateWithoutDate, dateTimeOffsetExpectedValue + ".18 +00:01"}; + String[] dateNormalCase = {GMTDate + ".18", GMTDate + ".1770000", + dateTimeOffsetExpectedValue + ".1770000 +00:01", GMTDateWithoutDate + ".1770000", + GMTDateWithoutDate + ".18", dateTimeOffsetExpectedValue + ".18 +00:01"}; + String[] dateSetObject = {GMTDate + ".18", GMTDate + ".177", dateTimeOffsetExpectedValue + ".177 +00:01", + GMTDateWithoutDate, GMTDateWithoutDate, dateTimeOffsetExpectedValue + ".18 +00:01"}; createDatePrecisionTable(2); populateDateNormalCase(2); @@ -107,10 +107,10 @@ public void testNumericPrecision8Scale0() throws Exception { public void testDateScale0() throws Exception { dropTables(stmt); - String[] dateNormalCase2 = {GMTDate, GMTDate + ".1770000", dateTimeOffsetExpectedValue + ".1770000 +00:01", GMTDateWithoutDate + ".1770000", - GMTDateWithoutDate, dateTimeOffsetExpectedValue + " +00:01"}; - String[] dateSetObject2 = {GMTDate + ".0", GMTDate + ".177", dateTimeOffsetExpectedValue + ".177 +00:01", GMTDateWithoutDate, - GMTDateWithoutDate, dateTimeOffsetExpectedValue + " +00:01"}; + String[] dateNormalCase2 = {GMTDate, GMTDate + ".1770000", dateTimeOffsetExpectedValue + ".1770000 +00:01", + GMTDateWithoutDate + ".1770000", GMTDateWithoutDate, dateTimeOffsetExpectedValue + " +00:01"}; + String[] dateSetObject2 = {GMTDate + ".0", GMTDate + ".177", dateTimeOffsetExpectedValue + ".177 +00:01", + GMTDateWithoutDate, GMTDateWithoutDate, dateTimeOffsetExpectedValue + " +00:01"}; createDatePrecisionTable(0); populateDateNormalCase(0); @@ -156,38 +156,35 @@ public void testDateScale5Null() throws Exception { private void testNumeric(String[] numeric) throws SQLException { - try(ResultSet rs = stmt.executeQuery("select * from " + numericTable)) { - int numberOfColumns = rs.getMetaData().getColumnCount(); - - ArrayList skipMax = new ArrayList<>(); - - while (rs.next()) { - testGetString(rs, numberOfColumns, skipMax, numeric); - testGetBigDecimal(rs, numberOfColumns, numeric); - testGetObject(rs, numberOfColumns, skipMax, numeric); - } + try (ResultSet rs = stmt.executeQuery("select * from " + numericTable)) { + int numberOfColumns = rs.getMetaData().getColumnCount(); + + ArrayList skipMax = new ArrayList<>(); + + while (rs.next()) { + testGetString(rs, numberOfColumns, skipMax, numeric); + testGetBigDecimal(rs, numberOfColumns, numeric); + testGetObject(rs, numberOfColumns, skipMax, numeric); + } } } - private void testDate(String[] dateNormalCase, - String[] dateSetObject) throws Exception { - - try(ResultSet rs = stmt.executeQuery("select * from " + dateTable)) { - int numberOfColumns = rs.getMetaData().getColumnCount(); - - ArrayList skipMax = new ArrayList<>(); - - while (rs.next()) { - testGetString(rs, numberOfColumns, skipMax, dateNormalCase); - testGetObject(rs, numberOfColumns, skipMax, dateSetObject); - testGetDate(rs, numberOfColumns, dateSetObject); - } + private void testDate(String[] dateNormalCase, String[] dateSetObject) throws Exception { + + try (ResultSet rs = stmt.executeQuery("select * from " + dateTable)) { + int numberOfColumns = rs.getMetaData().getColumnCount(); + + ArrayList skipMax = new ArrayList<>(); + + while (rs.next()) { + testGetString(rs, numberOfColumns, skipMax, dateNormalCase); + testGetObject(rs, numberOfColumns, skipMax, dateSetObject); + testGetDate(rs, numberOfColumns, dateSetObject); + } } } - private void testGetString(ResultSet rs, - int numberOfColumns, - ArrayList skipMax, + private void testGetString(ResultSet rs, int numberOfColumns, ArrayList skipMax, String[] values) throws SQLException { int index = 0; for (int i = 1; i <= numberOfColumns; i = i + 3) { @@ -201,27 +198,27 @@ private void testGetString(ResultSet rs, try { if (rs.getMetaData().getColumnTypeName(i).equalsIgnoreCase("time")) { - assertTrue(stringValue2.equalsIgnoreCase("" + values[index]) && stringValue3.equalsIgnoreCase("" + values[index]), - TestResource.getResource("R_decryptionFailed") + "getString(): " + stringValue1 + ", " + stringValue2 + ", " + stringValue3 - + ".\n" + TestResource.getResource("R_expectedValue") + ": " + values[index]); - } - else { + assertTrue( + stringValue2.equalsIgnoreCase("" + values[index]) + && stringValue3.equalsIgnoreCase("" + values[index]), + TestResource.getResource("R_decryptionFailed") + "getString(): " + stringValue1 + ", " + + stringValue2 + ", " + stringValue3 + ".\n" + + TestResource.getResource("R_expectedValue") + ": " + values[index]); + } else { assertTrue( values[index].contains(stringValue1) && stringValue2.equalsIgnoreCase("" + values[index]) && stringValue3.equalsIgnoreCase("" + values[index]), - TestResource.getResource("R_decryptionFailed") + "getString(): " + stringValue1 + ", " + stringValue2 + ", " + stringValue3 - + TestResource.getResource("R_expectedValue") + values[index]); + TestResource.getResource("R_decryptionFailed") + "getString(): " + stringValue1 + ", " + + stringValue2 + ", " + stringValue3 + TestResource.getResource("R_expectedValue") + + values[index]); } - } - finally { + } finally { index++; } } } - private void testGetBigDecimal(ResultSet rs, - int numberOfColumns, - String[] values) throws SQLException { + private void testGetBigDecimal(ResultSet rs, int numberOfColumns, String[] values) throws SQLException { int index = 0; for (int i = 1; i <= numberOfColumns; i = i + 3) { @@ -233,19 +230,17 @@ private void testGetBigDecimal(ResultSet rs, assertTrue( decimalValue1.equalsIgnoreCase(values[index]) && decimalValue2.equalsIgnoreCase(values[index]) && decimalValue3.equalsIgnoreCase(values[index]), - TestResource.getResource("R_decryptionFailed") + "getBigDecimal(): " + decimalValue1 + ", " + decimalValue2 + ", " + decimalValue3 - + "\n" + TestResource.getResource("R_expectedValue") + ": " + values[index]); + TestResource.getResource("R_decryptionFailed") + "getBigDecimal(): " + decimalValue1 + ", " + + decimalValue2 + ", " + decimalValue3 + "\n" + + TestResource.getResource("R_expectedValue") + ": " + values[index]); - } - finally { + } finally { index++; } } } - private void testGetObject(ResultSet rs, - int numberOfColumns, - ArrayList skipMax, + private void testGetObject(ResultSet rs, int numberOfColumns, ArrayList skipMax, String[] values) throws SQLException { int index = 0; for (int i = 1; i <= numberOfColumns; i = i + 3) { @@ -261,19 +256,17 @@ private void testGetObject(ResultSet rs, assertTrue( objectValue1.equalsIgnoreCase(values[index]) && objectValue2.equalsIgnoreCase(values[index]) && objectValue3.equalsIgnoreCase(values[index]), - TestResource.getResource("R_decryptionFailed") + "getObject(): " + objectValue1 + ", " + objectValue2 + ", " + objectValue3 + "\n" + TestResource.getResource("R_expectedValue") + ": " - + values[index]); + TestResource.getResource("R_decryptionFailed") + "getObject(): " + objectValue1 + ", " + + objectValue2 + ", " + objectValue3 + "\n" + + TestResource.getResource("R_expectedValue") + ": " + values[index]); - } - finally { + } finally { index++; } } } - private void testGetDate(ResultSet rs, - int numberOfColumns, - String[] dates) throws Exception { + private void testGetDate(ResultSet rs, int numberOfColumns, String[] dates) throws Exception { int index = 0; for (int i = 1; i <= numberOfColumns; i = i + 3) { @@ -328,10 +321,10 @@ private void testGetDate(ResultSet rs, assertTrue( stringValue1.equalsIgnoreCase(dates[index]) && stringValue2.equalsIgnoreCase(dates[index]) && stringValue3.equalsIgnoreCase(dates[index]), - TestResource.getResource("R_decryptionFailed") + "getString(): " + stringValue1 + ", " + stringValue2 + ", " + stringValue3 + "\n" + TestResource.getResource("R_expectedValue") + ": " - + dates[index]); - } - finally { + TestResource.getResource("R_decryptionFailed") + "getString(): " + stringValue1 + ", " + + stringValue2 + ", " + stringValue3 + "\n" + + TestResource.getResource("R_expectedValue") + ": " + dates[index]); + } finally { index++; } } @@ -343,237 +336,246 @@ private void testGetDate(ResultSet rs, } private void populateDateNormalCase(int scale) throws SQLException { - String sql = "insert into " + dateTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; - - try(SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting)) { - - // datetime2(5) - for (int i = 1; i <= 3; i++) { - pstmt.setTimestamp(i, new Timestamp(date.getTime()), scale); - } - - // datetime2 default - for (int i = 4; i <= 6; i++) { - pstmt.setTimestamp(i, new Timestamp(date.getTime())); - } - - // datetimeoffset default - for (int i = 7; i <= 9; i++) { - pstmt.setDateTimeOffset(i, microsoft.sql.DateTimeOffset.valueOf(new Timestamp(date.getTime()), 1)); - } - - // time default - for (int i = 10; i <= 12; i++) { - pstmt.setTime(i, new Time(date.getTime())); - } - - // time(3) - for (int i = 13; i <= 15; i++) { - pstmt.setTime(i, new Time(date.getTime()), scale); - } - - // datetimeoffset(2) - for (int i = 16; i <= 18; i++) { - pstmt.setDateTimeOffset(i, microsoft.sql.DateTimeOffset.valueOf(new Timestamp(date.getTime()), 1), scale); - } - - pstmt.execute(); + String sql = "insert into " + dateTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?" + ")"; + + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, + stmtColEncSetting)) { + + // datetime2(5) + for (int i = 1; i <= 3; i++) { + pstmt.setTimestamp(i, new Timestamp(date.getTime()), scale); + } + + // datetime2 default + for (int i = 4; i <= 6; i++) { + pstmt.setTimestamp(i, new Timestamp(date.getTime())); + } + + // datetimeoffset default + for (int i = 7; i <= 9; i++) { + pstmt.setDateTimeOffset(i, microsoft.sql.DateTimeOffset.valueOf(new Timestamp(date.getTime()), 1)); + } + + // time default + for (int i = 10; i <= 12; i++) { + pstmt.setTime(i, new Time(date.getTime())); + } + + // time(3) + for (int i = 13; i <= 15; i++) { + pstmt.setTime(i, new Time(date.getTime()), scale); + } + + // datetimeoffset(2) + for (int i = 16; i <= 18; i++) { + pstmt.setDateTimeOffset(i, microsoft.sql.DateTimeOffset.valueOf(new Timestamp(date.getTime()), 1), + scale); + } + + pstmt.execute(); } } private void populateDateNormalCaseNull(int scale) throws SQLException { - String sql = "insert into " + dateTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; - - try(SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting)) { - - // datetime2(5) - for (int i = 1; i <= 3; i++) { - pstmt.setTimestamp(i, null, scale); - } - - // datetime2 default - for (int i = 4; i <= 6; i++) { - pstmt.setTimestamp(i, null); - } - - // datetimeoffset default - for (int i = 7; i <= 9; i++) { - pstmt.setDateTimeOffset(i, null); - } - - // time default - for (int i = 10; i <= 12; i++) { - pstmt.setTime(i, null); - } - - // time(3) - for (int i = 13; i <= 15; i++) { - pstmt.setTime(i, null, scale); - } - - // datetimeoffset(2) - for (int i = 16; i <= 18; i++) { - pstmt.setDateTimeOffset(i, null, scale); - } - - pstmt.execute(); + String sql = "insert into " + dateTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?" + ")"; + + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, + stmtColEncSetting)) { + + // datetime2(5) + for (int i = 1; i <= 3; i++) { + pstmt.setTimestamp(i, null, scale); + } + + // datetime2 default + for (int i = 4; i <= 6; i++) { + pstmt.setTimestamp(i, null); + } + + // datetimeoffset default + for (int i = 7; i <= 9; i++) { + pstmt.setDateTimeOffset(i, null); + } + + // time default + for (int i = 10; i <= 12; i++) { + pstmt.setTime(i, null); + } + + // time(3) + for (int i = 13; i <= 15; i++) { + pstmt.setTime(i, null, scale); + } + + // datetimeoffset(2) + for (int i = 16; i <= 18; i++) { + pstmt.setDateTimeOffset(i, null, scale); + } + + pstmt.execute(); } } - private void populateNumericNormalCase(String[] numeric, - int precision, - int scale) throws SQLException { + private void populateNumericNormalCase(String[] numeric, int precision, int scale) throws SQLException { String sql = "insert into " + numericTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?" + ")"; - try(SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting)) { - - // float(30) - for (int i = 1; i <= 3; i++) { - pstmt.setDouble(i, Double.valueOf(numeric[0])); - } - - // decimal(10,5) - for (int i = 4; i <= 6; i++) { - pstmt.setBigDecimal(i, new BigDecimal(numeric[1]), precision, scale); - } - - // numeric(8,2) - for (int i = 7; i <= 9; i++) { - pstmt.setBigDecimal(i, new BigDecimal(numeric[2]), precision, scale); - } - - pstmt.execute(); + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, + stmtColEncSetting)) { + + // float(30) + for (int i = 1; i <= 3; i++) { + pstmt.setDouble(i, Double.valueOf(numeric[0])); + } + + // decimal(10,5) + for (int i = 4; i <= 6; i++) { + pstmt.setBigDecimal(i, new BigDecimal(numeric[1]), precision, scale); + } + + // numeric(8,2) + for (int i = 7; i <= 9; i++) { + pstmt.setBigDecimal(i, new BigDecimal(numeric[2]), precision, scale); + } + + pstmt.execute(); } } - private void populateNumericSetObject(String[] numeric, - int precision, - int scale) throws SQLException { + private void populateNumericSetObject(String[] numeric, int precision, int scale) throws SQLException { String sql = "insert into " + numericTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?" + ")"; - try(SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting)) { - - // float(30) - for (int i = 1; i <= 3; i++) { - pstmt.setObject(i, Double.valueOf(numeric[0])); - - } - - // decimal(10,5) - for (int i = 4; i <= 6; i++) { - pstmt.setObject(i, new BigDecimal(numeric[1]), java.sql.Types.DECIMAL, precision, scale); - } - - // numeric(8,2) - for (int i = 7; i <= 9; i++) { - pstmt.setObject(i, new BigDecimal(numeric[2]), java.sql.Types.NUMERIC, precision, scale); - } - - pstmt.execute(); + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, + stmtColEncSetting)) { + + // float(30) + for (int i = 1; i <= 3; i++) { + pstmt.setObject(i, Double.valueOf(numeric[0])); + + } + + // decimal(10,5) + for (int i = 4; i <= 6; i++) { + pstmt.setObject(i, new BigDecimal(numeric[1]), java.sql.Types.DECIMAL, precision, scale); + } + + // numeric(8,2) + for (int i = 7; i <= 9; i++) { + pstmt.setObject(i, new BigDecimal(numeric[2]), java.sql.Types.NUMERIC, precision, scale); + } + + pstmt.execute(); } } - private void populateNumericSetObjectNull(int precision, - int scale) throws SQLException { + private void populateNumericSetObjectNull(int precision, int scale) throws SQLException { String sql = "insert into " + numericTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?" + ")"; - try(SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting)) { - - // float(30) - for (int i = 1; i <= 3; i++) { - pstmt.setObject(i, null, java.sql.Types.DOUBLE); - - } - - // decimal(10,5) - for (int i = 4; i <= 6; i++) { - pstmt.setObject(i, null, java.sql.Types.DECIMAL, precision, scale); - } - - // numeric(8,2) - for (int i = 7; i <= 9; i++) { - pstmt.setObject(i, null, java.sql.Types.NUMERIC, precision, scale); - } - - pstmt.execute(); + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, + stmtColEncSetting)) { + + // float(30) + for (int i = 1; i <= 3; i++) { + pstmt.setObject(i, null, java.sql.Types.DOUBLE); + + } + + // decimal(10,5) + for (int i = 4; i <= 6; i++) { + pstmt.setObject(i, null, java.sql.Types.DECIMAL, precision, scale); + } + + // numeric(8,2) + for (int i = 7; i <= 9; i++) { + pstmt.setObject(i, null, java.sql.Types.NUMERIC, precision, scale); + } + + pstmt.execute(); } } private void populateDateSetObject(int scale) throws SQLException { - String sql = "insert into " + dateTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; - - try(SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting)) { - - // datetime2(5) - for (int i = 1; i <= 3; i++) { - pstmt.setObject(i, new Timestamp(date.getTime()), java.sql.Types.TIMESTAMP, scale); - } - - // datetime2 default - for (int i = 4; i <= 6; i++) { - pstmt.setObject(i, new Timestamp(date.getTime()), java.sql.Types.TIMESTAMP); - } - - // datetimeoffset default - for (int i = 7; i <= 9; i++) { - pstmt.setObject(i, microsoft.sql.DateTimeOffset.valueOf(new Timestamp(date.getTime()), 1), microsoft.sql.Types.DATETIMEOFFSET); - } - - // time default - for (int i = 10; i <= 12; i++) { - pstmt.setObject(i, new Time(date.getTime()), java.sql.Types.TIME); - } - - // time(3) - for (int i = 13; i <= 15; i++) { - pstmt.setObject(i, new Time(date.getTime()), java.sql.Types.TIME, scale); - } - - // datetimeoffset(2) - for (int i = 16; i <= 18; i++) { - pstmt.setObject(i, microsoft.sql.DateTimeOffset.valueOf(new Timestamp(date.getTime()), 1), microsoft.sql.Types.DATETIMEOFFSET, scale); - } - - pstmt.execute(); + String sql = "insert into " + dateTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?" + ")"; + + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, + stmtColEncSetting)) { + + // datetime2(5) + for (int i = 1; i <= 3; i++) { + pstmt.setObject(i, new Timestamp(date.getTime()), java.sql.Types.TIMESTAMP, scale); + } + + // datetime2 default + for (int i = 4; i <= 6; i++) { + pstmt.setObject(i, new Timestamp(date.getTime()), java.sql.Types.TIMESTAMP); + } + + // datetimeoffset default + for (int i = 7; i <= 9; i++) { + pstmt.setObject(i, microsoft.sql.DateTimeOffset.valueOf(new Timestamp(date.getTime()), 1), + microsoft.sql.Types.DATETIMEOFFSET); + } + + // time default + for (int i = 10; i <= 12; i++) { + pstmt.setObject(i, new Time(date.getTime()), java.sql.Types.TIME); + } + + // time(3) + for (int i = 13; i <= 15; i++) { + pstmt.setObject(i, new Time(date.getTime()), java.sql.Types.TIME, scale); + } + + // datetimeoffset(2) + for (int i = 16; i <= 18; i++) { + pstmt.setObject(i, microsoft.sql.DateTimeOffset.valueOf(new Timestamp(date.getTime()), 1), + microsoft.sql.Types.DATETIMEOFFSET, scale); + } + + pstmt.execute(); } } private void populateDateSetObjectNull(int scale) throws SQLException { - String sql = "insert into " + dateTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?" + ")"; - - try(SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, stmtColEncSetting)) { - - // datetime2(5) - for (int i = 1; i <= 3; i++) { - pstmt.setObject(i, null, java.sql.Types.TIMESTAMP, scale); - } - - // datetime2 default - for (int i = 4; i <= 6; i++) { - pstmt.setObject(i, null, java.sql.Types.TIMESTAMP); - } - - // datetimeoffset default - for (int i = 7; i <= 9; i++) { - pstmt.setObject(i, null, microsoft.sql.Types.DATETIMEOFFSET); - } - - // time default - for (int i = 10; i <= 12; i++) { - pstmt.setObject(i, null, java.sql.Types.TIME); - } - - // time(3) - for (int i = 13; i <= 15; i++) { - pstmt.setObject(i, null, java.sql.Types.TIME, scale); - } - - // datetimeoffset(2) - for (int i = 16; i <= 18; i++) { - pstmt.setObject(i, null, microsoft.sql.Types.DATETIMEOFFSET, scale); - } - - pstmt.execute(); + String sql = "insert into " + dateTable + " values( " + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + "?,?,?," + + "?,?,?" + ")"; + + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) Util.getPreparedStmt(con, sql, + stmtColEncSetting)) { + + // datetime2(5) + for (int i = 1; i <= 3; i++) { + pstmt.setObject(i, null, java.sql.Types.TIMESTAMP, scale); + } + + // datetime2 default + for (int i = 4; i <= 6; i++) { + pstmt.setObject(i, null, java.sql.Types.TIMESTAMP); + } + + // datetimeoffset default + for (int i = 7; i <= 9; i++) { + pstmt.setObject(i, null, microsoft.sql.Types.DATETIMEOFFSET); + } + + // time default + for (int i = 10; i <= 12; i++) { + pstmt.setObject(i, null, java.sql.Types.TIME); + } + + // time(3) + for (int i = 13; i <= 15; i++) { + pstmt.setObject(i, null, java.sql.Types.TIME, scale); + } + + // datetimeoffset(2) + for (int i = 16; i <= 18; i++) { + pstmt.setObject(i, null, microsoft.sql.Types.DATETIMEOFFSET, scale); + } + + pstmt.execute(); } } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/JDBC43Test.java b/src/test/java/com/microsoft/sqlserver/jdbc/JDBC43Test.java index b19b45c96..9979ed6c7 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/JDBC43Test.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/JDBC43Test.java @@ -1,12 +1,12 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; +import static org.junit.Assert.assertEquals; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + import java.sql.Connection; import java.sql.Driver; import java.sql.DriverManager; @@ -26,13 +26,8 @@ import org.opentest4j.TestAbortedException; import com.microsoft.sqlserver.testframework.AbstractTest; -import com.microsoft.sqlserver.testframework.util.Util; +import com.microsoft.sqlserver.testframework.util.Util;; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; -import static org.junit.jupiter.api.Assumptions.assumeTrue; - -import com.microsoft.sqlserver.jdbc.TestResource;; /** * Tests JDBC 4.3 APIs @@ -45,8 +40,9 @@ public class JDBC43Test extends AbstractTest { /** * Tests that we are throwing the unsupported exception for connectionBuilder() - * @throws SQLException - * @throws TestAbortedException + * + * @throws SQLException + * @throws TestAbortedException * * @since 1.9 */ @@ -56,31 +52,29 @@ public void connectionBuilderTest() throws TestAbortedException, SQLException { SQLServerDataSource ds = new SQLServerDataSource(); try { superShardingKey = ds.createShardingKeyBuilder().subkey("EASTERN_REGION", JDBCType.VARCHAR).build(); - } - catch (SQLException e) { + } catch (SQLException e) { assert (e.getMessage().contains(TestResource.getResource("R_notImplemented"))); } try { shardingKey = ds.createShardingKeyBuilder().subkey("PITTSBURGH_BRANCH", JDBCType.VARCHAR).build(); - } - catch (SQLException e) { + } catch (SQLException e) { assert (e.getMessage().contains(TestResource.getResource("R_notImplemented"))); } try { - Connection con = ds.createConnectionBuilder().user("rafa").password("tennis").shardingKey(shardingKey).superShardingKey(superShardingKey) - .build(); - } - catch (SQLException e) { + Connection con = ds.createConnectionBuilder().user("rafa").password("tennis").shardingKey(shardingKey) + .superShardingKey(superShardingKey).build(); + } catch (SQLException e) { assert (e.getMessage().contains(TestResource.getResource("R_notImplemented"))); } } /** * Tests that we are throwing the unsupported exception for connectionBuilder() - * @throws SQLException - * @throws TestAbortedException + * + * @throws SQLException + * @throws TestAbortedException * * @since 1.9 */ @@ -90,31 +84,29 @@ public void xaConnectionBuilderTest() throws TestAbortedException, SQLException SQLServerXADataSource ds = new SQLServerXADataSource(); try { superShardingKey = ds.createShardingKeyBuilder().subkey("EASTERN_REGION", JDBCType.VARCHAR).build(); - } - catch (SQLException e) { + } catch (SQLException e) { assert (e.getMessage().contains(TestResource.getResource("R_notImplemented"))); } try { shardingKey = ds.createShardingKeyBuilder().subkey("PITTSBURGH_BRANCH", JDBCType.VARCHAR).build(); - } - catch (SQLException e) { + } catch (SQLException e) { assert (e.getMessage().contains(TestResource.getResource("R_notImplemented"))); } try { XAConnection con = ds.createXAConnectionBuilder().user("rafa").password("tennis").shardingKey(shardingKey) .superShardingKey(superShardingKey).build(); - } - catch (SQLException e) { + } catch (SQLException e) { assert (e.getMessage().contains(TestResource.getResource("R_notImplemented"))); } } /** * Tests that we are throwing the unsupported exception for createPooledConnectionBuilder() - * @throws SQLException - * @throws TestAbortedException + * + * @throws SQLException + * @throws TestAbortedException * @since 1.9 */ @Test @@ -123,30 +115,28 @@ public void connectionPoolDataSourceTest() throws TestAbortedException, SQLExcep ConnectionPoolDataSource ds = new SQLServerConnectionPoolDataSource(); try { superShardingKey = ds.createShardingKeyBuilder().subkey("EASTERN_REGION", JDBCType.VARCHAR).build(); - } - catch (SQLException e) { + } catch (SQLException e) { assert (e.getMessage().contains(TestResource.getResource("R_notImplemented"))); } try { shardingKey = ds.createShardingKeyBuilder().subkey("PITTSBURGH_BRANCH", JDBCType.VARCHAR).build(); - } - catch (SQLException e) { + } catch (SQLException e) { assert (e.getMessage().contains(TestResource.getResource("R_notImplemented"))); } try { - PooledConnection con = ds.createPooledConnectionBuilder().user("rafa").password("tennis").shardingKey(shardingKey) - .superShardingKey(superShardingKey).build(); - } - catch (SQLException e) { + PooledConnection con = ds.createPooledConnectionBuilder().user("rafa").password("tennis") + .shardingKey(shardingKey).superShardingKey(superShardingKey).build(); + } catch (SQLException e) { assert (e.getMessage().contains(TestResource.getResource("R_notImplemented"))); } } - + /** * Tests that we are throwing the unsupported exception for setShardingKeyIfValid() - * @throws SQLException - * @throws TestAbortedException + * + * @throws SQLException + * @throws TestAbortedException * @since 1.9 */ @Test @@ -155,23 +145,22 @@ public void setShardingKeyIfValidTest() throws TestAbortedException, SQLExceptio SQLServerConnection connection43 = (SQLServerConnection43) DriverManager.getConnection(connectionString); try { connection43.setShardingKeyIfValid(shardingKey, 10); - } - catch (SQLException e) { + } catch (SQLException e) { assert (e.getMessage().contains(TestResource.getResource("R_operationNotSupported"))); } try { connection43.setShardingKeyIfValid(shardingKey, superShardingKey, 10); - } - catch (SQLException e) { + } catch (SQLException e) { assert (e.getMessage().contains(TestResource.getResource("R_operationNotSupported"))); } - + } - + /** * Tests that we are throwing the unsupported exception for setShardingKey() - * @throws SQLException - * @throws TestAbortedException + * + * @throws SQLException + * @throws TestAbortedException * @since 1.9 */ @Test @@ -180,17 +169,15 @@ public void setShardingKeyTest() throws TestAbortedException, SQLException { SQLServerConnection connection43 = (SQLServerConnection43) DriverManager.getConnection(connectionString); try { connection43.setShardingKey(shardingKey); - } - catch (SQLException e) { + } catch (SQLException e) { assert (e.getMessage().contains(TestResource.getResource("R_operationNotSupported"))); } try { connection43.setShardingKey(shardingKey, superShardingKey); - } - catch (SQLException e) { + } catch (SQLException e) { assert (e.getMessage().contains(TestResource.getResource("R_operationNotSupported"))); } - + } /** diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/TestResource.java b/src/test/java/com/microsoft/sqlserver/jdbc/TestResource.java index b67b49871..691371b63 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/TestResource.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/TestResource.java @@ -1,15 +1,13 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; import java.util.ListResourceBundle; + /** * A simple resource bundle containing the strings for localizing. * @@ -23,16 +21,14 @@ protected Object[][] getContents() { return contents; } - // the keys must be prefixed with R_ to denote they are resource strings and their names should follow the camelCasing + // the keys must be prefixed with R_ to denote they are resource strings and their names should follow the + // camelCasing // convention and be descriptive - static final Object[][] contents = { - {"R_wrongEnv", "Aborting test: As this is not the right environement: "}, + static final Object[][] contents = {{"R_wrongEnv", "Aborting test: As this is not the right environement: "}, {"R_fipsPropertyNotSet", "Aborting test case as FIPS_ENV property is not set."}, {"R_invalidTrustCert", "Invalid TrustServerCertificate value."}, - {"R_invalidEncrypt", "Invalid encrypt value."}, - {"R_notImplemented", "not implemented"}, - {"R_resultsetClosed", "The result set is closed."}, - {"R_resultsetNull", "The result set is null."}, + {"R_invalidEncrypt", "Invalid encrypt value."}, {"R_notImplemented", "not implemented"}, + {"R_resultsetClosed", "The result set is closed."}, {"R_resultsetNull", "The result set is null."}, {"R_invalidFipsConfig", "Unable to verify FIPS mode settings."}, {"R_shouldBeEnabled", "should be enabled."}, {"R_StoredProcedureNotFound", "Could not find stored procedure"}, @@ -40,8 +36,7 @@ protected Object[][] getContents() { {"R_lengthTruncated", " The inserted length is truncated or not correct!"}, {"R_timeValueTruncated", " The time value is truncated or not correct!"}, {"R_invalidErrorMessage", "Invalid Error Message: "}, - {"R_expectedFailPassed", "Expected failure did not fail"}, - {"R_dataTypeNotFound", "Cannot find data type"}, + {"R_expectedFailPassed", "Expected failure did not fail"}, {"R_dataTypeNotFound", "Cannot find data type"}, {"R_illegalCharWktPosition", "Illegal character in Well-Known text at position {0}."}, {"R_illegalCharWkt", "Illegal Well-Known text. Please make sure Well-Known text is valid."}, {"R_errorMessage", " Error message: "}, @@ -53,10 +48,8 @@ protected Object[][] getContents() { {"R_connectionIsClosed", "The connection is closed."}, {"R_connectionIsNotClosed", "The connection is not closed."}, {"R_invalidExceptionMessage", "Invalid exception message"}, - {"R_failedValidate", "failed to validate values in $0} "}, - {"R_tableNotDropped", "table not dropped. "}, - {"R_connectionReset", "Connection reset"}, - {"R_unknownException", "Unknown exception"}, + {"R_failedValidate", "failed to validate values in $0} "}, {"R_tableNotDropped", "table not dropped. "}, + {"R_connectionReset", "Connection reset"}, {"R_unknownException", "Unknown exception"}, {"R_deadConnection", "Dead connection should be invalid"}, {"R_wrongExceptionMessage", "Wrong exception message"}, {"R_parameterNotDefined", "Parameter {0} was not defined"}, @@ -65,23 +58,21 @@ protected Object[][] getContents() { {"R_invalidQueryTimeout", "The query timeout value {0} is not valid."}, {"R_skipAzure", "Skipping test case on Azure SQL."}, {"R_expectedExceptionNotThrown", "Expected exception is not thrown."}, - {"R_errorNotCalled", "Error occurred is not called."}, - {"R_errorCalled", "Error occurred is called."}, + {"R_errorNotCalled", "Error occurred is not called."}, {"R_errorCalled", "Error occurred is called."}, {"R_supportUnwrapping", "{0} supports unwrapping."}, {"R_cantAccessSnapshot", "Cant access the TRANSACTION_SNAPSHOT "}, {"R_newConnectionShouldBeValid", "Newly created connection should be valid"}, {"R_closedConnectionShouldBeInvalid", "Closed connection should be invalid"}, {"R_noExceptionNegativeTimeout", "No exception thrown with negative timeout"}, - {"R_noExceptionClosedConnection", "No exception thrown calling getClientConnectionId on a closed connection"}, + {"R_noExceptionClosedConnection", + "No exception thrown calling getClientConnectionId on a closed connection"}, {"R_clientConnectionIdNull", "ClientConnectionId is null"}, {"R_valuesAreDifferent", "Values are different"}, {"R_parrentLoggerNameWrong", "Parent Logger name is wrong"}, {"R_unexpectedWrongDB", "Unexpected: ClientConnectionId is not in exception message due to wrong DB"}, {"R_unexpectedWrongHost", "Unexpected: ClientConnectionId is in exception message due to wrong host"}, - {"R_cannotOpenDatabase", "Cannot open database"}, - {"R_shouldNotConnect", "Should not have connected"}, - {"R_loginFailed", "Login failed"}, - {"R_exitedMoreSeconds", "Exited in more than {0} seconds."}, + {"R_cannotOpenDatabase", "Cannot open database"}, {"R_shouldNotConnect", "Should not have connected"}, + {"R_loginFailed", "Login failed"}, {"R_exitedMoreSeconds", "Exited in more than {0} seconds."}, {"R_exitedLessSeconds", "Exited in less than {0} seconds."}, {"R_invalidArgumentExecutor", "The argument executor is not valid"}, {"R_threadInterruptNotSet", "Thread's interrupt status is not set."}, @@ -95,15 +86,14 @@ protected Object[][] getContents() { {"R_idFromPoolNotSame", "ClientConnection Ids from pool are not the same."}, {"R_noProtocolVersion", "protocol version is not enabled or not supported by the client."}, {"R_protocolException", "Any protocol other than TLSv1, TLSv1.1, and TLSv1.2 should throw Exception"}, - {"R_invalidProtocolLabel", "SSL Protocol {0} label is not valid. Only TLS, TLSv1, TLSv1.1, and TLSv1.2 are supported."}, + {"R_invalidProtocolLabel", + "SSL Protocol {0} label is not valid. Only TLS, TLSv1, TLSv1.1, and TLSv1.2 are supported."}, {"R_SQLServerResourceMessage", "Message should be from SQL Server resources: "}, {"R_shouldThrowException", "Exception should have been thrown"}, {"R_tcpipConnectionToHost", "The TCP/IP connection to the host"}, - {"R_queryTimedOut", "The query has timed out."}, - {"R_readTimedOut", "Read timed out"}, + {"R_queryTimedOut", "The query has timed out."}, {"R_readTimedOut", "Read timed out"}, {"R_unexpectedErrorMessage", "Unexpected error message occured!"}, - {"R_warningsNotFound", "Warnings not found!"}, - {"R_warningsFound", "Warnings found!"}, + {"R_warningsNotFound", "Warnings not found!"}, {"R_warningsFound", "Warnings found!"}, {"R_causeShouldNotBeNull", "Cause should not be null."}, {"R_causeShouldBeInstance", "Cause should be instance of {0}."}, {"R_connShouldNotBeClosed", "Connection should not be closed"}, @@ -112,48 +102,46 @@ protected Object[][] getContents() { {"R_incorrectDriverVersionFormat", "Driver version number should be four parts! "}, {"R_previousShouldThrow", "Previous should have thrown an exception"}, {"R_objectMissingOrEmpty", "An object or column name is missing or empty."}, - {"R_dbNameIsCurrentDB", "The database name component of the object qualifier must be the name of the current database."}, + {"R_dbNameIsCurrentDB", + "The database name component of the object qualifier must be the name of the current database."}, {"R_numKeysIncorrect", "number of foreign key entries is incorrect."}, {"R_manifestNotFound", "Manifest file does not exist on classpath so ignoring test"}, - {"R_buildVersionError", "build version should be greater than driver versions for non SNAPSHOT versions, and same for SNAPSHOT versions"}, + {"R_buildVersionError", + "build version should be greater than driver versions for non SNAPSHOT versions, and same for SNAPSHOT versions"}, {"R_getURLContainsPwd", "Get URL should not have password attribute / property."}, {"R_userNameNull", "Username should not be null"}, {"R_userNameNotMatch", "Username does not match UserName from Connection String."}, - {"R_nameEmpty", "{0} name should not be empty."}, - {"R_nameNull", "{0} name should not be NULL."}, + {"R_nameEmpty", "{0} name should not be empty."}, {"R_nameNull", "{0} name should not be NULL."}, {"R_atLeastOneFound", "At least one {0} should be found."}, {"R_noSchemaShouldFail", "As we are not supplying schema it should fail."}, {"R_addBatchFailed", "addBatch does not add the SQL Statements to Batch, call to addBatch failed"}, {"R_insertBatchFailed", "affected rows does not match with batch size. Insert failed"}, {"R_savePointError", "Savepoint {0} should be {1}."}, - {"R_Incompat_SQLServerVersion", "Aborting test case as SQL Server version is not compatible with Always encrypted"}, + {"R_Incompat_SQLServerVersion", + "Aborting test case as SQL Server version is not compatible with Always encrypted"}, {"R_noKeyStore", "Aborting test case as no java key store and alias name exists."}, {"R_badStreamLength", "The stream value is not the specified length. The specified length was"}, {"R_streamReadError", "An error occurred while reading the value from the stream object. Error"}, - {"R_SQLStateNull", "SQLState should not be null"}, - {"R_blobFreed", "This Blob oject has been freed."}, - {"R_streamNull", "Stream is null when data is not."}, - {"R_incorrectUpdateCount", "Incorrect updateCount."}, + {"R_SQLStateNull", "SQLState should not be null"}, {"R_blobFreed", "This Blob oject has been freed."}, + {"R_streamNull", "Stream is null when data is not."}, {"R_incorrectUpdateCount", "Incorrect updateCount."}, {"R_testInterleaved", "Test interleaved inserts and warnings"}, {"R_errorFollowInserts", "Test error followed by inserts"}, {"R_errorFollow50280", "Test insert followed by non-fatal error (50280)"}, {"R_syntaxErrorDateConvert", "Syntax error converting date"}, {"R_dateConvertError", "Conversion failed when converting date"}, {"R_incompatJDBC", "Aborting test case as JDBC version is not compatible."}, - {"R_unexpectedException", "Unexpected exception occurred"}, - {"R_addBatchFailed", "addBatch failed"}, + {"R_unexpectedException", "Unexpected exception occurred"}, {"R_addBatchFailed", "addBatch failed"}, {"R_executeBatchFailed", "executeBatch failed"}, {"R_customErrorMessage", "Custom error message: col1 should be higher than 10"}, {"R_setDataNotEqual", "Received data not equal to setdata"}, {"R_syntaxMatchError", "Syntax translation does not match for query"}, - {"R_valueNotMatch", "Value does not match: "}, - {"R_incorrectDefault", "Incorrect default"}, + {"R_valueNotMatch", "Value does not match: "}, {"R_incorrectDefault", "Incorrect default"}, {"R_shouldBeSupported", "should be supported."}, {"R_operationNotSupported", "This operation is not supported."}, {"R_paramNotRecognized", "Not all parameters are recognized by driver."}, - {"R_invalidGetPreparedStatementHandle", "Invalid use of getPreparedStatementHandle() after statement close expected."}, - {"R_cancellationFailed", "Cancellation failed."}, - {"R_executionNotTimeout", "Execution did not timeout."}, + {"R_invalidGetPreparedStatementHandle", + "Invalid use of getPreparedStatementHandle() after statement close expected."}, + {"R_cancellationFailed", "Cancellation failed."}, {"R_executionNotTimeout", "Execution did not timeout."}, {"R_executionTooLong", "Execution took too long."}, {"R_executionNotLong", "Execution did not take long enough."}, {"R_queryCancelled", "The query was canceled."}, @@ -162,10 +150,8 @@ protected Object[][] getContents() { {"R_shouldBeWrapper", "{0} should be a wrapper for {1}."}, {"R_shouldNotBeWrapper", "{0} should not be a wrapper for {1}."}, {"R_outputParamFailed", "Test for output parameter failed."}, - {"R_inputParamFailed", "Test for input parameter failed."}, - {"R_decryptionFailed", "Decryption failed"}, - {"R_expectedValue", "Expected value: "}, - {"R_expectedValueAtIndex", "Expected value at index: "}, + {"R_inputParamFailed", "Test for input parameter failed."}, {"R_decryptionFailed", "Decryption failed"}, + {"R_expectedValue", "Expected value: "}, {"R_expectedValueAtIndex", "Expected value at index: "}, {"R_switchFailed", "Switch case is not matched with data"}, {"R_resultsetNotInstance", "Result set is not instance of SQLServerResultSet"}, diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/UtilTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/UtilTest.java index 783a8fc03..e19d02000 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/UtilTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/UtilTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc; @@ -16,6 +13,7 @@ import org.junit.platform.runner.JUnitPlatform; import org.junit.runner.RunWith; + /** * Tests the Util class * diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyAllTypes.java b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyAllTypes.java index 7782a86b7..93d12eadd 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyAllTypes.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyAllTypes.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.bulkCopy; @@ -25,9 +22,10 @@ import com.microsoft.sqlserver.testframework.Utils; import com.microsoft.sqlserver.testframework.util.ComparisonUtil; + @RunWith(JUnitPlatform.class) public class BulkCopyAllTypes extends AbstractTest { - + private static DBTable tableSrc = null; private static DBTable tableDest = null; @@ -46,48 +44,48 @@ public void testTVPResultSet() throws SQLException { testBulkCopyResultSet(false, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); } - private void testBulkCopyResultSet(boolean setSelectMethod, - Integer resultSetType, + private void testBulkCopyResultSet(boolean setSelectMethod, Integer resultSetType, Integer resultSetConcurrency) throws SQLException { setupVariation(); - try(Connection connnection = DriverManager.getConnection(connectionString + (setSelectMethod ? ";selectMethod=cursor;" : "")); - Statement statement = (null != resultSetType || null != resultSetConcurrency) ? - connnection.createStatement(resultSetType, resultSetConcurrency) : connnection.createStatement()){ - - ResultSet rs = statement.executeQuery("select * from " + tableSrc.getEscapedTableName()); - - SQLServerBulkCopy bcOperation = new SQLServerBulkCopy(connection); - bcOperation.setDestinationTableName(tableDest.getEscapedTableName()); - bcOperation.writeToServer(rs); - bcOperation.close(); - - ComparisonUtil.compareSrcTableAndDestTableIgnoreRowOrder(new DBConnection(connectionString), tableSrc, tableDest); + try (Connection connnection = DriverManager + .getConnection(connectionString + (setSelectMethod ? ";selectMethod=cursor;" : "")); + Statement statement = (null != resultSetType || null != resultSetConcurrency) ? connnection + .createStatement(resultSetType, resultSetConcurrency) : connnection.createStatement()) { + + ResultSet rs = statement.executeQuery("select * from " + tableSrc.getEscapedTableName()); + + SQLServerBulkCopy bcOperation = new SQLServerBulkCopy(connection); + bcOperation.setDestinationTableName(tableDest.getEscapedTableName()); + bcOperation.writeToServer(rs); + bcOperation.close(); + + ComparisonUtil.compareSrcTableAndDestTableIgnoreRowOrder(new DBConnection(connectionString), tableSrc, + tableDest); } terminateVariation(); } private void setupVariation() throws SQLException { - try(DBConnection dbConnection = new DBConnection(connectionString); - DBStatement dbStmt = dbConnection.createStatement()) { - - tableSrc = new DBTable(true); - tableDest = tableSrc.cloneSchema(); - - dbStmt.createTable(tableSrc); - dbStmt.createTable(tableDest); - - dbStmt.populateTable(tableSrc); + try (DBConnection dbConnection = new DBConnection(connectionString); + DBStatement dbStmt = dbConnection.createStatement()) { + + tableSrc = new DBTable(true); + tableDest = tableSrc.cloneSchema(); + + dbStmt.createTable(tableSrc); + dbStmt.createTable(tableDest); + + dbStmt.populateTable(tableSrc); } } private void terminateVariation() throws SQLException { - try(Connection conn = DriverManager.getConnection(connectionString); - Statement stmt = conn.createStatement()) { + try (Connection conn = DriverManager.getConnection(connectionString); Statement stmt = conn.createStatement()) { - Utils.dropTableIfExists(tableSrc.getEscapedTableName(), stmt); - Utils.dropTableIfExists(tableDest.getEscapedTableName(), stmt); + Utils.dropTableIfExists(tableSrc.getEscapedTableName(), stmt); + Utils.dropTableIfExists(tableDest.getEscapedTableName(), stmt); } } -} \ No newline at end of file +} diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyCSVTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyCSVTest.java index ebd648a3c..d55e5d607 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyCSVTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyCSVTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.bulkCopy; @@ -39,11 +36,13 @@ import com.microsoft.sqlserver.testframework.sqlType.SqlType; import com.microsoft.sqlserver.testframework.util.ComparisonUtil; + /** * Test bulkcopy with CSV file input * - * In the input csv, first row is comma separated datatype name of values to follow Precision and scale are separated by hyphen in csv to distinguish - * between column and scale/precision ie decimal(18-6) in csv is decimal type with precision 18 and scale 6 + * In the input csv, first row is comma separated datatype name of values to follow Precision and scale are separated by + * hyphen in csv to distinguish between column and scale/precision ie decimal(18-6) in csv is decimal type with + * precision 18 and scale 6 * * Destination table contains one column for each datatype name in the csv header(first line of csv) */ @@ -64,7 +63,7 @@ public class BulkCopyCSVTest extends AbstractTest { * Create connection, statement and generate path of resource file */ @BeforeAll - static void setUpConnection() { + public static void setUpConnection() { con = new DBConnection(connectionString); stmt = con.createStatement(); filePath = Utils.getCurrentClassPath(); @@ -75,11 +74,11 @@ static void setUpConnection() { */ @Test @DisplayName("Test SQLServerBulkCSVFileRecord") - void testCSV() { - try (SQLServerBulkCSVFileRecord fileRecord = new SQLServerBulkCSVFileRecord(filePath + inputFile, encoding, delimiter, true)) { + public void testCSV() { + try (SQLServerBulkCSVFileRecord fileRecord = new SQLServerBulkCSVFileRecord(filePath + inputFile, encoding, + delimiter, true)) { testBulkCopyCSV(fileRecord, true); - } - catch (SQLException e) { + } catch (SQLException e) { fail(e.getMessage()); } } @@ -89,11 +88,11 @@ void testCSV() { */ @Test @DisplayName("Test SQLServerBulkCSVFileRecord First line not being column name") - void testCSVFirstLineNotColumnName() { - try (SQLServerBulkCSVFileRecord fileRecord = new SQLServerBulkCSVFileRecord(filePath + inputFileNoColumnName, encoding, delimiter, false)) { + public void testCSVFirstLineNotColumnName() { + try (SQLServerBulkCSVFileRecord fileRecord = new SQLServerBulkCSVFileRecord(filePath + inputFileNoColumnName, + encoding, delimiter, false)) { testBulkCopyCSV(fileRecord, false); - } - catch (SQLException e) { + } catch (SQLException e) { fail(e.getMessage()); } } @@ -105,21 +104,22 @@ void testCSVFirstLineNotColumnName() { */ @Test @DisplayName("Test SQLServerBulkCSVFileRecord with passing file from url") - void testCSVFromURL() throws SQLException { + public void testCSVFromURL() throws SQLException { try (InputStream csvFileInputStream = new URL( - "https://raw.githubusercontent.com/Microsoft/mssql-jdbc/master/src/test/resources/BulkCopyCSVTestInput.csv").openStream(); - SQLServerBulkCSVFileRecord fileRecord = new SQLServerBulkCSVFileRecord(csvFileInputStream, encoding, delimiter, true)) { + "https://raw.githubusercontent.com/Microsoft/mssql-jdbc/master/src/test/resources/BulkCopyCSVTestInput.csv") + .openStream(); + SQLServerBulkCSVFileRecord fileRecord = new SQLServerBulkCSVFileRecord(csvFileInputStream, encoding, + delimiter, true)) { testBulkCopyCSV(fileRecord, true); - } - catch (Exception e) { + } catch (Exception e) { fail(e.getMessage()); } } - private void testBulkCopyCSV(SQLServerBulkCSVFileRecord fileRecord, - boolean firstLineIsColumnNames) { + private void testBulkCopyCSV(SQLServerBulkCSVFileRecord fileRecord, boolean firstLineIsColumnNames) { DBTable destTable = null; - try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath + inputFile), encoding))) { + try (BufferedReader br = new BufferedReader( + new InputStreamReader(new FileInputStream(filePath + inputFile), encoding))) { // read the first line from csv and parse it to get datatypes to create destination column String[] columnTypes = br.readLine().substring(1)/* Skip the Byte order mark */.split(delimiter, -1); br.close(); @@ -127,54 +127,52 @@ private void testBulkCopyCSV(SQLServerBulkCSVFileRecord fileRecord, int numberOfColumns = columnTypes.length; destTable = new DBTable(false); try (SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy((Connection) con.product())) { - bulkCopy.setDestinationTableName(destTable.getEscapedTableName()); - - // add a column in destTable for each datatype in csv - for (int i = 0; i < numberOfColumns; i++) { - SqlType sqlType = null; - int precision = -1; - int scale = -1; - - String columnType = columnTypes[i].trim().toLowerCase(); - int indexOpenParenthesis = columnType.lastIndexOf("("); - // skip the parenthesis in case of precision and scale type - if (-1 != indexOpenParenthesis) { - String precision_scale = columnType.substring(indexOpenParenthesis + 1, columnType.length() - 1); - columnType = columnType.substring(0, indexOpenParenthesis); - sqlType = SqlTypeMapping.valueOf(columnType.toUpperCase()).sqlType; - - // add scale if exist - int indexPrecisionScaleSeparator = precision_scale.indexOf("-"); - if (-1 != indexPrecisionScaleSeparator) { - scale = Integer.parseInt(precision_scale.substring(indexPrecisionScaleSeparator + 1)); - sqlType.setScale(scale); - precision_scale = precision_scale.substring(0, indexPrecisionScaleSeparator); - } - // add precision - precision = Integer.parseInt(precision_scale); - sqlType.setPrecision(precision); - } - else { - sqlType = SqlTypeMapping.valueOf(columnType.toUpperCase()).sqlType; - } - - destTable.addColumn(sqlType); - fileRecord.addColumnMetadata(i + 1, "", sqlType.getJdbctype().getVendorTypeNumber(), (-1 == precision) ? 0 : precision, - (-1 == scale) ? 0 : scale); - } - stmt.createTable(destTable); - bulkCopy.writeToServer((ISQLServerBulkRecord) fileRecord); + bulkCopy.setDestinationTableName(destTable.getEscapedTableName()); + + // add a column in destTable for each datatype in csv + for (int i = 0; i < numberOfColumns; i++) { + SqlType sqlType = null; + int precision = -1; + int scale = -1; + + String columnType = columnTypes[i].trim().toLowerCase(); + int indexOpenParenthesis = columnType.lastIndexOf("("); + // skip the parenthesis in case of precision and scale type + if (-1 != indexOpenParenthesis) { + String precision_scale = columnType.substring(indexOpenParenthesis + 1, + columnType.length() - 1); + columnType = columnType.substring(0, indexOpenParenthesis); + sqlType = SqlTypeMapping.valueOf(columnType.toUpperCase()).sqlType; + + // add scale if exist + int indexPrecisionScaleSeparator = precision_scale.indexOf("-"); + if (-1 != indexPrecisionScaleSeparator) { + scale = Integer.parseInt(precision_scale.substring(indexPrecisionScaleSeparator + 1)); + sqlType.setScale(scale); + precision_scale = precision_scale.substring(0, indexPrecisionScaleSeparator); + } + // add precision + precision = Integer.parseInt(precision_scale); + sqlType.setPrecision(precision); + } else { + sqlType = SqlTypeMapping.valueOf(columnType.toUpperCase()).sqlType; + } + + destTable.addColumn(sqlType); + fileRecord.addColumnMetadata(i + 1, "", sqlType.getJdbctype().getVendorTypeNumber(), + (-1 == precision) ? 0 : precision, (-1 == scale) ? 0 : scale); + } + stmt.createTable(destTable); + bulkCopy.writeToServer((ISQLServerBulkRecord) fileRecord); } if (firstLineIsColumnNames) validateValuesFromCSV(destTable, inputFile); else validateValuesFromCSV(destTable, inputFileNoColumnName); - } - catch (Exception e) { + } catch (Exception e) { fail(e.getMessage()); - } - finally { + } finally { if (null != destTable) { stmt.dropTable(destTable); } @@ -186,33 +184,33 @@ private void testBulkCopyCSV(SQLServerBulkCSVFileRecord fileRecord, * * @param destinationTable */ - static void validateValuesFromCSV(DBTable destinationTable, - String inputFile) { - try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(filePath + inputFile), encoding))) { + static void validateValuesFromCSV(DBTable destinationTable, String inputFile) { + try (BufferedReader br = new BufferedReader( + new InputStreamReader(new FileInputStream(filePath + inputFile), encoding))) { if (inputFile.equalsIgnoreCase("BulkCopyCSVTestInput.csv")) - br.readLine(); // skip first line as it is header - - try (DBResultSet dstResultSet = stmt.executeQuery("SELECT * FROM " + destinationTable.getEscapedTableName() + ";")) { - ResultSetMetaData destMeta = ((ResultSet) dstResultSet.product()).getMetaData(); - int totalColumns = destMeta.getColumnCount(); - while (dstResultSet.next()) { - String[] srcValues = br.readLine().split(delimiter); - if ((0 == srcValues.length) && (srcValues.length != totalColumns)) { - srcValues = new String[totalColumns]; - Arrays.fill(srcValues, null); - } - for (int i = 1; i <= totalColumns; i++) { - String srcValue = srcValues[i - 1]; - String dstValue = dstResultSet.getString(i); - srcValue = (null != srcValue) ? srcValue.trim() : srcValue; - dstValue = (null != dstValue) ? dstValue.trim() : dstValue; - // get the value from csv as string and compare them - ComparisonUtil.compareExpectedAndActual(java.sql.Types.VARCHAR, srcValue, dstValue); - } - } + br.readLine(); // skip first line as it is header + + try (DBResultSet dstResultSet = stmt + .executeQuery("SELECT * FROM " + destinationTable.getEscapedTableName() + ";")) { + ResultSetMetaData destMeta = ((ResultSet) dstResultSet.product()).getMetaData(); + int totalColumns = destMeta.getColumnCount(); + while (dstResultSet.next()) { + String[] srcValues = br.readLine().split(delimiter); + if ((0 == srcValues.length) && (srcValues.length != totalColumns)) { + srcValues = new String[totalColumns]; + Arrays.fill(srcValues, null); + } + for (int i = 1; i <= totalColumns; i++) { + String srcValue = srcValues[i - 1]; + String dstValue = dstResultSet.getString(i); + srcValue = (null != srcValue) ? srcValue.trim() : srcValue; + dstValue = (null != dstValue) ? dstValue.trim() : dstValue; + // get the value from csv as string and compare them + ComparisonUtil.compareExpectedAndActual(java.sql.Types.VARCHAR, srcValue, dstValue); + } + } } - } - catch (Exception e) { + } catch (Exception e) { fail("CSV validation failed with " + e.getMessage()); } } @@ -223,7 +221,7 @@ static void validateValuesFromCSV(DBTable destinationTable, * @throws SQLException */ @AfterAll - static void tearConnection() throws SQLException { + public static void tearConnection() throws SQLException { stmt.close(); con.close(); } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyColumnMappingTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyColumnMappingTest.java index 49e72a880..e2236c50b 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyColumnMappingTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyColumnMappingTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.bulkCopy; @@ -12,8 +9,8 @@ import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; -import java.util.concurrent.ThreadLocalRandom; import java.text.MessageFormat; +import java.util.concurrent.ThreadLocalRandom; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; @@ -22,6 +19,7 @@ import org.junit.platform.runner.JUnitPlatform; import org.junit.runner.RunWith; +import com.microsoft.sqlserver.jdbc.TestResource; import com.microsoft.sqlserver.testframework.DBConnection; import com.microsoft.sqlserver.testframework.DBResultSet; import com.microsoft.sqlserver.testframework.DBStatement; @@ -29,7 +27,6 @@ import com.microsoft.sqlserver.testframework.sqlType.SqlType; import com.microsoft.sqlserver.testframework.util.ComparisonUtil; -import com.microsoft.sqlserver.jdbc.TestResource; /** * Test BulkCopy Column Mapping @@ -45,20 +42,20 @@ public class BulkCopyColumnMappingTest extends BulkCopyTestSetUp { * Create connection, statement and generate path of resource file */ @BeforeAll - static void setUpConnection() { + public static void setUpConnection() { con = new DBConnection(connectionString); stmt = con.createStatement(); } @AfterAll - static void closeConnection() throws SQLException { + public static void closeConnection() throws SQLException { stmt.close(); con.close(); } @Test @DisplayName("BulkCopy:test no explicit column mapping") - void testNoExplicitCM() { + public void testNoExplicitCM() { // create dest table DBTable destTable = sourceTable.cloneSchema(); @@ -72,7 +69,7 @@ void testNoExplicitCM() { @Test @DisplayName("BulkCopy:test explicit column mapping") - void testExplicitCM() { + public void testExplicitCM() { // create dest table DBTable destTable = sourceTable.cloneSchema(); @@ -107,7 +104,7 @@ void testExplicitCM() { @Test @DisplayName("BulkCopy:test unicode column mapping") - void testUnicodeCM() { + public void testUnicodeCM() { // create source unicode table DBTable sourceTableUnicode = new DBTable(true, true); @@ -133,7 +130,8 @@ void testUnicodeCM() { break; case 2: - bulkWrapper.setColumnMapping(sourceTableUnicode.getColumnName(i - 1), destTableUnicode.getColumnName(i - 1)); + bulkWrapper.setColumnMapping(sourceTableUnicode.getColumnName(i - 1), + destTableUnicode.getColumnName(i - 1)); break; case 3: @@ -147,7 +145,7 @@ void testUnicodeCM() { @Test @DisplayName("BulkCopy:test repetative column mapping") - void testRepetativeCM() { + public void testRepetativeCM() { // create source table DBTable sourceTable1 = new DBTable(true); @@ -194,10 +192,9 @@ void testRepetativeCM() { BulkCopyTestUtil.performBulkCopy(bulkWrapper, sourceTable1, destTable, false, false, false); try { validateValuesRepetativeCM(con, sourceTable1, destTable); - } - catch (SQLException e) { + } catch (SQLException e) { MessageFormat form = new MessageFormat(TestResource.getResource("R_failedValidate")); - Object[] msgArgs = {sourceTable1.getTableName()+" and"+destTable.getTableName()}; + Object[] msgArgs = {sourceTable1.getTableName() + " and" + destTable.getTableName()}; fail(form.format(msgArgs) + "\n" + destTable.getTableName() + "\n" + e.getMessage()); } @@ -207,7 +204,7 @@ void testRepetativeCM() { @Test @DisplayName("BulkCopy:test implicit mismatched column mapping") - void testImplicitMismatchCM() { + public void testImplicitMismatchCM() { // create non unicode dest table with different schema from source table DBTable destTable = new DBTable(true, false, true); @@ -242,7 +239,7 @@ void testImplicitMismatchCM() { @Test @DisplayName("BulkCopy:test invalid column mapping") - void testInvalidCM() { + public void testInvalidCM() { // create dest table DBTable destTable = sourceTable.cloneSchema(); @@ -327,42 +324,43 @@ void testInvalidCM() { } /** - * validate if same values are in both source and destination table taking into account 1 extra column in destination which should be a copy of - * first column of source. + * validate if same values are in both source and destination table taking into account 1 extra column in + * destination which should be a copy of first column of source. * * @param con * @param sourceTable * @param destinationTable * @throws SQLException */ - private void validateValuesRepetativeCM(DBConnection con, - DBTable sourceTable, + private void validateValuesRepetativeCM(DBConnection con, DBTable sourceTable, DBTable destinationTable) throws SQLException { - try(DBStatement srcStmt = con.createStatement(); - DBStatement dstStmt = con.createStatement(); - DBResultSet srcResultSet = srcStmt.executeQuery("SELECT * FROM " + sourceTable.getEscapedTableName() + ";"); - DBResultSet dstResultSet = dstStmt.executeQuery("SELECT * FROM " + destinationTable.getEscapedTableName() + ";")) { - ResultSetMetaData sourceMeta = ((ResultSet) srcResultSet.product()).getMetaData(); - int totalColumns = sourceMeta.getColumnCount(); - - // verify data from sourceType and resultSet - while (srcResultSet.next() && dstResultSet.next()) { - for (int i = 1; i <= totalColumns; i++) { - // TODO: check row and column count in both the tables - - Object srcValue, dstValue; - srcValue = srcResultSet.getObject(i); - dstValue = dstResultSet.getObject(i); - ComparisonUtil.compareExpectedAndActual(sourceMeta.getColumnType(i), srcValue, dstValue); - - // compare value of first column of source with extra column in destination - if (1 == i) { - Object srcValueFirstCol = srcResultSet.getObject(i); - Object dstValLastCol = dstResultSet.getObject(totalColumns + 1); - ComparisonUtil.compareExpectedAndActual(sourceMeta.getColumnType(i), srcValueFirstCol, dstValLastCol); - } - } - } + try (DBStatement srcStmt = con.createStatement(); DBStatement dstStmt = con.createStatement(); + DBResultSet srcResultSet = srcStmt + .executeQuery("SELECT * FROM " + sourceTable.getEscapedTableName() + ";"); + DBResultSet dstResultSet = dstStmt + .executeQuery("SELECT * FROM " + destinationTable.getEscapedTableName() + ";")) { + ResultSetMetaData sourceMeta = ((ResultSet) srcResultSet.product()).getMetaData(); + int totalColumns = sourceMeta.getColumnCount(); + + // verify data from sourceType and resultSet + while (srcResultSet.next() && dstResultSet.next()) { + for (int i = 1; i <= totalColumns; i++) { + // TODO: check row and column count in both the tables + + Object srcValue, dstValue; + srcValue = srcResultSet.getObject(i); + dstValue = dstResultSet.getObject(i); + ComparisonUtil.compareExpectedAndActual(sourceMeta.getColumnType(i), srcValue, dstValue); + + // compare value of first column of source with extra column in destination + if (1 == i) { + Object srcValueFirstCol = srcResultSet.getObject(i); + Object dstValLastCol = dstResultSet.getObject(totalColumns + 1); + ComparisonUtil.compareExpectedAndActual(sourceMeta.getColumnType(i), srcValueFirstCol, + dstValLastCol); + } + } + } } } @@ -371,8 +369,7 @@ private void dropTable(String tableName) { String dropSQL = "DROP TABLE [dbo]." + tableName; try { stmt.execute(dropSQL); - } - catch (SQLException e) { + } catch (SQLException e) { fail(tableName + " " + TestResource.getResource("R_tableNotDropped") + "\n" + e.getMessage()); } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyConnectionTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyConnectionTest.java index bbc3f7100..1863bd639 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyConnectionTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyConnectionTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.bulkCopy; @@ -30,6 +27,7 @@ import com.microsoft.sqlserver.jdbc.SQLServerBulkCopyOptions; import com.microsoft.sqlserver.jdbc.SQLServerConnection; + /** * Test BulkCopy Connection Constructor and BulkCopyOption */ @@ -43,18 +41,19 @@ public class BulkCopyConnectionTest extends BulkCopyTestSetUp { * @return */ @TestFactory - Stream generateBulkCopyConstructorTest() { + public Stream generateBulkCopyConstructorTest() { List testData = createTestDatatestBulkCopyConstructor(); // had to avoid using lambdas as we need to test against java7 return testData.stream().map(new Function() { @Override public DynamicTest apply(final BulkCopyTestWrapper datum) { - return DynamicTest.dynamicTest("Testing " + datum.testName, new org.junit.jupiter.api.function.Executable() { - @Override - public void execute() { - BulkCopyTestUtil.performBulkCopy(datum, sourceTable); - } - }); + return DynamicTest.dynamicTest("Testing " + datum.testName, + new org.junit.jupiter.api.function.Executable() { + @Override + public void execute() { + BulkCopyTestUtil.performBulkCopy(datum, sourceTable); + } + }); } }); } @@ -65,17 +64,18 @@ public void execute() { * @return */ @TestFactory - Stream generateBulkCopyOptionsTest() { + public Stream generateBulkCopyOptionsTest() { List testData = createTestDatatestBulkCopyOption(); return testData.stream().map(new Function() { @Override public DynamicTest apply(final BulkCopyTestWrapper datum) { - return DynamicTest.dynamicTest("Testing " + datum.testName, new org.junit.jupiter.api.function.Executable() { - @Override - public void execute() { - BulkCopyTestUtil.performBulkCopy(datum, sourceTable); - } - }); + return DynamicTest.dynamicTest("Testing " + datum.testName, + new org.junit.jupiter.api.function.Executable() { + @Override + public void execute() { + BulkCopyTestUtil.performBulkCopy(datum, sourceTable); + } + }); } }); } @@ -85,13 +85,12 @@ public void execute() { */ @Test @DisplayName("BulkCopy:test uninitialized Connection") - void testInvalidConnection1() { + public void testInvalidConnection1() { assertThrows(SQLException.class, new org.junit.jupiter.api.function.Executable() { @Override public void execute() throws SQLException { - try(Connection con = null; - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con)) { - //do nothing + try (Connection con = null; SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con)) { + // do nothing } } }); @@ -102,13 +101,12 @@ public void execute() throws SQLException { */ @Test @DisplayName("BulkCopy:test uninitialized SQLServerConnection") - void testInvalidConnection2() { + public void testInvalidConnection2() { assertThrows(SQLException.class, new org.junit.jupiter.api.function.Executable() { @Override public void execute() throws SQLException { - try(SQLServerConnection con = null; - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con)) { - //do nothing + try (SQLServerConnection con = null; SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con)) { + // do nothing } } }); @@ -119,13 +117,13 @@ public void execute() throws SQLException { */ @Test @DisplayName("BulkCopy:test empty connection string") - void testInvalidConnection3() { + public void testInvalidConnection3() { assertThrows(SQLException.class, new org.junit.jupiter.api.function.Executable() { @Override public void execute() throws SQLException { String connectionUrl = " "; - try(SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(connectionUrl)) { - //do nothing + try (SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(connectionUrl)) { + // do nothing } } }); @@ -136,13 +134,13 @@ public void execute() throws SQLException { */ @Test @DisplayName("BulkCopy:test null connenction string") - void testInvalidConnection4() { + public void testInvalidConnection4() { assertThrows(SQLException.class, new org.junit.jupiter.api.function.Executable() { @Override public void execute() throws SQLException { String connectionUrl = null; - try(SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(connectionUrl)) { - //do nothing + try (SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(connectionUrl)) { + // do nothing } } }); @@ -153,7 +151,7 @@ public void execute() throws SQLException { */ @Test @DisplayName("BulkCopy:test null SQLServerBulkCopyOptions") - void testEmptyBulkCopyOptions() { + public void testEmptyBulkCopyOptions() { BulkCopyTestWrapper bulkWrapper = new BulkCopyTestWrapper(connectionString); bulkWrapper.setUsingConnection((0 == ThreadLocalRandom.current().nextInt(2)) ? true : false); SQLServerBulkCopyOptions option = null; diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyISQLServerBulkRecordTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyISQLServerBulkRecordTest.java index 83316cc22..ce61ad6a0 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyISQLServerBulkRecordTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyISQLServerBulkRecordTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.bulkCopy; @@ -30,6 +27,7 @@ import com.microsoft.sqlserver.testframework.DBTable; import com.microsoft.sqlserver.testframework.sqlType.SqlType; + /** * Test bulkcopy decimal sacle and precision */ @@ -38,7 +36,7 @@ public class BulkCopyISQLServerBulkRecordTest extends AbstractTest { @Test - void testISQLServerBulkRecord() throws SQLException { + public void testISQLServerBulkRecord() throws SQLException { try (DBConnection con = new DBConnection(connectionString); DBStatement stmt = con.createStatement()) { DBTable dstTable = new DBTable(true); stmt.createTable(dstTable); @@ -58,10 +56,7 @@ private class ColumnMetadata { int precision; int scale; - ColumnMetadata(String name, - int type, - int precision, - int scale) { + ColumnMetadata(String name, int type, int precision, int scale) { columnName = name; columnType = type; this.precision = precision; @@ -87,8 +82,8 @@ private class ColumnMetadata { // TODO: update the test to use correct precision once bulkCopy is fixed precision = 50; } - columnMetadata.put(i + 1, - new ColumnMetadata(sqlType.getName(), sqlType.getJdbctype().getVendorTypeNumber(), precision, sqlType.getScale())); + columnMetadata.put(i + 1, new ColumnMetadata(sqlType.getName(), + sqlType.getJdbctype().getVendorTypeNumber(), precision, sqlType.getScale())); } // add data @@ -100,8 +95,7 @@ private class ColumnMetadata { SqlType sqlType = dstTable.getSqlType(j); if (JDBCType.BIT == sqlType.getJdbctype()) { CurrentRow[j] = ((0 == ThreadLocalRandom.current().nextInt(2)) ? Boolean.FALSE : Boolean.TRUE); - } - else { + } else { CurrentRow[j] = sqlType.createdata(); } } @@ -159,20 +153,13 @@ public void reset() { } @Override - public void addColumnMetadata(int positionInFile, - String name, - int jdbcType, - int precision, - int scale, + public void addColumnMetadata(int positionInFile, String name, int jdbcType, int precision, int scale, DateTimeFormatter dateTimeFormatter) throws SQLServerException { // TODO Not Implemented } @Override - public void addColumnMetadata(int positionInFile, - String name, - int jdbcType, - int precision, + public void addColumnMetadata(int positionInFile, String name, int jdbcType, int precision, int scale) throws SQLServerException { // TODO Not Implemented } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyResultSetCursorTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyResultSetCursorTest.java index 774deff4a..ad6a497e3 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyResultSetCursorTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyResultSetCursorTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.bulkCopy; @@ -29,22 +26,27 @@ import com.microsoft.sqlserver.testframework.AbstractTest; import com.microsoft.sqlserver.testframework.Utils; + @RunWith(JUnitPlatform.class) public class BulkCopyResultSetCursorTest extends AbstractTest { - static BigDecimal[] expectedBigDecimals = {new BigDecimal("12345.12345"), new BigDecimal("125.123"), new BigDecimal("45.12345")}; + static BigDecimal[] expectedBigDecimals = {new BigDecimal("12345.12345"), new BigDecimal("125.123"), + new BigDecimal("45.12345")}; static String[] expectedBigDecimalStrings = {"12345.12345", "125.12300", "45.12345"}; static String[] expectedStrings = {"hello", "world", "!!!"}; - static Timestamp[] expectedTimestamps = {new Timestamp(1433338533461L), new Timestamp(14917485583999L), new Timestamp(1491123533000L)}; - static String[] expectedTimestampStrings = {"2015-06-03 13:35:33.4610000", "2442-09-19 01:59:43.9990000", "2017-04-02 08:58:53.0000000"}; + static Timestamp[] expectedTimestamps = {new Timestamp(1433338533461L), new Timestamp(14917485583999L), + new Timestamp(1491123533000L)}; + static String[] expectedTimestampStrings = {"2015-06-03 13:35:33.4610000", "2442-09-19 01:59:43.9990000", + "2017-04-02 08:58:53.0000000"}; private static String srcTable = "BulkCopyResultSetCursorTest_SourceTable"; private static String desTable = "BulkCopyResultSetCursorTest_DestinationTable"; /** - * Test a previous failure when using server cursor and using the same connection to create Bulk Copy and result set. + * Test a previous failure when using server cursor and using the same connection to create Bulk Copy and result + * set. * * @throws SQLException */ @@ -56,27 +58,27 @@ public void testServerCursors() throws SQLException { serverCursorsTest(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); } - private void serverCursorsTest(int resultSetType, - int resultSetConcurrency) throws SQLException { - try (Connection conn = DriverManager.getConnection(connectionString); - Statement stmt = conn.createStatement()) { - - dropTables(stmt); - createTables(stmt); - populateSourceTable(); - - try (ResultSet rs = conn.createStatement(resultSetType, resultSetConcurrency).executeQuery("select * from " + srcTable); - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(conn)) { - bulkCopy.setDestinationTableName(desTable); - bulkCopy.writeToServer(rs); - - verifyDestinationTableData(expectedBigDecimals.length); - } + private void serverCursorsTest(int resultSetType, int resultSetConcurrency) throws SQLException { + try (Connection conn = DriverManager.getConnection(connectionString); Statement stmt = conn.createStatement()) { + + dropTables(stmt); + createTables(stmt); + populateSourceTable(); + + try (ResultSet rs = conn.createStatement(resultSetType, resultSetConcurrency) + .executeQuery("select * from " + srcTable); + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(conn)) { + bulkCopy.setDestinationTableName(desTable); + bulkCopy.writeToServer(rs); + + verifyDestinationTableData(expectedBigDecimals.length); + } } } /** - * Test a previous failure when setting SelectMethod to cursor and using the same connection to create Bulk Copy and result set. + * Test a previous failure when setting SelectMethod to cursor and using the same connection to create Bulk Copy and + * result set. * * @throws SQLException */ @@ -85,18 +87,18 @@ public void testSelectMethodSetToCursor() throws SQLException { Properties info = new Properties(); info.setProperty("SelectMethod", "cursor"); try (Connection conn = DriverManager.getConnection(connectionString, info); - Statement stmt = conn.createStatement()) { - dropTables(stmt); - createTables(stmt); - populateSourceTable(); - - try (ResultSet rs = conn.createStatement().executeQuery("select * from " + srcTable); - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(conn)) { - bulkCopy.setDestinationTableName(desTable); - bulkCopy.writeToServer(rs); - - verifyDestinationTableData(expectedBigDecimals.length); - } + Statement stmt = conn.createStatement()) { + dropTables(stmt); + createTables(stmt); + populateSourceTable(); + + try (ResultSet rs = conn.createStatement().executeQuery("select * from " + srcTable); + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(conn)) { + bulkCopy.setDestinationTableName(desTable); + bulkCopy.writeToServer(rs); + + verifyDestinationTableData(expectedBigDecimals.length); + } } } @@ -107,76 +109,77 @@ public void testSelectMethodSetToCursor() throws SQLException { */ @Test public void testMultiplePreparedStatementAndResultSet() throws SQLException { - try (Connection conn = DriverManager.getConnection(connectionString); - Statement stmt = conn.createStatement()) { - - dropTables(stmt); - createTables(stmt); - populateSourceTable(); - - try (ResultSet rs = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE).executeQuery("select * from " + srcTable)) { - try (SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(conn)) { - bulkCopy.setDestinationTableName(desTable); - bulkCopy.writeToServer(rs); - verifyDestinationTableData(expectedBigDecimals.length); - } - - rs.beforeFirst(); - try (SQLServerBulkCopy bulkCopy1 = new SQLServerBulkCopy(conn)) { - bulkCopy1.setDestinationTableName(desTable); - bulkCopy1.writeToServer(rs); - verifyDestinationTableData(expectedBigDecimals.length * 2); - } - - rs.beforeFirst(); - try (SQLServerBulkCopy bulkCopy2 = new SQLServerBulkCopy(conn)) { - bulkCopy2.setDestinationTableName(desTable); - bulkCopy2.writeToServer(rs); - verifyDestinationTableData(expectedBigDecimals.length * 3); - } - - String sql = "insert into " + desTable + " values (?,?,?,?)"; - Calendar calGMT = Calendar.getInstance(TimeZone.getTimeZone("GMT")); - try (SQLServerPreparedStatement pstmt1 = (SQLServerPreparedStatement) conn.prepareStatement(sql)) { - for (int i = 0; i < expectedBigDecimals.length; i++) { - pstmt1.setBigDecimal(1, expectedBigDecimals[i]); - pstmt1.setString(2, expectedStrings[i]); - pstmt1.setTimestamp(3, expectedTimestamps[i], calGMT); - pstmt1.setString(4, expectedStrings[i]); - pstmt1.execute(); - } - verifyDestinationTableData(expectedBigDecimals.length * 4); - } - try (ResultSet rs2 = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE).executeQuery("select * from " + srcTable); - SQLServerBulkCopy bulkCopy3 = new SQLServerBulkCopy(conn)) { - bulkCopy3.setDestinationTableName(desTable); - bulkCopy3.writeToServer(rs2); - verifyDestinationTableData(expectedBigDecimals.length * 5); - } - } - } + try (Connection conn = DriverManager.getConnection(connectionString); Statement stmt = conn.createStatement()) { + + dropTables(stmt); + createTables(stmt); + populateSourceTable(); + + try (ResultSet rs = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE) + .executeQuery("select * from " + srcTable)) { + try (SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(conn)) { + bulkCopy.setDestinationTableName(desTable); + bulkCopy.writeToServer(rs); + verifyDestinationTableData(expectedBigDecimals.length); + } + + rs.beforeFirst(); + try (SQLServerBulkCopy bulkCopy1 = new SQLServerBulkCopy(conn)) { + bulkCopy1.setDestinationTableName(desTable); + bulkCopy1.writeToServer(rs); + verifyDestinationTableData(expectedBigDecimals.length * 2); + } + + rs.beforeFirst(); + try (SQLServerBulkCopy bulkCopy2 = new SQLServerBulkCopy(conn)) { + bulkCopy2.setDestinationTableName(desTable); + bulkCopy2.writeToServer(rs); + verifyDestinationTableData(expectedBigDecimals.length * 3); + } + + String sql = "insert into " + desTable + " values (?,?,?,?)"; + Calendar calGMT = Calendar.getInstance(TimeZone.getTimeZone("GMT")); + try (SQLServerPreparedStatement pstmt1 = (SQLServerPreparedStatement) conn.prepareStatement(sql)) { + for (int i = 0; i < expectedBigDecimals.length; i++) { + pstmt1.setBigDecimal(1, expectedBigDecimals[i]); + pstmt1.setString(2, expectedStrings[i]); + pstmt1.setTimestamp(3, expectedTimestamps[i], calGMT); + pstmt1.setString(4, expectedStrings[i]); + pstmt1.execute(); + } + verifyDestinationTableData(expectedBigDecimals.length * 4); + } + try (ResultSet rs2 = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE) + .executeQuery("select * from " + srcTable); + SQLServerBulkCopy bulkCopy3 = new SQLServerBulkCopy(conn)) { + bulkCopy3.setDestinationTableName(desTable); + bulkCopy3.writeToServer(rs2); + verifyDestinationTableData(expectedBigDecimals.length * 5); + } + } + } } private static void verifyDestinationTableData(int expectedNumberOfRows) throws SQLException { try (Connection conn = DriverManager.getConnection(connectionString); - ResultSet rs = conn.createStatement().executeQuery("select * from " + desTable)) { - - int expectedArrayLength = expectedBigDecimals.length; - - int i = 0; - while (rs.next()) { - assertTrue(rs.getString(1).equals(expectedBigDecimalStrings[i % expectedArrayLength]), - "Expected Value:" + expectedBigDecimalStrings[i % expectedArrayLength] + ", Actual Value: " + rs.getString(1)); - assertTrue(rs.getString(2).trim().equals(expectedStrings[i % expectedArrayLength]), - "Expected Value:" + expectedStrings[i % expectedArrayLength] + ", Actual Value: " + rs.getString(2)); - assertTrue(rs.getString(3).equals(expectedTimestampStrings[i % expectedArrayLength]), - "Expected Value:" + expectedTimestampStrings[i % expectedArrayLength] + ", Actual Value: " + rs.getString(3)); - assertTrue(rs.getString(4).trim().equals(expectedStrings[i % expectedArrayLength]), - "Expected Value:" + expectedStrings[i % expectedArrayLength] + ", Actual Value: " + rs.getString(4)); - i++; - } - - assertTrue(i == expectedNumberOfRows); + ResultSet rs = conn.createStatement().executeQuery("select * from " + desTable)) { + + int expectedArrayLength = expectedBigDecimals.length; + + int i = 0; + while (rs.next()) { + assertTrue(rs.getString(1).equals(expectedBigDecimalStrings[i % expectedArrayLength]), "Expected Value:" + + expectedBigDecimalStrings[i % expectedArrayLength] + ", Actual Value: " + rs.getString(1)); + assertTrue(rs.getString(2).trim().equals(expectedStrings[i % expectedArrayLength]), "Expected Value:" + + expectedStrings[i % expectedArrayLength] + ", Actual Value: " + rs.getString(2)); + assertTrue(rs.getString(3).equals(expectedTimestampStrings[i % expectedArrayLength]), "Expected Value:" + + expectedTimestampStrings[i % expectedArrayLength] + ", Actual Value: " + rs.getString(3)); + assertTrue(rs.getString(4).trim().equals(expectedStrings[i % expectedArrayLength]), "Expected Value:" + + expectedStrings[i % expectedArrayLength] + ", Actual Value: " + rs.getString(4)); + i++; + } + + assertTrue(i == expectedNumberOfRows); } } @@ -185,15 +188,15 @@ private static void populateSourceTable() throws SQLException { Calendar calGMT = Calendar.getInstance(TimeZone.getTimeZone("GMT")); try (Connection conn = DriverManager.getConnection(connectionString); - SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) conn.prepareStatement(sql)) { - - for (int i = 0; i < expectedBigDecimals.length; i++) { - pstmt.setBigDecimal(1, expectedBigDecimals[i]); - pstmt.setString(2, expectedStrings[i]); - pstmt.setTimestamp(3, expectedTimestamps[i], calGMT); - pstmt.setString(4, expectedStrings[i]); - pstmt.execute(); - } + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) conn.prepareStatement(sql)) { + + for (int i = 0; i < expectedBigDecimals.length; i++) { + pstmt.setBigDecimal(1, expectedBigDecimals[i]); + pstmt.setString(2, expectedStrings[i]); + pstmt.setTimestamp(3, expectedTimestamps[i], calGMT); + pstmt.setString(4, expectedStrings[i]); + pstmt.execute(); + } } } @@ -203,10 +206,12 @@ private static void dropTables(Statement stmt) throws SQLException { } private static void createTables(Statement stmt) throws SQLException { - String sql = "create table " + srcTable + " (c1 decimal(10,5) null, c2 nchar(50) null, c3 datetime2(7) null, c4 char(7000));"; + String sql = "create table " + srcTable + + " (c1 decimal(10,5) null, c2 nchar(50) null, c3 datetime2(7) null, c4 char(7000));"; stmt.execute(sql); - sql = "create table " + desTable + " (c1 decimal(10,5) null, c2 nchar(50) null, c3 datetime2(7) null, c4 char(7000));"; + sql = "create table " + desTable + + " (c1 decimal(10,5) null, c2 nchar(50) null, c3 datetime2(7) null, c4 char(7000));"; stmt.execute(sql); } -} \ No newline at end of file +} diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTestSetUp.java b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTestSetUp.java index f916336de..4573fda29 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTestSetUp.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTestSetUp.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.bulkCopy; @@ -20,6 +17,7 @@ import com.microsoft.sqlserver.testframework.DBStatement; import com.microsoft.sqlserver.testframework.DBTable;; + /** * Create and drop source table needed for testing bulk copy */ @@ -30,13 +28,13 @@ public class BulkCopyTestSetUp extends AbstractTest { /** * Create source table needed for testing bulk copy - * @throws SQLException + * + * @throws SQLException */ @BeforeAll - static void setUpSourceTable() throws SQLException { - try (DBConnection con = new DBConnection(connectionString); - DBStatement stmt = con.createStatement(); - DBPreparedStatement pstmt = new DBPreparedStatement(con);) { + public static void setUpSourceTable() throws SQLException { + try (DBConnection con = new DBConnection(connectionString); DBStatement stmt = con.createStatement(); + DBPreparedStatement pstmt = new DBPreparedStatement(con);) { sourceTable = new DBTable(true); stmt.createTable(sourceTable); pstmt.populateTable(sourceTable); @@ -45,12 +43,12 @@ static void setUpSourceTable() throws SQLException { /** * drop source table after testing bulk copy - * @throws SQLException + * + * @throws SQLException */ @AfterAll - static void dropSourceTable() throws SQLException { - try (DBConnection con = new DBConnection(connectionString); - DBStatement stmt = con.createStatement()) { + public static void dropSourceTable() throws SQLException { + try (DBConnection con = new DBConnection(connectionString); DBStatement stmt = con.createStatement()) { stmt.dropTable(sourceTable); } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTestUtil.java b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTestUtil.java index 78b6ac18d..b1352dc13 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTestUtil.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTestUtil.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.bulkCopy; @@ -13,16 +10,18 @@ import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; + import com.microsoft.sqlserver.jdbc.ISQLServerBulkRecord; import com.microsoft.sqlserver.jdbc.SQLServerBulkCopy; -import com.microsoft.sqlserver.jdbc.bulkCopy.BulkCopyTestWrapper.ColumnMap; import com.microsoft.sqlserver.jdbc.TestResource; +import com.microsoft.sqlserver.jdbc.bulkCopy.BulkCopyTestWrapper.ColumnMap; import com.microsoft.sqlserver.testframework.DBConnection; import com.microsoft.sqlserver.testframework.DBResultSet; import com.microsoft.sqlserver.testframework.DBStatement; import com.microsoft.sqlserver.testframework.DBTable; import com.microsoft.sqlserver.testframework.util.ComparisonUtil; + /** * Utility class */ @@ -34,8 +33,7 @@ class BulkCopyTestUtil { * @param wrapper * @param sourceTable */ - static void performBulkCopy(BulkCopyTestWrapper wrapper, - DBTable sourceTable) { + static void performBulkCopy(BulkCopyTestWrapper wrapper, DBTable sourceTable) { performBulkCopy(wrapper, sourceTable, true); } @@ -46,9 +44,7 @@ static void performBulkCopy(BulkCopyTestWrapper wrapper, * @param sourceTable * @param destTable */ - static void performBulkCopy(BulkCopyTestWrapper wrapper, - DBTable sourceTable, - DBTable destTable) { + static void performBulkCopy(BulkCopyTestWrapper wrapper, DBTable sourceTable, DBTable destTable) { performBulkCopy(wrapper, sourceTable, destTable, true); } @@ -59,54 +55,46 @@ static void performBulkCopy(BulkCopyTestWrapper wrapper, * @param sourceTable * @param validateResult */ - static void performBulkCopy(BulkCopyTestWrapper wrapper, - DBTable sourceTable, - boolean validateResult) { + static void performBulkCopy(BulkCopyTestWrapper wrapper, DBTable sourceTable, boolean validateResult) { DBTable destinationTable = null; try (DBConnection con = new DBConnection(wrapper.getConnectionString()); - DBStatement stmt = con.createStatement()) { + DBStatement stmt = con.createStatement()) { destinationTable = sourceTable.cloneSchema(); stmt.createTable(destinationTable); - try (DBResultSet srcResultSet = stmt.executeQuery("SELECT * FROM " + sourceTable.getEscapedTableName() + ";"); - SQLServerBulkCopy bulkCopy = wrapper.isUsingConnection() ? - new SQLServerBulkCopy((Connection) con.product()) : - new SQLServerBulkCopy(wrapper.getConnectionString())) { - if (wrapper.isUsingBulkCopyOptions()) { - bulkCopy.setBulkCopyOptions(wrapper.getBulkOptions()); - } - bulkCopy.setDestinationTableName(destinationTable.getEscapedTableName()); - if (wrapper.isUsingColumnMapping()) { - for (int i = 0; i < wrapper.cm.size(); i++) { - ColumnMap currentMap = wrapper.cm.get(i); - if (currentMap.sourceIsInt && currentMap.destIsInt) { - bulkCopy.addColumnMapping(currentMap.srcInt, currentMap.destInt); - } - else if (currentMap.sourceIsInt && (!currentMap.destIsInt)) { - bulkCopy.addColumnMapping(currentMap.srcInt, currentMap.destString); - } - else if ((!currentMap.sourceIsInt) && currentMap.destIsInt) { - bulkCopy.addColumnMapping(currentMap.srcString, currentMap.destInt); - } - else if ((!currentMap.sourceIsInt) && (!currentMap.destIsInt)) { - bulkCopy.addColumnMapping(currentMap.srcString, currentMap.destString); - } - } - } - bulkCopy.writeToServer((ResultSet) srcResultSet.product()); - if (validateResult) { - validateValues(con, sourceTable, destinationTable); - } - } - catch (SQLException ex) { + try (DBResultSet srcResultSet = stmt + .executeQuery("SELECT * FROM " + sourceTable.getEscapedTableName() + ";"); + SQLServerBulkCopy bulkCopy = wrapper.isUsingConnection() ? new SQLServerBulkCopy( + (Connection) con.product()) : new SQLServerBulkCopy(wrapper.getConnectionString())) { + if (wrapper.isUsingBulkCopyOptions()) { + bulkCopy.setBulkCopyOptions(wrapper.getBulkOptions()); + } + bulkCopy.setDestinationTableName(destinationTable.getEscapedTableName()); + if (wrapper.isUsingColumnMapping()) { + for (int i = 0; i < wrapper.cm.size(); i++) { + ColumnMap currentMap = wrapper.cm.get(i); + if (currentMap.sourceIsInt && currentMap.destIsInt) { + bulkCopy.addColumnMapping(currentMap.srcInt, currentMap.destInt); + } else if (currentMap.sourceIsInt && (!currentMap.destIsInt)) { + bulkCopy.addColumnMapping(currentMap.srcInt, currentMap.destString); + } else if ((!currentMap.sourceIsInt) && currentMap.destIsInt) { + bulkCopy.addColumnMapping(currentMap.srcString, currentMap.destInt); + } else if ((!currentMap.sourceIsInt) && (!currentMap.destIsInt)) { + bulkCopy.addColumnMapping(currentMap.srcString, currentMap.destString); + } + } + } + bulkCopy.writeToServer((ResultSet) srcResultSet.product()); + if (validateResult) { + validateValues(con, sourceTable, destinationTable); + } + } catch (SQLException ex) { fail(ex.getMessage()); - } - finally { + } finally { stmt.dropTable(destinationTable); con.close(); } - } - catch (SQLException ex) { + } catch (SQLException ex) { fail(ex.getMessage()); } } @@ -119,16 +107,14 @@ else if ((!currentMap.sourceIsInt) && (!currentMap.destIsInt)) { * @param destTable * @param validateResult */ - static void performBulkCopy(BulkCopyTestWrapper wrapper, - DBTable sourceTable, - DBTable destinationTable, + static void performBulkCopy(BulkCopyTestWrapper wrapper, DBTable sourceTable, DBTable destinationTable, boolean validateResult) { try (DBConnection con = new DBConnection(wrapper.getConnectionString()); - DBStatement stmt = con.createStatement(); - DBResultSet srcResultSet = stmt.executeQuery("SELECT * FROM " + sourceTable.getEscapedTableName() + ";"); - SQLServerBulkCopy bulkCopy = wrapper.isUsingConnection() ? - new SQLServerBulkCopy((Connection) con.product()) : - new SQLServerBulkCopy(wrapper.getConnectionString())) { + DBStatement stmt = con.createStatement(); + DBResultSet srcResultSet = stmt + .executeQuery("SELECT * FROM " + sourceTable.getEscapedTableName() + ";"); + SQLServerBulkCopy bulkCopy = wrapper.isUsingConnection() ? new SQLServerBulkCopy( + (Connection) con.product()) : new SQLServerBulkCopy(wrapper.getConnectionString())) { if (wrapper.isUsingBulkCopyOptions()) { bulkCopy.setBulkCopyOptions(wrapper.getBulkOptions()); } @@ -138,14 +124,11 @@ static void performBulkCopy(BulkCopyTestWrapper wrapper, ColumnMap currentMap = wrapper.cm.get(i); if (currentMap.sourceIsInt && currentMap.destIsInt) { bulkCopy.addColumnMapping(currentMap.srcInt, currentMap.destInt); - } - else if (currentMap.sourceIsInt && (!currentMap.destIsInt)) { + } else if (currentMap.sourceIsInt && (!currentMap.destIsInt)) { bulkCopy.addColumnMapping(currentMap.srcInt, currentMap.destString); - } - else if ((!currentMap.sourceIsInt) && currentMap.destIsInt) { + } else if ((!currentMap.sourceIsInt) && currentMap.destIsInt) { bulkCopy.addColumnMapping(currentMap.srcString, currentMap.destInt); - } - else if ((!currentMap.sourceIsInt) && (!currentMap.destIsInt)) { + } else if ((!currentMap.sourceIsInt) && (!currentMap.destIsInt)) { bulkCopy.addColumnMapping(currentMap.srcString, currentMap.destString); } } @@ -154,8 +137,7 @@ else if ((!currentMap.sourceIsInt) && (!currentMap.destIsInt)) { if (validateResult) { validateValues(con, sourceTable, destinationTable); } - } - catch (SQLException ex) { + } catch (SQLException ex) { fail(ex.getMessage()); } } @@ -169,59 +151,52 @@ else if ((!currentMap.sourceIsInt) && (!currentMap.destIsInt)) { * @param validateResult * @param fail */ - static void performBulkCopy(BulkCopyTestWrapper wrapper, - DBTable sourceTable, - DBTable destinationTable, - boolean validateResult, - boolean fail) { + static void performBulkCopy(BulkCopyTestWrapper wrapper, DBTable sourceTable, DBTable destinationTable, + boolean validateResult, boolean fail) { try (DBConnection con = new DBConnection(wrapper.getConnectionString()); - DBStatement stmt = con.createStatement(); - DBResultSet srcResultSet = stmt.executeQuery("SELECT * FROM " + sourceTable.getEscapedTableName() + ";"); - SQLServerBulkCopy bulkCopy = wrapper.isUsingConnection() ? - new SQLServerBulkCopy((Connection) con.product()) : - new SQLServerBulkCopy(wrapper.getConnectionString())) { + DBStatement stmt = con.createStatement(); + DBResultSet srcResultSet = stmt + .executeQuery("SELECT * FROM " + sourceTable.getEscapedTableName() + ";"); + SQLServerBulkCopy bulkCopy = wrapper.isUsingConnection() ? new SQLServerBulkCopy( + (Connection) con.product()) : new SQLServerBulkCopy(wrapper.getConnectionString())) { try { - if (wrapper.isUsingBulkCopyOptions()) { - bulkCopy.setBulkCopyOptions(wrapper.getBulkOptions()); - } - bulkCopy.setDestinationTableName(destinationTable.getEscapedTableName()); - if (wrapper.isUsingColumnMapping()) { - for (int i = 0; i < wrapper.cm.size(); i++) { - ColumnMap currentMap = wrapper.cm.get(i); - if (currentMap.sourceIsInt && currentMap.destIsInt) { - bulkCopy.addColumnMapping(currentMap.srcInt, currentMap.destInt); - } - else if (currentMap.sourceIsInt && (!currentMap.destIsInt)) { - bulkCopy.addColumnMapping(currentMap.srcInt, currentMap.destString); - } - else if ((!currentMap.sourceIsInt) && currentMap.destIsInt) { - bulkCopy.addColumnMapping(currentMap.srcString, currentMap.destInt); - } - else if ((!currentMap.sourceIsInt) && (!currentMap.destIsInt)) { - bulkCopy.addColumnMapping(currentMap.srcString, currentMap.destString); - } - } - } - bulkCopy.writeToServer((ResultSet) srcResultSet.product()); - if (fail) - fail(TestResource.getResource("R_expectedExceptionNotThrown")); - if (validateResult) { - validateValues(con, sourceTable, destinationTable); - } - } catch (SQLException ex) { - if (!fail) { - fail(ex.getMessage()); - } - } - finally { - stmt.dropTable(destinationTable); - con.close(); - } + if (wrapper.isUsingBulkCopyOptions()) { + bulkCopy.setBulkCopyOptions(wrapper.getBulkOptions()); + } + bulkCopy.setDestinationTableName(destinationTable.getEscapedTableName()); + if (wrapper.isUsingColumnMapping()) { + for (int i = 0; i < wrapper.cm.size(); i++) { + ColumnMap currentMap = wrapper.cm.get(i); + if (currentMap.sourceIsInt && currentMap.destIsInt) { + bulkCopy.addColumnMapping(currentMap.srcInt, currentMap.destInt); + } else if (currentMap.sourceIsInt && (!currentMap.destIsInt)) { + bulkCopy.addColumnMapping(currentMap.srcInt, currentMap.destString); + } else if ((!currentMap.sourceIsInt) && currentMap.destIsInt) { + bulkCopy.addColumnMapping(currentMap.srcString, currentMap.destInt); + } else if ((!currentMap.sourceIsInt) && (!currentMap.destIsInt)) { + bulkCopy.addColumnMapping(currentMap.srcString, currentMap.destString); + } + } + } + bulkCopy.writeToServer((ResultSet) srcResultSet.product()); + if (fail) + fail(TestResource.getResource("R_expectedExceptionNotThrown")); + if (validateResult) { + validateValues(con, sourceTable, destinationTable); + } + } catch (SQLException ex) { + if (!fail) { + fail(ex.getMessage()); + } + } finally { + stmt.dropTable(destinationTable); + con.close(); + } } catch (SQLException e) { if (!fail) { fail(e.getMessage()); } - } + } } /** @@ -234,61 +209,51 @@ else if ((!currentMap.sourceIsInt) && (!currentMap.destIsInt)) { * @param fail * @param dropDest */ - static void performBulkCopy(BulkCopyTestWrapper wrapper, - DBTable sourceTable, - DBTable destinationTable, - boolean validateResult, - boolean fail, - boolean dropDest) { + static void performBulkCopy(BulkCopyTestWrapper wrapper, DBTable sourceTable, DBTable destinationTable, + boolean validateResult, boolean fail, boolean dropDest) { try (DBConnection con = new DBConnection(wrapper.getConnectionString()); - DBStatement stmt = con.createStatement(); - DBResultSet srcResultSet = stmt.executeQuery("SELECT * FROM " + sourceTable.getEscapedTableName() + ";"); - SQLServerBulkCopy bulkCopy = wrapper.isUsingConnection() ? - new SQLServerBulkCopy((Connection) con.product()) : - new SQLServerBulkCopy(wrapper.getConnectionString())) { + DBStatement stmt = con.createStatement(); + DBResultSet srcResultSet = stmt + .executeQuery("SELECT * FROM " + sourceTable.getEscapedTableName() + ";"); + SQLServerBulkCopy bulkCopy = wrapper.isUsingConnection() ? new SQLServerBulkCopy( + (Connection) con.product()) : new SQLServerBulkCopy(wrapper.getConnectionString())) { try { - if (wrapper.isUsingBulkCopyOptions()) { - bulkCopy.setBulkCopyOptions(wrapper.getBulkOptions()); - } - bulkCopy.setDestinationTableName(destinationTable.getEscapedTableName()); - if (wrapper.isUsingColumnMapping()) { - for (int i = 0; i < wrapper.cm.size(); i++) { - ColumnMap currentMap = wrapper.cm.get(i); - if (currentMap.sourceIsInt && currentMap.destIsInt) { - bulkCopy.addColumnMapping(currentMap.srcInt, currentMap.destInt); - } - else if (currentMap.sourceIsInt && (!currentMap.destIsInt)) { - bulkCopy.addColumnMapping(currentMap.srcInt, currentMap.destString); - } - else if ((!currentMap.sourceIsInt) && currentMap.destIsInt) { - bulkCopy.addColumnMapping(currentMap.srcString, currentMap.destInt); - } - else if ((!currentMap.sourceIsInt) && (!currentMap.destIsInt)) { - bulkCopy.addColumnMapping(currentMap.srcString, currentMap.destString); - } - } - } - bulkCopy.writeToServer((ResultSet) srcResultSet.product()); - if (fail) - fail(TestResource.getResource("R_expectedExceptionNotThrown")); - bulkCopy.close(); - if (validateResult) { - validateValues(con, sourceTable, destinationTable); - } - } - catch (SQLException ex) { - if (!fail) { - fail(ex.getMessage()); - } - } - finally { - if (dropDest) { - stmt.dropTable(destinationTable); - } - con.close(); - } - } - catch (SQLException ex) { + if (wrapper.isUsingBulkCopyOptions()) { + bulkCopy.setBulkCopyOptions(wrapper.getBulkOptions()); + } + bulkCopy.setDestinationTableName(destinationTable.getEscapedTableName()); + if (wrapper.isUsingColumnMapping()) { + for (int i = 0; i < wrapper.cm.size(); i++) { + ColumnMap currentMap = wrapper.cm.get(i); + if (currentMap.sourceIsInt && currentMap.destIsInt) { + bulkCopy.addColumnMapping(currentMap.srcInt, currentMap.destInt); + } else if (currentMap.sourceIsInt && (!currentMap.destIsInt)) { + bulkCopy.addColumnMapping(currentMap.srcInt, currentMap.destString); + } else if ((!currentMap.sourceIsInt) && currentMap.destIsInt) { + bulkCopy.addColumnMapping(currentMap.srcString, currentMap.destInt); + } else if ((!currentMap.sourceIsInt) && (!currentMap.destIsInt)) { + bulkCopy.addColumnMapping(currentMap.srcString, currentMap.destString); + } + } + } + bulkCopy.writeToServer((ResultSet) srcResultSet.product()); + if (fail) + fail(TestResource.getResource("R_expectedExceptionNotThrown")); + bulkCopy.close(); + if (validateResult) { + validateValues(con, sourceTable, destinationTable); + } + } catch (SQLException ex) { + if (!fail) { + fail(ex.getMessage()); + } + } finally { + if (dropDest) { + stmt.dropTable(destinationTable); + } + con.close(); + } + } catch (SQLException ex) { if (!fail) { fail(ex.getMessage()); } @@ -303,28 +268,27 @@ else if ((!currentMap.sourceIsInt) && (!currentMap.destIsInt)) { * @param destinationTable * @throws SQLException */ - static void validateValues(DBConnection con, - DBTable sourceTable, - DBTable destinationTable) throws SQLException { - try (DBStatement srcStmt = con.createStatement(); - DBStatement dstStmt = con.createStatement(); - DBResultSet srcResultSet = srcStmt.executeQuery("SELECT * FROM " + sourceTable.getEscapedTableName() + ";"); - DBResultSet dstResultSet = dstStmt.executeQuery("SELECT * FROM " + destinationTable.getEscapedTableName() + ";")) { - ResultSetMetaData destMeta = ((ResultSet) dstResultSet.product()).getMetaData(); - int totalColumns = destMeta.getColumnCount(); - - // verify data from sourceType and resultSet - while (srcResultSet.next() && dstResultSet.next()) { - for (int i = 1; i <= totalColumns; i++) { - // TODO: check row and column count in both the tables - - Object srcValue, dstValue; - srcValue = srcResultSet.getObject(i); - dstValue = dstResultSet.getObject(i); - - ComparisonUtil.compareExpectedAndActual(destMeta.getColumnType(i), srcValue, dstValue); - } - } + static void validateValues(DBConnection con, DBTable sourceTable, DBTable destinationTable) throws SQLException { + try (DBStatement srcStmt = con.createStatement(); DBStatement dstStmt = con.createStatement(); + DBResultSet srcResultSet = srcStmt + .executeQuery("SELECT * FROM " + sourceTable.getEscapedTableName() + ";"); + DBResultSet dstResultSet = dstStmt + .executeQuery("SELECT * FROM " + destinationTable.getEscapedTableName() + ";")) { + ResultSetMetaData destMeta = ((ResultSet) dstResultSet.product()).getMetaData(); + int totalColumns = destMeta.getColumnCount(); + + // verify data from sourceType and resultSet + while (srcResultSet.next() && dstResultSet.next()) { + for (int i = 1; i <= totalColumns; i++) { + // TODO: check row and column count in both the tables + + Object srcValue, dstValue; + srcValue = srcResultSet.getObject(i); + dstValue = dstResultSet.getObject(i); + + ComparisonUtil.compareExpectedAndActual(destMeta.getColumnType(i), srcValue, dstValue); + } + } } } @@ -334,21 +298,18 @@ static void validateValues(DBConnection con, * @param srcData * @param dstTable */ - static void performBulkCopy(BulkCopyTestWrapper bulkWrapper, - ISQLServerBulkRecord srcData, - DBTable dstTable) { + static void performBulkCopy(BulkCopyTestWrapper bulkWrapper, ISQLServerBulkRecord srcData, DBTable dstTable) { try (DBConnection con = new DBConnection(bulkWrapper.getConnectionString()); - DBStatement stmt = con.createStatement(); - SQLServerBulkCopy bc = new SQLServerBulkCopy(bulkWrapper.getConnectionString());) { + DBStatement stmt = con.createStatement(); + SQLServerBulkCopy bc = new SQLServerBulkCopy(bulkWrapper.getConnectionString());) { bc.setDestinationTableName(dstTable.getEscapedTableName()); bc.writeToServer(srcData); validateValues(con, srcData, dstTable); - } - catch (Exception e) { + } catch (Exception e) { fail(e.getMessage()); } } - + /** * * @param con @@ -356,43 +317,41 @@ static void performBulkCopy(BulkCopyTestWrapper bulkWrapper, * @param destinationTable * @throws Exception */ - static void validateValues( - DBConnection con, - ISQLServerBulkRecord srcData, + static void validateValues(DBConnection con, ISQLServerBulkRecord srcData, DBTable destinationTable) throws Exception { - - try (DBStatement dstStmt = con.createStatement(); - DBResultSet dstResultSet = dstStmt.executeQuery("SELECT * FROM " + destinationTable.getEscapedTableName() + ";")) { - ResultSetMetaData destMeta = ((ResultSet) dstResultSet.product()).getMetaData(); - int totalColumns = destMeta.getColumnCount(); - - // reset the counter in ISQLServerBulkRecord, which was incremented during read by BulkCopy - java.lang.reflect.Method method = srcData.getClass().getMethod("reset"); - method.invoke(srcData); - - // verify data from sourceType and resultSet - while (srcData.next() && dstResultSet.next()) - { - Object[] srcValues = srcData.getRowData(); - for (int i = 1; i <= totalColumns; i++) { - - Object srcValue, dstValue; - srcValue = srcValues[i-1]; - if(srcValue.getClass().getName().equalsIgnoreCase("java.lang.Double")){ - // in case of SQL Server type Float (ie java type double), in float(n) if n is <=24 ie precsion is <=7 SQL Server type Real is returned(ie java type float) - if(destMeta.getPrecision(i) <8) - srcValue = ((Double)srcValue).floatValue(); - } - dstValue = dstResultSet.getObject(i); - int dstType = destMeta.getColumnType(i); - if(java.sql.Types.TIMESTAMP != dstType - && java.sql.Types.TIME != dstType - && microsoft.sql.Types.DATETIMEOFFSET != dstType){ - // skip validation for temporal types due to rounding eg 7986-10-21 09:51:15.114 is rounded as 7986-10-21 09:51:15.113 in server - ComparisonUtil.compareExpectedAndActual(dstType, srcValue, dstValue); - } - } - } + + try (DBStatement dstStmt = con.createStatement(); DBResultSet dstResultSet = dstStmt + .executeQuery("SELECT * FROM " + destinationTable.getEscapedTableName() + ";")) { + ResultSetMetaData destMeta = ((ResultSet) dstResultSet.product()).getMetaData(); + int totalColumns = destMeta.getColumnCount(); + + // reset the counter in ISQLServerBulkRecord, which was incremented during read by BulkCopy + java.lang.reflect.Method method = srcData.getClass().getMethod("reset"); + method.invoke(srcData); + + // verify data from sourceType and resultSet + while (srcData.next() && dstResultSet.next()) { + Object[] srcValues = srcData.getRowData(); + for (int i = 1; i <= totalColumns; i++) { + + Object srcValue, dstValue; + srcValue = srcValues[i - 1]; + if (srcValue.getClass().getName().equalsIgnoreCase("java.lang.Double")) { + // in case of SQL Server type Float (ie java type double), in float(n) if n is <=24 ie precsion + // is <=7 SQL Server type Real is returned(ie java type float) + if (destMeta.getPrecision(i) < 8) + srcValue = ((Double) srcValue).floatValue(); + } + dstValue = dstResultSet.getObject(i); + int dstType = destMeta.getColumnType(i); + if (java.sql.Types.TIMESTAMP != dstType && java.sql.Types.TIME != dstType + && microsoft.sql.Types.DATETIMEOFFSET != dstType) { + // skip validation for temporal types due to rounding eg 7986-10-21 09:51:15.114 is rounded as + // 7986-10-21 09:51:15.113 in server + ComparisonUtil.compareExpectedAndActual(dstType, srcValue, dstValue); + } + } + } } } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTestWrapper.java b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTestWrapper.java index c6be7261c..3bde9718c 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTestWrapper.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTestWrapper.java @@ -1,169 +1,159 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ -package com.microsoft.sqlserver.jdbc.bulkCopy; - -import java.util.LinkedList; - -import com.microsoft.sqlserver.jdbc.SQLServerBulkCopyOptions; - -/** - * Wrapper class that has all the data/values needed to execute BulkCopy test case - */ -class BulkCopyTestWrapper { - /** - * Test case name - */ - String testName; - - /** - * true if SQLServerBulkCopy should use connection object - */ - private boolean isUsingConnection; - - /** - * true if SQLServerBulkCopy should include SQLServerBulkCopyOptions - */ - private boolean useBulkCopyOptions; - - /** - * true if SQLServerBulkCopy should use column mapping - */ - private boolean isUsingColumnMapping = false; - - public LinkedList cm = new LinkedList<>(); - - private SQLServerBulkCopyOptions bulkOptions; - - private String connectionString; - - BulkCopyTestWrapper(String connectionString) { - this.connectionString = connectionString; - } - - /** - * - * @return - */ - public boolean isUsingConnection() { - return isUsingConnection; - } - - /** - * - * @param isUsingConnection - * true if connection object should be passed in BulkCopy constructor false if connection string is to be - * passed to constructor - */ - public void setUsingConnection(boolean isUsingConnection) { - this.isUsingConnection = isUsingConnection; - testName += "isUsingConnection=" + isUsingConnection + ";"; - } - - public boolean isUsingBulkCopyOptions() { - return useBulkCopyOptions; - } - - public void useBulkCopyOptions(boolean useBulkCopyOptions) { - this.useBulkCopyOptions = useBulkCopyOptions; - testName += "useBulkCopyOptions=" + useBulkCopyOptions + ";"; - } - - public SQLServerBulkCopyOptions getBulkOptions() { - return bulkOptions; - } - - public void setBulkOptions(SQLServerBulkCopyOptions bulkOptions) { - this.bulkOptions = bulkOptions; - } - - public String getConnectionString() { - return connectionString; - } - - public void setConnectionString(String connectionString) { - this.connectionString = connectionString; - } - - public void setUsingColumnMapping() { - this.isUsingColumnMapping = true; - } - - public boolean isUsingColumnMapping() { - return isUsingColumnMapping; - } - - public void setColumnMapping(int sourceColOrdinal, - int destColOrdinal) { - setUsingColumnMapping(); - cm.add(new ColumnMap(sourceColOrdinal, destColOrdinal)); - } - - public void setColumnMapping(int sourceColOrdinal, - String destColName) { - setUsingColumnMapping(); - cm.add(new ColumnMap(sourceColOrdinal, destColName)); - } - - public void setColumnMapping(String sourceColName, - String destColName) { - setUsingColumnMapping(); - cm.add(new ColumnMap(sourceColName, destColName)); - } - - public void setColumnMapping(String sourceColName, - int destColOrdinal) { - setUsingColumnMapping(); - cm.add(new ColumnMap(sourceColName, destColOrdinal)); - } - - class ColumnMap { - boolean sourceIsInt = false; - boolean destIsInt = false; - - int srcInt = -1; - String srcString = null; - int destInt = -1; - String destString = null; - - ColumnMap(int src, - int dest) { - this.sourceIsInt = true; - this.destIsInt = true; - - this.srcInt = src; - this.destInt = dest; - } - - ColumnMap(String src, - int dest) { - this.sourceIsInt = false; - this.destIsInt = true; - - this.srcString = src; - this.destInt = dest; - } - - ColumnMap(int src, - String dest) { - this.sourceIsInt = true; - this.destIsInt = false; - - this.srcInt = src; - this.destString = dest; - } - - ColumnMap(String src, - String dest) { - this.sourceIsInt = false; - this.destIsInt = false; - - this.srcString = src; - this.destString = dest; - } - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package com.microsoft.sqlserver.jdbc.bulkCopy; + +import java.util.LinkedList; + +import com.microsoft.sqlserver.jdbc.SQLServerBulkCopyOptions; + + +/** + * Wrapper class that has all the data/values needed to execute BulkCopy test case + */ +class BulkCopyTestWrapper { + /** + * Test case name + */ + String testName; + + /** + * true if SQLServerBulkCopy should use connection object + */ + private boolean isUsingConnection; + + /** + * true if SQLServerBulkCopy should include SQLServerBulkCopyOptions + */ + private boolean useBulkCopyOptions; + + /** + * true if SQLServerBulkCopy should use column mapping + */ + private boolean isUsingColumnMapping = false; + + public LinkedList cm = new LinkedList<>(); + + private SQLServerBulkCopyOptions bulkOptions; + + private String connectionString; + + BulkCopyTestWrapper(String connectionString) { + this.connectionString = connectionString; + } + + /** + * + * @return + */ + public boolean isUsingConnection() { + return isUsingConnection; + } + + /** + * + * @param isUsingConnection + * true if connection object should be passed in BulkCopy constructor false if + * connection string is to be passed to constructor + */ + public void setUsingConnection(boolean isUsingConnection) { + this.isUsingConnection = isUsingConnection; + testName += "isUsingConnection=" + isUsingConnection + ";"; + } + + public boolean isUsingBulkCopyOptions() { + return useBulkCopyOptions; + } + + public void useBulkCopyOptions(boolean useBulkCopyOptions) { + this.useBulkCopyOptions = useBulkCopyOptions; + testName += "useBulkCopyOptions=" + useBulkCopyOptions + ";"; + } + + public SQLServerBulkCopyOptions getBulkOptions() { + return bulkOptions; + } + + public void setBulkOptions(SQLServerBulkCopyOptions bulkOptions) { + this.bulkOptions = bulkOptions; + } + + public String getConnectionString() { + return connectionString; + } + + public void setConnectionString(String connectionString) { + this.connectionString = connectionString; + } + + public void setUsingColumnMapping() { + this.isUsingColumnMapping = true; + } + + public boolean isUsingColumnMapping() { + return isUsingColumnMapping; + } + + public void setColumnMapping(int sourceColOrdinal, int destColOrdinal) { + setUsingColumnMapping(); + cm.add(new ColumnMap(sourceColOrdinal, destColOrdinal)); + } + + public void setColumnMapping(int sourceColOrdinal, String destColName) { + setUsingColumnMapping(); + cm.add(new ColumnMap(sourceColOrdinal, destColName)); + } + + public void setColumnMapping(String sourceColName, String destColName) { + setUsingColumnMapping(); + cm.add(new ColumnMap(sourceColName, destColName)); + } + + public void setColumnMapping(String sourceColName, int destColOrdinal) { + setUsingColumnMapping(); + cm.add(new ColumnMap(sourceColName, destColOrdinal)); + } + + class ColumnMap { + boolean sourceIsInt = false; + boolean destIsInt = false; + + int srcInt = -1; + String srcString = null; + int destInt = -1; + String destString = null; + + ColumnMap(int src, int dest) { + this.sourceIsInt = true; + this.destIsInt = true; + + this.srcInt = src; + this.destInt = dest; + } + + ColumnMap(String src, int dest) { + this.sourceIsInt = false; + this.destIsInt = true; + + this.srcString = src; + this.destInt = dest; + } + + ColumnMap(int src, String dest) { + this.sourceIsInt = true; + this.destIsInt = false; + + this.srcInt = src; + this.destString = dest; + } + + ColumnMap(String src, String dest) { + this.sourceIsInt = false; + this.destIsInt = false; + + this.srcString = src; + this.destString = dest; + } + } +} diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTimeoutTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTimeoutTest.java index 0db8f67a7..c3497adf8 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTimeoutTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyTimeoutTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.bulkCopy; @@ -19,6 +16,7 @@ import com.microsoft.sqlserver.jdbc.SQLServerBulkCopyOptions; + /** * Test the timeout in SQLServerBulkCopyOptions. Source table is created with large row count so skip data validation. */ @@ -27,7 +25,8 @@ public class BulkCopyTimeoutTest extends BulkCopyTestSetUp { /** - * TODO: add support for small timeout value once test framework has support to add more than 10K rows, to check for Timeout Exception + * TODO: add support for small timeout value once test framework has support to add more than 10K rows, to check for + * Timeout Exception */ /** @@ -37,7 +36,7 @@ public class BulkCopyTimeoutTest extends BulkCopyTestSetUp { */ @Test @DisplayName("BulkCopy:test zero timeout") - void testZeroTimeOut() throws SQLException { + public void testZeroTimeOut() throws SQLException { testBulkCopyWithTimeout(0); } @@ -48,7 +47,7 @@ void testZeroTimeOut() throws SQLException { */ @Test @DisplayName("BulkCopy:test negative timeout") - void testNegativeTimeOut() throws SQLException { + public void testNegativeTimeOut() throws SQLException { assertThrows(SQLException.class, new org.junit.jupiter.api.function.Executable() { @Override public void execute() throws SQLException { @@ -56,9 +55,9 @@ public void execute() throws SQLException { } }); } - + private void testBulkCopyWithTimeout(int timeout) throws SQLException { - BulkCopyTestWrapper bulkWrapper = new BulkCopyTestWrapper(connectionString); + BulkCopyTestWrapper bulkWrapper = new BulkCopyTestWrapper(connectionString); bulkWrapper.setUsingConnection((0 == ThreadLocalRandom.current().nextInt(2)) ? true : false); SQLServerBulkCopyOptions option = new SQLServerBulkCopyOptions(); option.setBulkCopyTimeout(timeout); diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/ISQLServerBulkRecordIssuesTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/ISQLServerBulkRecordIssuesTest.java index bb24c65dc..e0325b319 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/ISQLServerBulkRecordIssuesTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/ISQLServerBulkRecordIssuesTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.bulkCopy; @@ -18,12 +15,12 @@ import java.sql.SQLException; import java.sql.Statement; import java.sql.Timestamp; +import java.text.MessageFormat; +import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Set; -import java.text.MessageFormat; -import java.time.format.DateTimeFormatter; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; @@ -40,430 +37,397 @@ import com.microsoft.sqlserver.testframework.AbstractTest; import com.microsoft.sqlserver.testframework.Utils; + @RunWith(JUnitPlatform.class) public class ISQLServerBulkRecordIssuesTest extends AbstractTest { - static Statement stmt = null; - static PreparedStatement pStmt = null; - static String query; - static SQLServerConnection con = null; - static String srcTable = "sourceTable"; - static String destTable = "destTable"; - String variation; - - /** - * Testing that sending a bigger varchar(3) to varchar(2) is thowing the - * proper error message. - * - * @throws Exception - */ - @Test - public void testVarchar() throws Exception { - variation = "testVarchar"; - BulkData bData = new BulkData(variation); - query = "CREATE TABLE " + destTable + " (smallDATA varchar(2))"; - stmt.executeUpdate(query); - - try (SQLServerBulkCopy bcOperation = new SQLServerBulkCopy( - connectionString)) { - bcOperation.setDestinationTableName(destTable); - bcOperation.writeToServer(bData); - bcOperation.close(); - fail(TestResource.getResource("R_expectedFailPassed")); - } catch (Exception e) { - if (e instanceof SQLException) { - assertTrue( - e.getMessage().contains( - TestResource.getResource("R_givenValueType")), - TestResource.getResource("R_invalidErrorMessage") - + e.toString()); - } else { - fail(e.getMessage()); - } - } - } - - /** - * Testing that setting scale and precision 0 in column meta data for - * smalldatetime should work - * - * @throws Exception - */ - @Test - public void testSmalldatetime() throws Exception { - variation = "testSmalldatetime"; - BulkData bData = new BulkData(variation); - String value = ("1954-05-22 02:44:00.0").toString(); - query = "CREATE TABLE " + destTable + " (smallDATA smalldatetime)"; - stmt.executeUpdate(query); - - try (SQLServerBulkCopy bcOperation = new SQLServerBulkCopy( - connectionString)) { - bcOperation.setDestinationTableName(destTable); - bcOperation.writeToServer(bData); - - try (ResultSet rs = stmt - .executeQuery("select * from " + destTable)) { - while (rs.next()) { - assertEquals(rs.getString(1), value); - } - } - } - } - - /** - * Testing that setting out of range value for small datetime is throwing - * the proper message - * - * @throws Exception - */ - @Test - public void testSmalldatetimeOutofRange() throws Exception { - variation = "testSmalldatetimeOutofRange"; - BulkData bData = new BulkData(variation); - - query = "CREATE TABLE " + destTable + " (smallDATA smalldatetime)"; - stmt.executeUpdate(query); - - try (SQLServerBulkCopy bcOperation = new SQLServerBulkCopy( - connectionString)) { - bcOperation.setDestinationTableName(destTable); - bcOperation.writeToServer(bData); - fail("BulkCopy executed for testSmalldatetimeOutofRange when it it was expected to fail"); - } catch (Exception e) { - if (e instanceof SQLException) { - MessageFormat form = new MessageFormat( - TestResource.getResource("R_conversionFailed")); - Object[] msgArgs = {"character string", "smalldatetime"}; - - assertTrue(e.getMessage().contains(form.format(msgArgs)), - TestResource.getResource("R_invalidErrorMessage") - + e.toString()); - } else { - fail(e.getMessage()); - } - } - } - - /** - * Test binary out of length (sending length of 6 to binary (5)) - * - * @throws Exception - */ - @Test - public void testBinaryColumnAsByte() throws Exception { - variation = "testBinaryColumnAsByte"; - BulkData bData = new BulkData(variation); - query = "CREATE TABLE " + destTable + " (col1 binary(5))"; - stmt.executeUpdate(query); - - try (SQLServerBulkCopy bcOperation = new SQLServerBulkCopy( - connectionString)) { - bcOperation.setDestinationTableName(destTable); - bcOperation.writeToServer(bData); - fail(TestResource.getResource("R_expectedFailPassed")); - } catch (Exception e) { - if (e instanceof SQLException) { - assertTrue( - e.getMessage().contains( - TestResource.getResource("R_givenValueType")), - TestResource.getResource("R_invalidErrorMessage") - + e.toString()); - } else { - fail(e.getMessage()); - } - } - } - - /** - * Test sending longer value for binary column while data is sent as string - * format - * - * @throws Exception - */ - @Test - public void testBinaryColumnAsString() throws Exception { - variation = "testBinaryColumnAsString"; - BulkData bData = new BulkData(variation); - query = "CREATE TABLE " + destTable + " (col1 binary(5))"; - stmt.executeUpdate(query); - - try (SQLServerBulkCopy bcOperation = new SQLServerBulkCopy( - connectionString)) { - bcOperation.setDestinationTableName(destTable); - bcOperation.writeToServer(bData); - fail(TestResource.getResource("R_expectedFailPassed")); - } catch (Exception e) { - if (e instanceof SQLException) { - assertTrue( - e.getMessage().contains( - TestResource.getResource("R_givenValueType")), - TestResource.getResource("R_invalidErrorMessage") - + e.toString()); - } else { - fail(e.getMessage()); - } - } - } - - /** - * Verify that sending valid value in string format for binary column is - * successful - * - * @throws Exception - */ - @Test - public void testSendValidValueforBinaryColumnAsString() throws Exception { - variation = "testSendValidValueforBinaryColumnAsString"; - BulkData bData = new BulkData(variation); - query = "CREATE TABLE " + destTable + " (col1 binary(5))"; - stmt.executeUpdate(query); - - try (SQLServerBulkCopy bcOperation = new SQLServerBulkCopy( - connectionString)) { - bcOperation.setDestinationTableName(destTable); - bcOperation.writeToServer(bData); - - try (ResultSet rs = stmt - .executeQuery("select * from " + destTable)) { - while (rs.next()) { - assertEquals(rs.getString(1), "0101010000"); - } - } - } catch (Exception e) { - fail(e.getMessage()); - } - } - - /** - * Prepare test - * - * @throws SQLException - * @throws SecurityException - * @throws IOException - */ - @BeforeAll - public static void setupHere() - throws SQLException, SecurityException, IOException { - con = (SQLServerConnection) DriverManager - .getConnection(connectionString); - stmt = con.createStatement(); - Utils.dropTableIfExists(destTable, stmt); - Utils.dropTableIfExists(srcTable, stmt); - } - - /** - * Clean up - * - * @throws SQLException - */ - @AfterEach - public void afterEachTests() throws SQLException { - Utils.dropTableIfExists(destTable, stmt); - Utils.dropTableIfExists(srcTable, stmt); - } - - @AfterAll - public static void afterAllTests() throws SQLException { - if (null != stmt) { - stmt.close(); - } - if (null != con) { - con.close(); - } - } + static Statement stmt = null; + static PreparedStatement pStmt = null; + static String query; + static SQLServerConnection con = null; + static String srcTable = "sourceTable"; + static String destTable = "destTable"; + String variation; + + /** + * Testing that sending a bigger varchar(3) to varchar(2) is thowing the proper error message. + * + * @throws Exception + */ + @Test + public void testVarchar() throws Exception { + variation = "testVarchar"; + BulkData bData = new BulkData(variation); + query = "CREATE TABLE " + destTable + " (smallDATA varchar(2))"; + stmt.executeUpdate(query); + + try (SQLServerBulkCopy bcOperation = new SQLServerBulkCopy(connectionString)) { + bcOperation.setDestinationTableName(destTable); + bcOperation.writeToServer(bData); + bcOperation.close(); + fail(TestResource.getResource("R_expectedFailPassed")); + } catch (Exception e) { + if (e instanceof SQLException) { + assertTrue(e.getMessage().contains(TestResource.getResource("R_givenValueType")), + TestResource.getResource("R_invalidErrorMessage") + e.toString()); + } else { + fail(e.getMessage()); + } + } + } + + /** + * Testing that setting scale and precision 0 in column meta data for smalldatetime should work + * + * @throws Exception + */ + @Test + public void testSmalldatetime() throws Exception { + variation = "testSmalldatetime"; + BulkData bData = new BulkData(variation); + String value = ("1954-05-22 02:44:00.0").toString(); + query = "CREATE TABLE " + destTable + " (smallDATA smalldatetime)"; + stmt.executeUpdate(query); + + try (SQLServerBulkCopy bcOperation = new SQLServerBulkCopy(connectionString)) { + bcOperation.setDestinationTableName(destTable); + bcOperation.writeToServer(bData); + + try (ResultSet rs = stmt.executeQuery("select * from " + destTable)) { + while (rs.next()) { + assertEquals(rs.getString(1), value); + } + } + } + } + + /** + * Testing that setting out of range value for small datetime is throwing the proper message + * + * @throws Exception + */ + @Test + public void testSmalldatetimeOutofRange() throws Exception { + variation = "testSmalldatetimeOutofRange"; + BulkData bData = new BulkData(variation); + + query = "CREATE TABLE " + destTable + " (smallDATA smalldatetime)"; + stmt.executeUpdate(query); + + try (SQLServerBulkCopy bcOperation = new SQLServerBulkCopy(connectionString)) { + bcOperation.setDestinationTableName(destTable); + bcOperation.writeToServer(bData); + fail("BulkCopy executed for testSmalldatetimeOutofRange when it it was expected to fail"); + } catch (Exception e) { + if (e instanceof SQLException) { + MessageFormat form = new MessageFormat(TestResource.getResource("R_conversionFailed")); + Object[] msgArgs = {"character string", "smalldatetime"}; + + assertTrue(e.getMessage().contains(form.format(msgArgs)), + TestResource.getResource("R_invalidErrorMessage") + e.toString()); + } else { + fail(e.getMessage()); + } + } + } + + /** + * Test binary out of length (sending length of 6 to binary (5)) + * + * @throws Exception + */ + @Test + public void testBinaryColumnAsByte() throws Exception { + variation = "testBinaryColumnAsByte"; + BulkData bData = new BulkData(variation); + query = "CREATE TABLE " + destTable + " (col1 binary(5))"; + stmt.executeUpdate(query); + + try (SQLServerBulkCopy bcOperation = new SQLServerBulkCopy(connectionString)) { + bcOperation.setDestinationTableName(destTable); + bcOperation.writeToServer(bData); + fail(TestResource.getResource("R_expectedFailPassed")); + } catch (Exception e) { + if (e instanceof SQLException) { + assertTrue(e.getMessage().contains(TestResource.getResource("R_givenValueType")), + TestResource.getResource("R_invalidErrorMessage") + e.toString()); + } else { + fail(e.getMessage()); + } + } + } + + /** + * Test sending longer value for binary column while data is sent as string format + * + * @throws Exception + */ + @Test + public void testBinaryColumnAsString() throws Exception { + variation = "testBinaryColumnAsString"; + BulkData bData = new BulkData(variation); + query = "CREATE TABLE " + destTable + " (col1 binary(5))"; + stmt.executeUpdate(query); + + try (SQLServerBulkCopy bcOperation = new SQLServerBulkCopy(connectionString)) { + bcOperation.setDestinationTableName(destTable); + bcOperation.writeToServer(bData); + fail(TestResource.getResource("R_expectedFailPassed")); + } catch (Exception e) { + if (e instanceof SQLException) { + assertTrue(e.getMessage().contains(TestResource.getResource("R_givenValueType")), + TestResource.getResource("R_invalidErrorMessage") + e.toString()); + } else { + fail(e.getMessage()); + } + } + } + + /** + * Verify that sending valid value in string format for binary column is successful + * + * @throws Exception + */ + @Test + public void testSendValidValueforBinaryColumnAsString() throws Exception { + variation = "testSendValidValueforBinaryColumnAsString"; + BulkData bData = new BulkData(variation); + query = "CREATE TABLE " + destTable + " (col1 binary(5))"; + stmt.executeUpdate(query); + + try (SQLServerBulkCopy bcOperation = new SQLServerBulkCopy(connectionString)) { + bcOperation.setDestinationTableName(destTable); + bcOperation.writeToServer(bData); + + try (ResultSet rs = stmt.executeQuery("select * from " + destTable)) { + while (rs.next()) { + assertEquals(rs.getString(1), "0101010000"); + } + } + } catch (Exception e) { + fail(e.getMessage()); + } + } + + /** + * Prepare test + * + * @throws SQLException + * @throws SecurityException + * @throws IOException + */ + @BeforeAll + public static void setupHere() throws SQLException, SecurityException, IOException { + con = (SQLServerConnection) DriverManager.getConnection(connectionString); + stmt = con.createStatement(); + Utils.dropTableIfExists(destTable, stmt); + Utils.dropTableIfExists(srcTable, stmt); + } + + /** + * Clean up + * + * @throws SQLException + */ + @AfterEach + public void afterEachTests() throws SQLException { + Utils.dropTableIfExists(destTable, stmt); + Utils.dropTableIfExists(srcTable, stmt); + } + + @AfterAll + public static void afterAllTests() throws SQLException { + if (null != stmt) { + stmt.close(); + } + if (null != con) { + con.close(); + } + } } + class BulkData implements ISQLServerBulkRecord { - boolean isStringData = false; + boolean isStringData = false; + + private class ColumnMetadata { + String columnName; + int columnType; + int precision; + int scale; + + ColumnMetadata(String name, int type, int precision, int scale) { + columnName = name; + columnType = type; + this.precision = precision; + this.scale = scale; + } + } + + Map columnMetadata; + ArrayList dateData; + ArrayList stringData; + ArrayList byteData; - private class ColumnMetadata { - String columnName; - int columnType; - int precision; - int scale; - - ColumnMetadata(String name, int type, int precision, int scale) { - columnName = name; - columnType = type; - this.precision = precision; - this.scale = scale; - } - } - - Map columnMetadata; - ArrayList dateData; - ArrayList stringData; - ArrayList byteData; - - int counter = 0; - int rowCount = 1; - - BulkData(String variation) { - if (variation.equalsIgnoreCase("testVarchar")) { - isStringData = true; - columnMetadata = new HashMap<>(); - - columnMetadata.put(1, new ColumnMetadata("varchar(2)", - java.sql.Types.VARCHAR, 0, 0)); - - stringData = new ArrayList<>(); - stringData.add(new String("aaa")); - rowCount = stringData.size(); - } else if (variation.equalsIgnoreCase("testSmalldatetime")) { - isStringData = false; - columnMetadata = new HashMap<>(); - - columnMetadata.put(1, new ColumnMetadata("smallDatetime", - java.sql.Types.TIMESTAMP, 0, 0)); - - dateData = new ArrayList<>(); - dateData.add(Timestamp.valueOf("1954-05-22 02:43:37.123")); - rowCount = dateData.size(); - } else if (variation.equalsIgnoreCase("testSmalldatetimeOutofRange")) { - isStringData = false; - columnMetadata = new HashMap<>(); - - columnMetadata.put(1, new ColumnMetadata("smallDatetime", - java.sql.Types.TIMESTAMP, 0, 0)); - - dateData = new ArrayList<>(); - dateData.add(Timestamp.valueOf("1954-05-22 02:43:37.1234")); - rowCount = dateData.size(); - - } else if (variation.equalsIgnoreCase("testBinaryColumnAsByte")) { - isStringData = false; - columnMetadata = new HashMap<>(); - - columnMetadata.put(1, new ColumnMetadata("binary(5)", - java.sql.Types.BINARY, 5, 0)); - - byteData = new ArrayList<>(); - byteData.add("helloo".getBytes()); - rowCount = byteData.size(); - - } else if (variation.equalsIgnoreCase("testBinaryColumnAsString")) { - isStringData = true; - columnMetadata = new HashMap<>(); - - columnMetadata.put(1, new ColumnMetadata("binary(5)", - java.sql.Types.BINARY, 5, 0)); - - stringData = new ArrayList<>(); - stringData.add("616368697412"); - rowCount = stringData.size(); - - } - - else if (variation.equalsIgnoreCase( - "testSendValidValueforBinaryColumnAsString")) { - isStringData = true; - columnMetadata = new HashMap<>(); - - columnMetadata.put(1, new ColumnMetadata("binary(5)", - java.sql.Types.BINARY, 5, 0)); - - stringData = new ArrayList<>(); - stringData.add("010101"); - rowCount = stringData.size(); - - } - counter = 0; - - } - - @Override - public Set getColumnOrdinals() { - return columnMetadata.keySet(); - } - - @Override - public String getColumnName(int column) { - return columnMetadata.get(column).columnName; - } - - @Override - public int getColumnType(int column) { - return columnMetadata.get(column).columnType; - } - - @Override - public int getPrecision(int column) { - return columnMetadata.get(column).precision; - } - - @Override - public int getScale(int column) { - return columnMetadata.get(column).scale; - } - - @Override - public boolean isAutoIncrement(int column) { - return false; - } - - @Override - public Object[] getRowData() throws SQLServerException { - Object[] dataRow = new Object[columnMetadata.size()]; - if (isStringData) - dataRow[0] = stringData.get(counter); - else { - if (null != dateData) - dataRow[0] = dateData.get(counter); - else if (null != byteData) - dataRow[0] = byteData.get(counter); - } - counter++; - return dataRow; - } - - @Override - public boolean next() throws SQLServerException { - if (counter < rowCount) { - return true; - } - return false; - } - - @Override - public void addColumnMetadata(int positionInFile, String name, int jdbcType, - int precision, int scale, DateTimeFormatter dateTimeFormatter) - throws SQLServerException { - // TODO Not Implemented - } - - @Override - public void addColumnMetadata(int positionInFile, String name, int jdbcType, - int precision, int scale) throws SQLServerException { - // TODO Not Implemented - } - - @Override - public void setTimestampWithTimezoneFormat(String dateTimeFormat) { - // TODO Not Implemented - } - - @Override - public void setTimestampWithTimezoneFormat( - DateTimeFormatter dateTimeFormatter) { - // TODO Not Implemented - } - - @Override - public void setTimeWithTimezoneFormat(String timeFormat) { - // TODO Not Implemented - } - - @Override - public void setTimeWithTimezoneFormat(DateTimeFormatter dateTimeFormatter) { - // TODO Not Implemented - } - - @Override - public DateTimeFormatter getColumnDateTimeFormatter(int column) { - // TODO Not Implemented - return null; - } + int counter = 0; + int rowCount = 1; + + BulkData(String variation) { + if (variation.equalsIgnoreCase("testVarchar")) { + isStringData = true; + columnMetadata = new HashMap<>(); + + columnMetadata.put(1, new ColumnMetadata("varchar(2)", java.sql.Types.VARCHAR, 0, 0)); + + stringData = new ArrayList<>(); + stringData.add(new String("aaa")); + rowCount = stringData.size(); + } else if (variation.equalsIgnoreCase("testSmalldatetime")) { + isStringData = false; + columnMetadata = new HashMap<>(); + + columnMetadata.put(1, new ColumnMetadata("smallDatetime", java.sql.Types.TIMESTAMP, 0, 0)); + + dateData = new ArrayList<>(); + dateData.add(Timestamp.valueOf("1954-05-22 02:43:37.123")); + rowCount = dateData.size(); + } else if (variation.equalsIgnoreCase("testSmalldatetimeOutofRange")) { + isStringData = false; + columnMetadata = new HashMap<>(); + + columnMetadata.put(1, new ColumnMetadata("smallDatetime", java.sql.Types.TIMESTAMP, 0, 0)); + + dateData = new ArrayList<>(); + dateData.add(Timestamp.valueOf("1954-05-22 02:43:37.1234")); + rowCount = dateData.size(); + + } else if (variation.equalsIgnoreCase("testBinaryColumnAsByte")) { + isStringData = false; + columnMetadata = new HashMap<>(); + + columnMetadata.put(1, new ColumnMetadata("binary(5)", java.sql.Types.BINARY, 5, 0)); + + byteData = new ArrayList<>(); + byteData.add("helloo".getBytes()); + rowCount = byteData.size(); + + } else if (variation.equalsIgnoreCase("testBinaryColumnAsString")) { + isStringData = true; + columnMetadata = new HashMap<>(); + + columnMetadata.put(1, new ColumnMetadata("binary(5)", java.sql.Types.BINARY, 5, 0)); + + stringData = new ArrayList<>(); + stringData.add("616368697412"); + rowCount = stringData.size(); + + } + + else if (variation.equalsIgnoreCase("testSendValidValueforBinaryColumnAsString")) { + isStringData = true; + columnMetadata = new HashMap<>(); + + columnMetadata.put(1, new ColumnMetadata("binary(5)", java.sql.Types.BINARY, 5, 0)); + + stringData = new ArrayList<>(); + stringData.add("010101"); + rowCount = stringData.size(); + + } + counter = 0; + + } + + @Override + public Set getColumnOrdinals() { + return columnMetadata.keySet(); + } + + @Override + public String getColumnName(int column) { + return columnMetadata.get(column).columnName; + } + + @Override + public int getColumnType(int column) { + return columnMetadata.get(column).columnType; + } + + @Override + public int getPrecision(int column) { + return columnMetadata.get(column).precision; + } + + @Override + public int getScale(int column) { + return columnMetadata.get(column).scale; + } + + @Override + public boolean isAutoIncrement(int column) { + return false; + } + + @Override + public Object[] getRowData() throws SQLServerException { + Object[] dataRow = new Object[columnMetadata.size()]; + if (isStringData) + dataRow[0] = stringData.get(counter); + else { + if (null != dateData) + dataRow[0] = dateData.get(counter); + else if (null != byteData) + dataRow[0] = byteData.get(counter); + } + counter++; + return dataRow; + } + + @Override + public boolean next() throws SQLServerException { + if (counter < rowCount) { + return true; + } + return false; + } + + @Override + public void addColumnMetadata(int positionInFile, String name, int jdbcType, int precision, int scale, + DateTimeFormatter dateTimeFormatter) throws SQLServerException { + // TODO Not Implemented + } + + @Override + public void addColumnMetadata(int positionInFile, String name, int jdbcType, int precision, + int scale) throws SQLServerException { + // TODO Not Implemented + } + + @Override + public void setTimestampWithTimezoneFormat(String dateTimeFormat) { + // TODO Not Implemented + } + + @Override + public void setTimestampWithTimezoneFormat(DateTimeFormatter dateTimeFormatter) { + // TODO Not Implemented + } + + @Override + public void setTimeWithTimezoneFormat(String timeFormat) { + // TODO Not Implemented + } + + @Override + public void setTimeWithTimezoneFormat(DateTimeFormatter dateTimeFormatter) { + // TODO Not Implemented + } + + @Override + public DateTimeFormatter getColumnDateTimeFormatter(int column) { + // TODO Not Implemented + return null; + } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/SqlTypeMapping.java b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/SqlTypeMapping.java index 2fd0a8aa6..820ce02d5 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/SqlTypeMapping.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/SqlTypeMapping.java @@ -1,79 +1,76 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ -package com.microsoft.sqlserver.jdbc.bulkCopy; - -import com.microsoft.sqlserver.testframework.sqlType.SqlBigInt; -import com.microsoft.sqlserver.testframework.sqlType.SqlBinary; -import com.microsoft.sqlserver.testframework.sqlType.SqlBit; -import com.microsoft.sqlserver.testframework.sqlType.SqlChar; -import com.microsoft.sqlserver.testframework.sqlType.SqlDate; -import com.microsoft.sqlserver.testframework.sqlType.SqlDateTime; -import com.microsoft.sqlserver.testframework.sqlType.SqlDateTime2; -import com.microsoft.sqlserver.testframework.sqlType.SqlDateTimeOffset; -import com.microsoft.sqlserver.testframework.sqlType.SqlDecimal; -import com.microsoft.sqlserver.testframework.sqlType.SqlFloat; -import com.microsoft.sqlserver.testframework.sqlType.SqlInt; -import com.microsoft.sqlserver.testframework.sqlType.SqlMoney; -import com.microsoft.sqlserver.testframework.sqlType.SqlNChar; -import com.microsoft.sqlserver.testframework.sqlType.SqlNVarChar; -import com.microsoft.sqlserver.testframework.sqlType.SqlNumeric; -import com.microsoft.sqlserver.testframework.sqlType.SqlReal; -import com.microsoft.sqlserver.testframework.sqlType.SqlSmallDateTime; -import com.microsoft.sqlserver.testframework.sqlType.SqlSmallInt; -import com.microsoft.sqlserver.testframework.sqlType.SqlSmallMoney; -import com.microsoft.sqlserver.testframework.sqlType.SqlTime; -import com.microsoft.sqlserver.testframework.sqlType.SqlTinyInt; -import com.microsoft.sqlserver.testframework.sqlType.SqlType; -import com.microsoft.sqlserver.testframework.sqlType.SqlVarBinary; -import com.microsoft.sqlserver.testframework.sqlType.SqlVarChar; - -/** - * enum that returns object of desired datatype based for JDBCType type - */ -public enum SqlTypeMapping { - - BIGINT (new SqlBigInt()), - INT (new SqlInt()), - SMALLINT (new SqlSmallInt()), - TINYINT (new SqlTinyInt()), - BIT (new SqlBit()), - DECIMAL (new SqlDecimal()), - NUMERIC (new SqlNumeric()), - MONEY (new SqlMoney()), - SMALLMONEY (new SqlSmallMoney()), - // Appx Numeric - FLOAT (new SqlFloat()), - REAL (new SqlReal()), - // Character - CHAR (new SqlChar()), - VARCHAR (new SqlVarChar()), - // Unicode - NCHAR (new SqlNChar()), - NVARCHAR (new SqlNVarChar()), - // Temporal - DATETIME (new SqlDateTime()), - DATE (new SqlDate()), - TIME (new SqlTime()), - SMALLDATETIME (new SqlSmallDateTime()), - DATETIME2 (new SqlDateTime2()), - DATETIMEOFFSET (new SqlDateTimeOffset()), - //Binary - BINARY (new SqlBinary()), - VARBINARY (new SqlVarBinary()), - ; - - public SqlType sqlType; - - /** - * - * @param type - */ - SqlTypeMapping(SqlType type) { - this.sqlType = type; - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package com.microsoft.sqlserver.jdbc.bulkCopy; + +import com.microsoft.sqlserver.testframework.sqlType.SqlBigInt; +import com.microsoft.sqlserver.testframework.sqlType.SqlBinary; +import com.microsoft.sqlserver.testframework.sqlType.SqlBit; +import com.microsoft.sqlserver.testframework.sqlType.SqlChar; +import com.microsoft.sqlserver.testframework.sqlType.SqlDate; +import com.microsoft.sqlserver.testframework.sqlType.SqlDateTime; +import com.microsoft.sqlserver.testframework.sqlType.SqlDateTime2; +import com.microsoft.sqlserver.testframework.sqlType.SqlDateTimeOffset; +import com.microsoft.sqlserver.testframework.sqlType.SqlDecimal; +import com.microsoft.sqlserver.testframework.sqlType.SqlFloat; +import com.microsoft.sqlserver.testframework.sqlType.SqlInt; +import com.microsoft.sqlserver.testframework.sqlType.SqlMoney; +import com.microsoft.sqlserver.testframework.sqlType.SqlNChar; +import com.microsoft.sqlserver.testframework.sqlType.SqlNVarChar; +import com.microsoft.sqlserver.testframework.sqlType.SqlNumeric; +import com.microsoft.sqlserver.testframework.sqlType.SqlReal; +import com.microsoft.sqlserver.testframework.sqlType.SqlSmallDateTime; +import com.microsoft.sqlserver.testframework.sqlType.SqlSmallInt; +import com.microsoft.sqlserver.testframework.sqlType.SqlSmallMoney; +import com.microsoft.sqlserver.testframework.sqlType.SqlTime; +import com.microsoft.sqlserver.testframework.sqlType.SqlTinyInt; +import com.microsoft.sqlserver.testframework.sqlType.SqlType; +import com.microsoft.sqlserver.testframework.sqlType.SqlVarBinary; +import com.microsoft.sqlserver.testframework.sqlType.SqlVarChar; + + +/** + * enum that returns object of desired datatype based for JDBCType type + */ +public enum SqlTypeMapping { + + BIGINT(new SqlBigInt()), + INT(new SqlInt()), + SMALLINT(new SqlSmallInt()), + TINYINT(new SqlTinyInt()), + BIT(new SqlBit()), + DECIMAL(new SqlDecimal()), + NUMERIC(new SqlNumeric()), + MONEY(new SqlMoney()), + SMALLMONEY(new SqlSmallMoney()), + // Appx Numeric + FLOAT(new SqlFloat()), + REAL(new SqlReal()), + // Character + CHAR(new SqlChar()), + VARCHAR(new SqlVarChar()), + // Unicode + NCHAR(new SqlNChar()), + NVARCHAR(new SqlNVarChar()), + // Temporal + DATETIME(new SqlDateTime()), + DATE(new SqlDate()), + TIME(new SqlTime()), + SMALLDATETIME(new SqlSmallDateTime()), + DATETIME2(new SqlDateTime2()), + DATETIMEOFFSET(new SqlDateTimeOffset()), + // Binary + BINARY(new SqlBinary()), + VARBINARY(new SqlVarBinary()),; + + public SqlType sqlType; + + /** + * + * @param type + */ + SqlTypeMapping(SqlType type) { + this.sqlType = type; + } +} diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTest.java index d96044039..9f7885eb5 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.bvt; @@ -23,13 +20,13 @@ import org.junit.platform.runner.JUnitPlatform; import org.junit.runner.RunWith; +import com.microsoft.sqlserver.jdbc.TestResource; import com.microsoft.sqlserver.testframework.DBConnection; import com.microsoft.sqlserver.testframework.DBPreparedStatement; import com.microsoft.sqlserver.testframework.DBResultSet; import com.microsoft.sqlserver.testframework.DBResultSetTypes; -import com.microsoft.sqlserver.testframework.DBStatement; +import com.microsoft.sqlserver.testframework.DBStatement;; -import com.microsoft.sqlserver.jdbc.TestResource;; @RunWith(JUnitPlatform.class) @DisplayName("BVT Test") @@ -88,11 +85,10 @@ public void testDriverNameAndDriverVersion() throws SQLException { @Test public void testCreateStatement() throws SQLException { - String query = "SELECT * FROM " + table1.getEscapedTableName() + ";"; - - try (DBConnection conn = new DBConnection(connectionString); - DBStatement stmt = conn.createStatement(); - DBResultSet rs = stmt.executeQuery(query)) { + String query = "SELECT * FROM " + table1.getEscapedTableName() + ";"; + + try (DBConnection conn = new DBConnection(connectionString); DBStatement stmt = conn.createStatement(); + DBResultSet rs = stmt.executeQuery(query)) { rs.verify(table1); } } @@ -106,14 +102,14 @@ public void testCreateStatement() throws SQLException { public void testCreateStatementWithQueryTimeout() throws SQLException { try (DBConnection conn = new DBConnection(connectionString + ";querytimeout=10"); - DBStatement stmt = conn.createStatement()) { + DBStatement stmt = conn.createStatement()) { assertEquals(10, stmt.getQueryTimeout()); } } /** - * Create a statement ResultSet.Type_forward_only, ResultSet.CONCUR_READ_ONLY, executeQuery verify cursor by using next and previous and verify - * data + * Create a statement ResultSet.Type_forward_only, ResultSet.CONCUR_READ_ONLY, executeQuery verify cursor by using + * next and previous and verify data * * @throws SQLException * @throws ClassNotFoundException @@ -121,11 +117,11 @@ public void testCreateStatementWithQueryTimeout() throws SQLException { @Test public void testStmtForwardOnlyReadOnly() throws SQLException, ClassNotFoundException { - String query = "SELECT * FROM " + table1.getEscapedTableName(); - + String query = "SELECT * FROM " + table1.getEscapedTableName(); + try (DBConnection conn = new DBConnection(connectionString); - DBStatement stmt = conn.createStatement(DBResultSetTypes.TYPE_FORWARD_ONLY_CONCUR_READ_ONLY); - DBResultSet rs = stmt.executeQuery(query)) { + DBStatement stmt = conn.createStatement(DBResultSetTypes.TYPE_FORWARD_ONLY_CONCUR_READ_ONLY); + DBResultSet rs = stmt.executeQuery(query)) { rs.next(); rs.verifyCurrentRow(table1); @@ -135,8 +131,7 @@ public void testStmtForwardOnlyReadOnly() throws SQLException, ClassNotFoundExce try { rs.previous(); assertTrue(false, "Previous should have thrown an exception"); - } - catch (SQLException ex) { + } catch (SQLException ex) { // expected exception } rs.verify(table1); @@ -144,8 +139,8 @@ public void testStmtForwardOnlyReadOnly() throws SQLException, ClassNotFoundExce } /** - * Create a statement, ResultSet.SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY, executeQuery verify cursor by using next, afterlast and previous - * and verify data + * Create a statement, ResultSet.SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY, executeQuery verify cursor by using + * next, afterlast and previous and verify data * * @throws SQLException * @throws ClassNotFoundException @@ -153,8 +148,8 @@ public void testStmtForwardOnlyReadOnly() throws SQLException, ClassNotFoundExce @Test public void testStmtScrollInsensitiveReadOnly() throws SQLException, ClassNotFoundException { try (DBConnection conn = new DBConnection(connectionString); - DBStatement stmt = conn.createStatement(DBResultSetTypes.TYPE_SCROLL_INSENSITIVE_CONCUR_READ_ONLY); - DBResultSet rs = stmt.selectAll(table1)) { + DBStatement stmt = conn.createStatement(DBResultSetTypes.TYPE_SCROLL_INSENSITIVE_CONCUR_READ_ONLY); + DBResultSet rs = stmt.selectAll(table1)) { rs.next(); rs.verifyCurrentRow(table1); rs.afterLast(); @@ -165,8 +160,8 @@ public void testStmtScrollInsensitiveReadOnly() throws SQLException, ClassNotFou } /** - * Create a statement ResultSet.SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY, executeQuery verify cursor by using next and absolute and verify - * data + * Create a statement ResultSet.SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY, executeQuery verify cursor by using + * next and absolute and verify data * * @throws SQLException */ @@ -174,10 +169,10 @@ public void testStmtScrollInsensitiveReadOnly() throws SQLException, ClassNotFou public void testStmtScrollSensitiveReadOnly() throws SQLException { String query = "SELECT * FROM " + table1.getEscapedTableName(); - + try (DBConnection conn = new DBConnection(connectionString); - DBStatement stmt = conn.createStatement(DBResultSetTypes.TYPE_SCROLL_SENSITIVE_CONCUR_READ_ONLY); - DBResultSet rs = stmt.executeQuery(query)) { + DBStatement stmt = conn.createStatement(DBResultSetTypes.TYPE_SCROLL_SENSITIVE_CONCUR_READ_ONLY); + DBResultSet rs = stmt.executeQuery(query)) { rs.next(); rs.next(); rs.verifyCurrentRow(table1); @@ -190,19 +185,19 @@ public void testStmtScrollSensitiveReadOnly() throws SQLException { } /** - * Create a statement ResultSet.Type_forward_only, ResultSet.CONCUR_UPDATABLE, executeQuery verify cursor by using next and previous and verify - * data + * Create a statement ResultSet.Type_forward_only, ResultSet.CONCUR_UPDATABLE, executeQuery verify cursor by using + * next and previous and verify data * * @throws SQLException */ @Test public void testStmtForwardOnlyUpdateable() throws SQLException { - - String query = "SELECT * FROM " + table1.getEscapedTableName(); + + String query = "SELECT * FROM " + table1.getEscapedTableName(); try (DBConnection conn = new DBConnection(connectionString); - DBStatement stmt = conn.createStatement(DBResultSetTypes.TYPE_FORWARD_ONLY_CONCUR_UPDATABLE); - DBResultSet rs = stmt.executeQuery(query)) { + DBStatement stmt = conn.createStatement(DBResultSetTypes.TYPE_FORWARD_ONLY_CONCUR_UPDATABLE); + DBResultSet rs = stmt.executeQuery(query)) { rs.next(); // Verify resultset behavior @@ -213,8 +208,7 @@ public void testStmtForwardOnlyUpdateable() throws SQLException { try { rs.previous(); assertTrue(false, TestResource.getResource("R_previousShouldThrow")); - } - catch (SQLException ex) { + } catch (SQLException ex) { // expected exception } rs.verify(table1); @@ -222,19 +216,19 @@ public void testStmtForwardOnlyUpdateable() throws SQLException { } /** - * Create a statement ResultSet.SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE, executeQuery verify cursor by using next and previous and verify - * data + * Create a statement ResultSet.SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE, executeQuery verify cursor by using + * next and previous and verify data * * @throws SQLException */ @Test public void testStmtScrollSensitiveUpdatable() throws SQLException { - String query = "SELECT * FROM " + table1.getEscapedTableName(); - + String query = "SELECT * FROM " + table1.getEscapedTableName(); + try (DBConnection conn = new DBConnection(connectionString); - DBStatement stmt = conn.createStatement(DBResultSetTypes.TYPE_SCROLL_SENSITIVE_CONCUR_UPDATABLE); - DBResultSet rs = stmt.executeQuery(query)) { + DBStatement stmt = conn.createStatement(DBResultSetTypes.TYPE_SCROLL_SENSITIVE_CONCUR_UPDATABLE); + DBResultSet rs = stmt.executeQuery(query)) { // Verify resultset behavior rs.next(); @@ -248,7 +242,8 @@ public void testStmtScrollSensitiveUpdatable() throws SQLException { } /** - * Create a statement TYPE_SS_SCROLL_DYNAMIC, CONCUR_SS_OPTIMISTIC_CC, executeQuery verify cursor by using next and previous and verify data + * Create a statement TYPE_SS_SCROLL_DYNAMIC, CONCUR_SS_OPTIMISTIC_CC, executeQuery verify cursor by using next and + * previous and verify data * * @throws SQLException */ @@ -256,8 +251,8 @@ public void testStmtScrollSensitiveUpdatable() throws SQLException { public void testStmtSSScrollDynamicOptimisticCC() throws SQLException { try (DBConnection conn = new DBConnection(connectionString); - DBStatement stmt = conn.createStatement(DBResultSetTypes.TYPE_DYNAMIC_CONCUR_OPTIMISTIC); - DBResultSet rs = stmt.selectAll(table1)) { + DBStatement stmt = conn.createStatement(DBResultSetTypes.TYPE_DYNAMIC_CONCUR_OPTIMISTIC); + DBResultSet rs = stmt.selectAll(table1)) { // Verify resultset behavior rs.next(); @@ -268,7 +263,8 @@ public void testStmtSSScrollDynamicOptimisticCC() throws SQLException { } /** - * Create a statement TYPE_SS_SEVER_CURSOR_FORWARD_ONLY, CONCUR_READ_ONLY, executeQuery verify cursor by using next and verify data + * Create a statement TYPE_SS_SEVER_CURSOR_FORWARD_ONLY, CONCUR_READ_ONLY, executeQuery verify cursor by using next + * and verify data * * @throws SQLException */ @@ -277,10 +273,10 @@ public void testStmtSserverCursorForwardOnly() throws SQLException { DBResultSetTypes rsType = DBResultSetTypes.TYPE_FORWARD_ONLY_CONCUR_READ_ONLY; String query = "SELECT * FROM " + table1.getEscapedTableName(); - + try (DBConnection conn = new DBConnection(connectionString); - DBStatement stmt = conn.createStatement(rsType.resultsetCursor, rsType.resultSetConcurrency); - DBResultSet rs = stmt.executeQuery(query)) { + DBStatement stmt = conn.createStatement(rsType.resultsetCursor, rsType.resultSetConcurrency); + DBResultSet rs = stmt.executeQuery(query)) { // Verify resultset behavior rs.next(); rs.verify(table1); @@ -298,9 +294,9 @@ public void testCreatepreparedStatement() throws SQLException { String colName = table1.getColumnName(7); String value = table1.getRowData(7, 0).toString(); String query = "SELECT * from " + table1.getEscapedTableName() + " where [" + colName + "] = ? "; - + try (DBConnection conn = new DBConnection(connectionString); - DBPreparedStatement pstmt = conn.prepareStatement(query)) { + DBPreparedStatement pstmt = conn.prepareStatement(query)) { pstmt.setObject(1, new BigDecimal(value)); DBResultSet rs = pstmt.executeQuery(); @@ -318,10 +314,9 @@ public void testCreatepreparedStatement() throws SQLException { public void testResultSet() throws SQLException { String query = "SELECT * FROM " + table1.getEscapedTableName(); - - try (DBConnection conn = new DBConnection(connectionString); - DBStatement stmt = conn.createStatement(); - DBResultSet rs = stmt.executeQuery(query)) { + + try (DBConnection conn = new DBConnection(connectionString); DBStatement stmt = conn.createStatement(); + DBResultSet rs = stmt.executeQuery(query)) { // verify resultSet rs.verify(table1); } @@ -336,16 +331,14 @@ public void testResultSet() throws SQLException { public void testResultSetAndClose() throws SQLException { String query = "SELECT * FROM " + table1.getEscapedTableName(); - - try (DBConnection conn = new DBConnection(connectionString); - DBStatement stmt = conn.createStatement(); - DBResultSet rs = stmt.executeQuery(query)) { + + try (DBConnection conn = new DBConnection(connectionString); DBStatement stmt = conn.createStatement(); + DBResultSet rs = stmt.executeQuery(query)) { try { if (null != rs) rs.close(); - } - catch (SQLException e) { + } catch (SQLException e) { fail(e.toString()); } } @@ -358,17 +351,16 @@ public void testResultSetAndClose() throws SQLException { */ @Test public void testTwoResultsetsDifferentStmt() throws SQLException { - + String query = "SELECT * FROM " + table1.getEscapedTableName(); String query2 = "SELECT * FROM " + table2.getEscapedTableName(); - try (DBConnection conn = new DBConnection(connectionString); - DBStatement stmt1 = conn.createStatement(); - DBStatement stmt2 = conn.createStatement()) { + try (DBConnection conn = new DBConnection(connectionString); DBStatement stmt1 = conn.createStatement(); + DBStatement stmt2 = conn.createStatement()) { DBResultSet rs1 = stmt1.executeQuery(query); DBResultSet rs2 = stmt2.executeQuery(query2); - + // Interleave resultset calls rs1.next(); rs1.verifyCurrentRow(table1); @@ -394,25 +386,22 @@ public void testTwoResultsetsSameStmt() throws SQLException { String query = "SELECT * FROM " + table1.getEscapedTableName(); String query2 = "SELECT * FROM " + table2.getEscapedTableName(); - - try (DBConnection conn = new DBConnection(connectionString); - DBStatement stmt = conn.createStatement()) { + + try (DBConnection conn = new DBConnection(connectionString); DBStatement stmt = conn.createStatement()) { DBResultSet rs1 = stmt.executeQuery(query); DBResultSet rs2 = stmt.executeQuery(query2); // Interleave resultset calls. rs is expected to be closed try { rs1.next(); - } - catch (SQLException e) { - assertEquals(e.getMessage(), TestResource.getResource("R_resultsetClosed")); + } catch (SQLException e) { + assertEquals(e.getMessage(), TestResource.getResource("R_resultsetClosed")); } rs2.next(); rs2.verifyCurrentRow(table2); try { rs1.next(); - } - catch (SQLException e) { + } catch (SQLException e) { assertEquals(e.getMessage(), TestResource.getResource("R_resultsetClosed")); } rs1.close(); @@ -430,15 +419,13 @@ public void testTwoResultsetsSameStmt() throws SQLException { @Test public void testResultSetAndCloseStmt() throws SQLException { String query = "SELECT * FROM " + table1.getEscapedTableName(); - try (DBConnection conn = new DBConnection(connectionString); - DBStatement stmt = conn.createStatement(); - DBResultSet rs = stmt.executeQuery(query)) { + try (DBConnection conn = new DBConnection(connectionString); DBStatement stmt = conn.createStatement(); + DBResultSet rs = stmt.executeQuery(query)) { stmt.close(); // this should close the resultSet try { rs.next(); - } - catch (SQLException e) { + } catch (SQLException e) { assertEquals(e.getMessage(), TestResource.getResource("R_resultsetClosed")); } assertTrue(true, "Previous one should have thrown exception!"); @@ -455,8 +442,7 @@ public void testResultSetSelectMethod() throws SQLException { String query = "SELECT * FROM " + table1.getEscapedTableName(); try (DBConnection conn = new DBConnection(connectionString + ";selectMethod=cursor;"); - DBStatement stmt = conn.createStatement(); - DBResultSet rs = stmt.executeQuery(query)) { + DBStatement stmt = conn.createStatement(); DBResultSet rs = stmt.executeQuery(query)) { rs.verify(table1); } } @@ -469,10 +455,11 @@ public void testResultSetSelectMethod() throws SQLException { @AfterAll public static void terminate() throws SQLException { - try (DBConnection conn = new DBConnection(connectionString); - DBStatement stmt = conn.createStatement()) { - stmt.execute("if object_id('" + table1.getEscapedTableName() + "','U') is not null" + " drop table " + table1.getEscapedTableName()); - stmt.execute("if object_id('" + table2.getEscapedTableName() + "','U') is not null" + " drop table " + table2.getEscapedTableName()); + try (DBConnection conn = new DBConnection(connectionString); DBStatement stmt = conn.createStatement()) { + stmt.execute("if object_id('" + table1.getEscapedTableName() + "','U') is not null" + " drop table " + + table1.getEscapedTableName()); + stmt.execute("if object_id('" + table2.getEscapedTableName() + "','U') is not null" + " drop table " + + table2.getEscapedTableName()); } } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTestSetup.java b/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTestSetup.java index 0306d6f1d..404879fd2 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTestSetup.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/bvt/bvtTestSetup.java @@ -1,44 +1,41 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ -package com.microsoft.sqlserver.jdbc.bvt; - -import java.sql.SQLException; - -import org.junit.jupiter.api.BeforeAll; -import org.junit.platform.runner.JUnitPlatform; -import org.junit.runner.RunWith; - -import com.microsoft.sqlserver.testframework.AbstractTest; -import com.microsoft.sqlserver.testframework.DBConnection; -import com.microsoft.sqlserver.testframework.DBStatement; -import com.microsoft.sqlserver.testframework.DBTable; - -/** - * - * Setting up the test - */ -@RunWith(JUnitPlatform.class) -public class bvtTestSetup extends AbstractTest { - - static DBTable table1; - static DBTable table2; - - @BeforeAll - public static void init() throws SQLException { - try (DBConnection conn = new DBConnection(connectionString); - DBStatement stmt = conn.createStatement()) { - // create tables - table1 = new DBTable(true); - stmt.createTable(table1); - stmt.populateTable(table1); - table2 = new DBTable(true); - stmt.createTable(table2); - stmt.populateTable(table2); - } - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package com.microsoft.sqlserver.jdbc.bvt; + +import java.sql.SQLException; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.platform.runner.JUnitPlatform; +import org.junit.runner.RunWith; + +import com.microsoft.sqlserver.testframework.AbstractTest; +import com.microsoft.sqlserver.testframework.DBConnection; +import com.microsoft.sqlserver.testframework.DBStatement; +import com.microsoft.sqlserver.testframework.DBTable; + + +/** + * + * Setting up the test + */ +@RunWith(JUnitPlatform.class) +public class bvtTestSetup extends AbstractTest { + + static DBTable table1; + static DBTable table2; + + @BeforeAll + public static void init() throws SQLException { + try (DBConnection conn = new DBConnection(connectionString); DBStatement stmt = conn.createStatement()) { + // create tables + table1 = new DBTable(true); + stmt.createTable(table1); + stmt.populateTable(table1); + table2 = new DBTable(true); + stmt.createTable(table2); + stmt.populateTable(table2); + } + } +} diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/callablestatement/CallableStatementTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/callablestatement/CallableStatementTest.java index cbf4a0066..ad7c9ae19 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/callablestatement/CallableStatementTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/callablestatement/CallableStatementTest.java @@ -10,8 +10,8 @@ import java.sql.SQLException; import java.sql.Statement; import java.sql.Types; -import java.util.UUID; import java.text.MessageFormat; +import java.util.UUID; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; @@ -25,6 +25,7 @@ import com.microsoft.sqlserver.testframework.AbstractTest; import com.microsoft.sqlserver.testframework.Utils; + /** * Test CallableStatement */ @@ -68,7 +69,7 @@ public static void setupTest() throws SQLException { public void getStringGUIDTest() throws SQLException { String sql = "{call " + outputProcedureNameGUID + "(?)}"; - + try (SQLServerCallableStatement callableStatement = (SQLServerCallableStatement) connection.prepareCall(sql)) { UUID originalValue = UUID.randomUUID(); @@ -98,8 +99,8 @@ public void getSetNullWithTypeVarchar() throws SQLException { ds.setSendStringParametersAsUnicode(true); String sql = "{? = call " + setNullProcedureName + " (?,?)}"; try (Connection connection = ds.getConnection(); - SQLServerCallableStatement cs = (SQLServerCallableStatement) connection.prepareCall(sql); - SQLServerCallableStatement cs2 = (SQLServerCallableStatement) connection.prepareCall(sql)){ + SQLServerCallableStatement cs = (SQLServerCallableStatement) connection.prepareCall(sql); + SQLServerCallableStatement cs2 = (SQLServerCallableStatement) connection.prepareCall(sql)) { cs.registerOutParameter(1, Types.INTEGER); cs.setString(2, polishchar); @@ -116,12 +117,11 @@ public void getSetNullWithTypeVarchar() throws SQLException { cs2.execute(); String actual = cs2.getString(3); - + assertEquals(expected, actual); } } - /** * recognize parameter names with and without leading '@' * @@ -131,7 +131,7 @@ public void getSetNullWithTypeVarchar() throws SQLException { public void inputParamsTest() throws SQLException { String call = "{CALL " + inputParamsProcedureName + " (?,?)}"; ResultSet rs = null; - + // the historical way: no leading '@', parameter names respected (not positional) CallableStatement cs1 = connection.prepareCall(call); cs1.setString("p2", "world"); @@ -139,7 +139,7 @@ public void inputParamsTest() throws SQLException { rs = cs1.executeQuery(); rs.next(); assertEquals("helloworld", rs.getString(1)); - + // the "new" way: leading '@', parameter names still respected (not positional) CallableStatement cs2 = connection.prepareCall(call); cs2.setString("@p2", "world!"); @@ -147,7 +147,7 @@ public void inputParamsTest() throws SQLException { rs = cs2.executeQuery(); rs.next(); assertEquals("Hello world!", rs.getString(1)); - + // sanity check: unrecognized parameter name CallableStatement cs3 = connection.prepareCall(call); try { @@ -164,7 +164,7 @@ public void inputParamsTest() throws SQLException { } } - + /** * Cleanup after test * @@ -186,7 +186,8 @@ public static void cleanup() throws SQLException { } private static void createGUIDStoredProcedure(Statement stmt) throws SQLException { - String sql = "CREATE PROCEDURE " + outputProcedureNameGUID + "(@p1 uniqueidentifier OUTPUT) AS SELECT @p1 = c1 FROM " + tableNameGUID + ";"; + String sql = "CREATE PROCEDURE " + outputProcedureNameGUID + + "(@p1 uniqueidentifier OUTPUT) AS SELECT @p1 = c1 FROM " + tableNameGUID + ";"; stmt.execute(sql); } @@ -196,19 +197,14 @@ private static void createGUIDTable(Statement stmt) throws SQLException { } private static void createSetNullPreocedure(Statement stmt) throws SQLException { - stmt.execute("create procedure " + setNullProcedureName + " (@p1 nvarchar(255), @p2 nvarchar(255) output) as select @p2=@p1 return 0"); + stmt.execute("create procedure " + setNullProcedureName + + " (@p1 nvarchar(255), @p2 nvarchar(255) output) as select @p2=@p1 return 0"); } private static void createInputParamsProcedure(Statement stmt) throws SQLException { - String sql = - "CREATE PROCEDURE [dbo].[CallableStatementTest_inputParams_SP] " + - " @p1 nvarchar(max) = N'parameter1', " + - " @p2 nvarchar(max) = N'parameter2' " + - "AS " + - "BEGIN " + - " SET NOCOUNT ON; " + - " SELECT @p1 + @p2 AS result; " + - "END "; + String sql = "CREATE PROCEDURE [dbo].[CallableStatementTest_inputParams_SP] " + + " @p1 nvarchar(max) = N'parameter1', " + " @p2 nvarchar(max) = N'parameter2' " + "AS " + + "BEGIN " + " SET NOCOUNT ON; " + " SELECT @p1 + @p2 AS result; " + "END "; stmt.execute(sql); } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/connection/ConnectionDriverTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/connection/ConnectionDriverTest.java index 393ca2436..20e50feb6 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/connection/ConnectionDriverTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/connection/ConnectionDriverTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.connection; @@ -18,6 +15,7 @@ import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.sql.Statement; +import java.text.MessageFormat; import java.util.Properties; import java.util.UUID; import java.util.concurrent.Executor; @@ -25,7 +23,6 @@ import java.util.concurrent.Executors; import java.util.concurrent.Future; import java.util.logging.Logger; -import java.text.MessageFormat; import javax.sql.ConnectionEvent; import javax.sql.PooledConnection; @@ -46,6 +43,7 @@ import com.microsoft.sqlserver.testframework.DBTable; import com.microsoft.sqlserver.testframework.util.RandomUtil; + @RunWith(JUnitPlatform.class) public class ConnectionDriverTest extends AbstractTest { // If no retry is done, the function should atleast exit in 5 seconds @@ -124,29 +122,30 @@ public void testEncryptedConnection() throws SQLException { ds.setEncrypt(true); ds.setTrustServerCertificate(true); ds.setPacketSize(8192); - try(Connection con = ds.getConnection()) {} + try (Connection con = ds.getConnection()) {} } @Test public void testJdbcDriverMethod() throws SQLFeatureNotSupportedException { SQLServerDriver serverDriver = new SQLServerDriver(); Logger logger = serverDriver.getParentLogger(); - assertEquals(logger.getName(), "com.microsoft.sqlserver.jdbc", TestResource.getResource("R_parrentLoggerNameWrong")); + assertEquals(logger.getName(), "com.microsoft.sqlserver.jdbc", + TestResource.getResource("R_parrentLoggerNameWrong")); } @Test public void testJdbcDataSourceMethod() throws SQLFeatureNotSupportedException { SQLServerDataSource fxds = new SQLServerDataSource(); Logger logger = fxds.getParentLogger(); - assertEquals(logger.getName(), "com.microsoft.sqlserver.jdbc", TestResource.getResource("R_parrentLoggerNameWrong")); + assertEquals(logger.getName(), "com.microsoft.sqlserver.jdbc", + TestResource.getResource("R_parrentLoggerNameWrong")); } class MyEventListener implements javax.sql.ConnectionEventListener { boolean connClosed = false; boolean errorOccurred = false; - public MyEventListener() { - } + public MyEventListener() {} public void connectionClosed(ConnectionEvent event) { connClosed = true; @@ -158,13 +157,15 @@ public void connectionErrorOccurred(ConnectionEvent event) { } /** - * Attach the Event listener and listen for connection events, fatal errors should not close the pooled connection objects + * Attach the Event listener and listen for connection events, fatal errors should not close the pooled connection + * objects * * @throws SQLException */ @Test public void testConnectionEvents() throws SQLException { - assumeTrue(!DBConnection.isSqlAzure(DriverManager.getConnection(connectionString)), TestResource.getResource("R_skipAzure")); + assumeTrue(!DBConnection.isSqlAzure(DriverManager.getConnection(connectionString)), + TestResource.getResource("R_skipAzure")); SQLServerConnectionPoolDataSource mds = new SQLServerConnectionPoolDataSource(); mds.setURL(connectionString); @@ -172,31 +173,31 @@ public void testConnectionEvents() throws SQLException { // Attach the Event listener and listen for connection events. MyEventListener myE = new MyEventListener(); - pooledConnection.addConnectionEventListener(myE); // ConnectionListener implements ConnectionEventListener - - try(Connection con = pooledConnection.getConnection(); - Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE)) { - - boolean exceptionThrown = false; - try { - // raise a severe exception and make sure that the connection is not - // closed. - stmt.executeUpdate("RAISERROR ('foo', 20,1) WITH LOG"); - } - catch (Exception e) { - exceptionThrown = true; - } - assertTrue(exceptionThrown, TestResource.getResource("R_expectedExceptionNotThrown")); - - // Check to see if error occurred. - assertTrue(myE.errorOccurred, TestResource.getResource("R_errorNotCalled")); + pooledConnection.addConnectionEventListener(myE); // ConnectionListener implements ConnectionEventListener + + try (Connection con = pooledConnection.getConnection(); + Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE)) { + + boolean exceptionThrown = false; + try { + // raise a severe exception and make sure that the connection is not + // closed. + stmt.executeUpdate("RAISERROR ('foo', 20,1) WITH LOG"); + } catch (Exception e) { + exceptionThrown = true; + } + assertTrue(exceptionThrown, TestResource.getResource("R_expectedExceptionNotThrown")); + + // Check to see if error occurred. + assertTrue(myE.errorOccurred, TestResource.getResource("R_errorNotCalled")); } // make sure that connection is closed. } @Test public void testConnectionPoolGetTwice() throws SQLException { - assumeTrue(!DBConnection.isSqlAzure(DriverManager.getConnection(connectionString)), TestResource.getResource("R_skipAzure")); + assumeTrue(!DBConnection.isSqlAzure(DriverManager.getConnection(connectionString)), + TestResource.getResource("R_skipAzure")); SQLServerConnectionPoolDataSource mds = new SQLServerConnectionPoolDataSource(); mds.setURL(connectionString); @@ -204,25 +205,26 @@ public void testConnectionPoolGetTwice() throws SQLException { // Attach the Event listener and listen for connection events. MyEventListener myE = new MyEventListener(); - pooledConnection.addConnectionEventListener(myE); // ConnectionListener implements ConnectionEventListener + pooledConnection.addConnectionEventListener(myE); // ConnectionListener implements ConnectionEventListener - Connection con = pooledConnection.getConnection(); - Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); + Connection con = pooledConnection.getConnection(); + Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); // raise a non severe exception and make sure that the connection is not closed. stmt.executeUpdate("RAISERROR ('foo', 3,1) WITH LOG"); // not a serious error there should not be any errors. assertTrue(!myE.errorOccurred, TestResource.getResource("R_errorCalled")); // check to make sure that connection is not closed. - assertTrue(!con.isClosed(), TestResource.getResource("R_connectionIsClosed")); - stmt.close(); - con.close(); + assertTrue(!con.isClosed(), TestResource.getResource("R_connectionIsClosed")); + stmt.close(); + con.close(); // check to make sure that connection is closed. assertTrue(con.isClosed(), TestResource.getResource("R_connectionIsNotClosed")); } @Test public void testConnectionClosed() throws SQLException { - assumeTrue(!DBConnection.isSqlAzure(DriverManager.getConnection(connectionString)), TestResource.getResource("R_skipAzure")); + assumeTrue(!DBConnection.isSqlAzure(DriverManager.getConnection(connectionString)), + TestResource.getResource("R_skipAzure")); SQLServerDataSource mds = new SQLServerDataSource(); mds.setURL(connectionString); @@ -232,42 +234,44 @@ public void testConnectionClosed() throws SQLException { boolean exceptionThrown = false; try { stmt.executeUpdate("RAISERROR ('foo', 20,1) WITH LOG"); - } - catch (Exception e) { + } catch (Exception e) { exceptionThrown = true; } assertTrue(exceptionThrown, TestResource.getResource("R_expectedExceptionNotThrown")); - + // check to make sure that connection is closed. assertTrue(con.isClosed(), TestResource.getResource("R_connectionIsNotClosed")); } @Test public void testIsWrapperFor() throws SQLException, ClassNotFoundException { - try(Connection conn = DriverManager.getConnection(connectionString); - SQLServerConnection ssconn = (SQLServerConnection) conn) { - boolean isWrapper; - isWrapper = ssconn.isWrapperFor(ssconn.getClass()); - MessageFormat form = new MessageFormat(TestResource.getResource("R_supportUnwrapping")); - Object[] msgArgs1 = {"SQLServerConnection"}; - - assertTrue(isWrapper, form.format(msgArgs1)); - assertEquals(ssconn.TRANSACTION_SNAPSHOT, ssconn.TRANSACTION_SNAPSHOT, TestResource.getResource("R_cantAccessSnapshot")); - - isWrapper = ssconn.isWrapperFor(Class.forName("com.microsoft.sqlserver.jdbc.ISQLServerConnection")); - Object[] msgArgs2 = {"ISQLServerConnection"}; - assertTrue(isWrapper, form.format(msgArgs2)); - ISQLServerConnection iSql = (ISQLServerConnection) ssconn.unwrap(Class.forName("com.microsoft.sqlserver.jdbc.ISQLServerConnection")); - assertEquals(iSql.TRANSACTION_SNAPSHOT, iSql.TRANSACTION_SNAPSHOT, TestResource.getResource("R_cantAccessSnapshot")); - - ssconn.unwrap(Class.forName("java.sql.Connection")); + try (Connection conn = DriverManager.getConnection(connectionString); + SQLServerConnection ssconn = (SQLServerConnection) conn) { + boolean isWrapper; + isWrapper = ssconn.isWrapperFor(ssconn.getClass()); + MessageFormat form = new MessageFormat(TestResource.getResource("R_supportUnwrapping")); + Object[] msgArgs1 = {"SQLServerConnection"}; + + assertTrue(isWrapper, form.format(msgArgs1)); + assertEquals(ssconn.TRANSACTION_SNAPSHOT, ssconn.TRANSACTION_SNAPSHOT, + TestResource.getResource("R_cantAccessSnapshot")); + + isWrapper = ssconn.isWrapperFor(Class.forName("com.microsoft.sqlserver.jdbc.ISQLServerConnection")); + Object[] msgArgs2 = {"ISQLServerConnection"}; + assertTrue(isWrapper, form.format(msgArgs2)); + ISQLServerConnection iSql = (ISQLServerConnection) ssconn + .unwrap(Class.forName("com.microsoft.sqlserver.jdbc.ISQLServerConnection")); + assertEquals(iSql.TRANSACTION_SNAPSHOT, iSql.TRANSACTION_SNAPSHOT, + TestResource.getResource("R_cantAccessSnapshot")); + + ssconn.unwrap(Class.forName("java.sql.Connection")); } } @Test public void testNewConnection() throws SQLException { - try(SQLServerConnection conn = (SQLServerConnection) DriverManager.getConnection(connectionString)) { - assertTrue(conn.isValid(0), TestResource.getResource("R_newConnectionShouldBeValid")); + try (SQLServerConnection conn = (SQLServerConnection) DriverManager.getConnection(connectionString)) { + assertTrue(conn.isValid(0), TestResource.getResource("R_newConnectionShouldBeValid")); } } @@ -281,47 +285,47 @@ public void testClosedConnection() throws SQLException { @Test public void testNegativeTimeout() throws Exception { try (SQLServerConnection conn = (SQLServerConnection) DriverManager.getConnection(connectionString)) { - try { - conn.isValid(-42); - throw new Exception(TestResource.getResource("R_noExceptionNegativeTimeout")); - } - catch (SQLException e) { - MessageFormat form = new MessageFormat(TestResource.getResource("R_invalidQueryTimeout")); - Object[] msgArgs = {"-42"}; - - assertEquals(e.getMessage(), form.format(msgArgs), TestResource.getResource("R_wrongExceptionMessage")); - } + try { + conn.isValid(-42); + throw new Exception(TestResource.getResource("R_noExceptionNegativeTimeout")); + } catch (SQLException e) { + MessageFormat form = new MessageFormat(TestResource.getResource("R_invalidQueryTimeout")); + Object[] msgArgs = {"-42"}; + + assertEquals(e.getMessage(), form.format(msgArgs), TestResource.getResource("R_wrongExceptionMessage")); + } } } @Test public void testDeadConnection() throws SQLException { - assumeTrue(!DBConnection.isSqlAzure(DriverManager.getConnection(connectionString)), TestResource.getResource("R_skipAzure")); - - try (SQLServerConnection conn = (SQLServerConnection) DriverManager.getConnection(connectionString + ";responseBuffering=adaptive")) { - - Statement stmt = null; - String tableName = RandomUtil.getIdentifier("Table"); - tableName = DBTable.escapeIdentifier(tableName); - - conn.setAutoCommit(false); - stmt = conn.createStatement(); - stmt.executeUpdate("CREATE TABLE " + tableName + " (col1 int primary key)"); - for (int i = 0; i < 80; i++) { - stmt.executeUpdate("INSERT INTO " + tableName + "(col1) values (" + i + ")"); - } - conn.commit(); - try { - stmt.execute("SELECT x1.col1 as foo, x2.col1 as bar, x1.col1 as eeep FROM " + tableName + " as x1, " + tableName - + " as x2; RAISERROR ('Oops', 21, 42) WITH LOG"); - } - catch (SQLException e) { - assertEquals(e.getMessage(), TestResource.getResource("R_connectionReset"), TestResource.getResource("R_unknownException")); - } - finally { - DriverManager.getConnection(connectionString).createStatement().execute("drop table " + tableName); - } - assertEquals(conn.isValid(5), false, TestResource.getResource("R_deadConnection")); + assumeTrue(!DBConnection.isSqlAzure(DriverManager.getConnection(connectionString)), + TestResource.getResource("R_skipAzure")); + + try (SQLServerConnection conn = (SQLServerConnection) DriverManager + .getConnection(connectionString + ";responseBuffering=adaptive")) { + + Statement stmt = null; + String tableName = RandomUtil.getIdentifier("Table"); + tableName = DBTable.escapeIdentifier(tableName); + + conn.setAutoCommit(false); + stmt = conn.createStatement(); + stmt.executeUpdate("CREATE TABLE " + tableName + " (col1 int primary key)"); + for (int i = 0; i < 80; i++) { + stmt.executeUpdate("INSERT INTO " + tableName + "(col1) values (" + i + ")"); + } + conn.commit(); + try { + stmt.execute("SELECT x1.col1 as foo, x2.col1 as bar, x1.col1 as eeep FROM " + tableName + " as x1, " + + tableName + " as x2; RAISERROR ('Oops', 21, 42) WITH LOG"); + } catch (SQLException e) { + assertEquals(e.getMessage(), TestResource.getResource("R_connectionReset"), + TestResource.getResource("R_unknownException")); + } finally { + DriverManager.getConnection(connectionString).createStatement().execute("drop table " + tableName); + } + assertEquals(conn.isValid(5), false, TestResource.getResource("R_deadConnection")); } } @@ -334,32 +338,30 @@ public void testClientConnectionId() throws Exception { // Call getClientConnectionId on a closed connection, should raise exception conn.getClientConnectionId(); throw new Exception(TestResource.getResource("R_noExceptionClosedConnection")); - } - catch (SQLException e) { - assertEquals(e.getMessage(), TestResource.getResource("R_connectionIsClosed"), TestResource.getResource("R_wrongExceptionMessage")); + } catch (SQLException e) { + assertEquals(e.getMessage(), TestResource.getResource("R_connectionIsClosed"), + TestResource.getResource("R_wrongExceptionMessage")); } conn = null; try { // Wrong database, ClientConnectionId should be available in error message - conn = (SQLServerConnection) DriverManager - .getConnection(connectionString + ";databaseName=" + RandomUtil.getIdentifierForDB("DataBase") + ";"); + conn = (SQLServerConnection) DriverManager.getConnection( + connectionString + ";databaseName=" + RandomUtil.getIdentifierForDB("DataBase") + ";"); conn.close(); - } - catch (SQLException e) { + } catch (SQLException e) { assertTrue(e.getMessage().indexOf("ClientConnectionId") != -1, TestResource.getResource("R_unexpectedWrongDB")); } try { // Nonexist host, ClientConnectionId should not be available in error message - conn = (SQLServerConnection) DriverManager - .getConnection(connectionString + ";instanceName=" + RandomUtil.getIdentifier("Instance") + ";logintimeout=5;"); + conn = (SQLServerConnection) DriverManager.getConnection( + connectionString + ";instanceName=" + RandomUtil.getIdentifier("Instance") + ";logintimeout=5;"); conn.close(); - } - catch (SQLException e) { + } catch (SQLException e) { assertEquals(false, e.getMessage().indexOf("ClientConnectionId") != -1, TestResource.getResource("R_unexpectedWrongHost")); } @@ -378,8 +380,7 @@ public void testIncorrectDatabase() throws SQLException { ds.setDatabaseName(RandomUtil.getIdentifier("DataBase")); timerStart = System.currentTimeMillis(); con = ds.getConnection(); - } - catch (Exception e) { + } catch (Exception e) { assertTrue(e.getMessage().contains(TestResource.getResource("R_cannotOpenDatabase"))); timerEnd = System.currentTimeMillis(); } @@ -405,8 +406,7 @@ public void testIncorrectUserName() throws SQLException { ds.setUser(RandomUtil.getIdentifier("User")); timerStart = System.currentTimeMillis(); con = ds.getConnection(); - } - catch (Exception e) { + } catch (Exception e) { assertTrue(e.getMessage().contains(TestResource.getResource("R_loginFailed"))); timerEnd = System.currentTimeMillis(); } @@ -431,8 +431,7 @@ public void testIncorrectPassword() throws SQLException { ds.setPassword(RandomUtil.getIdentifier("Password")); timerStart = System.currentTimeMillis(); con = ds.getConnection(); - } - catch (Exception e) { + } catch (Exception e) { assertTrue(e.getMessage().contains(TestResource.getResource("R_loginFailed"))); timerEnd = System.currentTimeMillis(); } @@ -458,8 +457,7 @@ public void testInvalidCombination() throws SQLException { ds.setFailoverPartner(RandomUtil.getIdentifier("FailoverPartner")); timerStart = System.currentTimeMillis(); con = ds.getConnection(); - } - catch (Exception e) { + } catch (Exception e) { assertTrue(e.getMessage().contains(TestResource.getResource("R_connectMirrored"))); timerEnd = System.currentTimeMillis(); } @@ -485,8 +483,7 @@ public void testIncorrectDatabaseWithFailoverPartner() throws SQLException { ds.setFailoverPartner(RandomUtil.getIdentifier("FailoverPartner")); timerStart = System.currentTimeMillis(); con = ds.getConnection(); - } - catch (Exception e) { + } catch (Exception e) { timerEnd = System.currentTimeMillis(); } @@ -502,8 +499,7 @@ public void testAbortBadParam() throws SQLException { SQLServerConnection conn = (SQLServerConnection) DriverManager.getConnection(connectionString); try { conn.abort(null); - } - catch (SQLException e) { + } catch (SQLException e) { assertTrue(e.getMessage().contains(TestResource.getResource("R_invalidArgumentExecutor"))); } } @@ -526,7 +522,7 @@ public void testGetSchema() throws SQLException { SQLServerConnection conn = (SQLServerConnection) DriverManager.getConnection(connectionString); conn.getSchema(); } - + static Boolean isInterrupted = false; /** @@ -547,8 +543,7 @@ public void run() { try { ds.getConnection(); - } - catch (SQLException e) { + } catch (SQLException e) { isInterrupted = Thread.currentThread().isInterrupted(); } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/connection/ConnectionWrapper43Test.java b/src/test/java/com/microsoft/sqlserver/jdbc/connection/ConnectionWrapper43Test.java index 204673991..6329f7e02 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/connection/ConnectionWrapper43Test.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/connection/ConnectionWrapper43Test.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.connection; @@ -24,6 +21,7 @@ import com.microsoft.sqlserver.jdbc.SQLServerConnection43; import com.microsoft.sqlserver.testframework.AbstractTest; + /** * Test ConnectionWrapper43Test class * @@ -45,12 +43,10 @@ public void SQLServerConnection43Test() throws SQLException { try { if (1.8d <= javaVersion && 4 == major && 2 == minor) { assertTrue(connection instanceof SQLServerConnection); - } - else { + } else { assertTrue(connection instanceof SQLServerConnection43); } - } - finally { + } finally { if (null != connection) { connection.close(); } @@ -58,7 +54,7 @@ public void SQLServerConnection43Test() throws SQLException { } @BeforeAll - private static void setupConnection() throws SQLException { + public static void setupConnection() throws SQLException { connection = DriverManager.getConnection(connectionString); DatabaseMetaData metadata = connection.getMetaData(); @@ -67,7 +63,7 @@ private static void setupConnection() throws SQLException { } @AfterAll - private static void terminateVariation() throws SQLException { + public static void terminateVariation() throws SQLException { if (null != connection) { connection.close(); } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/connection/DBMetadataTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/connection/DBMetadataTest.java index f71da3f7f..54dba8705 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/connection/DBMetadataTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/connection/DBMetadataTest.java @@ -1,58 +1,56 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ -package com.microsoft.sqlserver.jdbc.connection; - -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -import org.junit.jupiter.api.Test; -import org.junit.platform.runner.JUnitPlatform; -import org.junit.runner.RunWith; - -import com.microsoft.sqlserver.jdbc.SQLServerDataSource; -import com.microsoft.sqlserver.testframework.AbstractTest; -import com.microsoft.sqlserver.testframework.DBTable; -import com.microsoft.sqlserver.testframework.util.RandomUtil; - -@RunWith(JUnitPlatform.class) -public class DBMetadataTest extends AbstractTest { - @Test - public void testDatabaseMetaData() throws SQLException { - String functionName = RandomUtil.getIdentifier("proc"); - functionName = DBTable.escapeIdentifier(functionName); - - SQLServerDataSource ds = new SQLServerDataSource(); - ds.setURL(connectionString); - - String sqlDropFunction = "if exists (select * from dbo.sysobjects where id = object_id(N'[dbo]." + functionName + "')" - + "and xtype in (N'FN', N'IF', N'TF'))" + "drop function " + functionName; - String sqlCreateFunction = "CREATE FUNCTION " + functionName + " (@text varchar(8000), @delimiter varchar(20) = ' ') RETURNS @Strings TABLE " - + "(position int IDENTITY PRIMARY KEY, value varchar(8000)) AS BEGIN INSERT INTO @Strings VALUES ('DDD') RETURN END "; - - try (Connection con = ds.getConnection(); - Statement stmt = con.createStatement()) { - // drop function - stmt.execute(sqlDropFunction); - // create function - stmt.execute(sqlCreateFunction); - - DatabaseMetaData md = con.getMetaData(); - try (ResultSet arguments = md.getProcedureColumns(null, null, null, "@TABLE_RETURN_VALUE")) { - - if (arguments.next()) { - arguments.getString("COLUMN_NAME"); - arguments.getString("DATA_TYPE"); // call this function to make sure it does not crash - } - } - stmt.execute(sqlDropFunction); - } - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package com.microsoft.sqlserver.jdbc.connection; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import org.junit.jupiter.api.Test; +import org.junit.platform.runner.JUnitPlatform; +import org.junit.runner.RunWith; + +import com.microsoft.sqlserver.jdbc.SQLServerDataSource; +import com.microsoft.sqlserver.testframework.AbstractTest; +import com.microsoft.sqlserver.testframework.DBTable; +import com.microsoft.sqlserver.testframework.util.RandomUtil; + + +@RunWith(JUnitPlatform.class) +public class DBMetadataTest extends AbstractTest { + @Test + public void testDatabaseMetaData() throws SQLException { + String functionName = RandomUtil.getIdentifier("proc"); + functionName = DBTable.escapeIdentifier(functionName); + + SQLServerDataSource ds = new SQLServerDataSource(); + ds.setURL(connectionString); + + String sqlDropFunction = "if exists (select * from dbo.sysobjects where id = object_id(N'[dbo]." + functionName + + "')" + "and xtype in (N'FN', N'IF', N'TF'))" + "drop function " + functionName; + String sqlCreateFunction = "CREATE FUNCTION " + functionName + + " (@text varchar(8000), @delimiter varchar(20) = ' ') RETURNS @Strings TABLE " + + "(position int IDENTITY PRIMARY KEY, value varchar(8000)) AS BEGIN INSERT INTO @Strings VALUES ('DDD') RETURN END "; + + try (Connection con = ds.getConnection(); Statement stmt = con.createStatement()) { + // drop function + stmt.execute(sqlDropFunction); + // create function + stmt.execute(sqlCreateFunction); + + DatabaseMetaData md = con.getMetaData(); + try (ResultSet arguments = md.getProcedureColumns(null, null, null, "@TABLE_RETURN_VALUE")) { + + if (arguments.next()) { + arguments.getString("COLUMN_NAME"); + arguments.getString("DATA_TYPE"); // call this function to make sure it does not crash + } + } + stmt.execute(sqlDropFunction); + } + } +} diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/connection/DriverVersionTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/connection/DriverVersionTest.java index bb4176d1d..bf622a26b 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/connection/DriverVersionTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/connection/DriverVersionTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.connection; @@ -13,7 +10,6 @@ import java.util.Arrays; import java.util.Random; - import org.junit.jupiter.api.Test; import org.junit.platform.runner.JUnitPlatform; import org.junit.runner.RunWith; @@ -21,12 +17,13 @@ import com.microsoft.sqlserver.testframework.AbstractTest; import com.microsoft.sqlserver.testframework.util.Util; + /** - * This test validates PR #342. In this PR, DatatypeConverter#parseHexBinary is replaced with type casting. This tests validates if the behavior - * reminds the same. + * This test validates PR #342. In this PR, DatatypeConverter#parseHexBinary is replaced with type casting. This tests + * validates if the behavior reminds the same. * - * The valid length of driver version byte array has to be 4. Otherwise, connection won't be established. Therefore, the valid value for the original - * method is between 0 and 255 (inclusive). + * The valid length of driver version byte array has to be 4. Otherwise, connection won't be established. Therefore, the + * valid value for the original method is between 0 and 255 (inclusive). * */ @RunWith(JUnitPlatform.class) @@ -39,7 +36,8 @@ public class DriverVersionTest extends AbstractTest { /** * validates version byte array generated by the original method and type casting reminds the same. - * @throws SQLException + * + * @throws SQLException */ @Test public void testConnectionDriver() throws SQLException { @@ -77,29 +75,25 @@ private String generateInterfaceLibVersion() { // 2 characters reserved for major if (2 == interfaceLibBuild.length()) { outputInterfaceLibVersion.append(interfaceLibBuild); - } - else { + } else { outputInterfaceLibVersion.append("0"); outputInterfaceLibVersion.append(interfaceLibBuild); } if (2 == interfaceLibPatch.length()) { outputInterfaceLibVersion.append(interfaceLibPatch); - } - else { + } else { outputInterfaceLibVersion.append("0"); outputInterfaceLibVersion.append(interfaceLibPatch); } if (2 == interfaceLibMinor.length()) { outputInterfaceLibVersion.append(interfaceLibMinor); - } - else { + } else { outputInterfaceLibVersion.append("0"); outputInterfaceLibVersion.append(interfaceLibMinor); } if (2 == interfaceLibMajor.length()) { outputInterfaceLibVersion.append(interfaceLibMajor); - } - else { + } else { outputInterfaceLibVersion.append("0"); outputInterfaceLibVersion.append(interfaceLibMajor); } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/connection/NativeMSSQLDataSourceTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/connection/NativeMSSQLDataSourceTest.java index e8ac9164b..edfc6e3a7 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/connection/NativeMSSQLDataSourceTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/connection/NativeMSSQLDataSourceTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.connection; @@ -31,6 +28,7 @@ import com.microsoft.sqlserver.jdbc.TestResource; import com.microsoft.sqlserver.testframework.AbstractTest; + @RunWith(JUnitPlatform.class) public class NativeMSSQLDataSourceTest extends AbstractTest { @@ -44,12 +42,12 @@ public void testNativeMSSQLDataSource() throws SQLException { @Test public void testSerialization() throws IOException { try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); - ObjectOutput objectOutput = new ObjectOutputStream(outputStream)) { - SQLServerDataSource ds = new SQLServerDataSource(); - ds.setLogWriter(new PrintWriter(new ByteArrayOutputStream())); - - objectOutput.writeObject(ds); - objectOutput.flush(); + ObjectOutput objectOutput = new ObjectOutputStream(outputStream)) { + SQLServerDataSource ds = new SQLServerDataSource(); + ds.setLogWriter(new PrintWriter(new ByteArrayOutputStream())); + + objectOutput.writeObject(ds); + objectOutput.flush(); } } @@ -70,8 +68,7 @@ public void testDSTSPassword() throws ClassNotFoundException, IOException, SQLEx ds.setTrustStorePassword("wrong_password"); try (Connection conn = ds.getConnection()) {} ds = testSerial(ds); - try (Connection conn = ds.getConnection()) {} - catch (SQLException e) { + try (Connection conn = ds.getConnection()) {} catch (SQLException e) { assertEquals(TestResource.getResource("R_trustStorePasswordNotSet"), e.getMessage()); } } @@ -82,38 +79,43 @@ public void testInterfaceWrapping() throws ClassNotFoundException, SQLException assertEquals(true, ds.isWrapperFor(Class.forName("com.microsoft.sqlserver.jdbc.ISQLServerDataSource"))); assertEquals(true, ds.isWrapperFor(Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDataSource"))); assertEquals(true, ds.isWrapperFor(Class.forName("javax.sql.CommonDataSource"))); - ISQLServerDataSource ids = (ISQLServerDataSource) (ds.unwrap(Class.forName("com.microsoft.sqlserver.jdbc.ISQLServerDataSource"))); + ISQLServerDataSource ids = (ISQLServerDataSource) (ds + .unwrap(Class.forName("com.microsoft.sqlserver.jdbc.ISQLServerDataSource"))); ids.setApplicationName("AppName"); SQLServerConnectionPoolDataSource poolDS = new SQLServerConnectionPoolDataSource(); assertEquals(true, poolDS.isWrapperFor(Class.forName("com.microsoft.sqlserver.jdbc.ISQLServerDataSource"))); assertEquals(true, poolDS.isWrapperFor(Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDataSource"))); - assertEquals(true, poolDS.isWrapperFor(Class.forName("com.microsoft.sqlserver.jdbc.SQLServerConnectionPoolDataSource"))); + assertEquals(true, + poolDS.isWrapperFor(Class.forName("com.microsoft.sqlserver.jdbc.SQLServerConnectionPoolDataSource"))); assertEquals(true, poolDS.isWrapperFor(Class.forName("javax.sql.CommonDataSource"))); - ISQLServerDataSource ids2 = (ISQLServerDataSource) (poolDS.unwrap(Class.forName("com.microsoft.sqlserver.jdbc.ISQLServerDataSource"))); + ISQLServerDataSource ids2 = (ISQLServerDataSource) (poolDS + .unwrap(Class.forName("com.microsoft.sqlserver.jdbc.ISQLServerDataSource"))); ids2.setApplicationName("AppName"); SQLServerXADataSource xaDS = new SQLServerXADataSource(); assertEquals(true, xaDS.isWrapperFor(Class.forName("com.microsoft.sqlserver.jdbc.ISQLServerDataSource"))); assertEquals(true, xaDS.isWrapperFor(Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDataSource"))); - assertEquals(true, xaDS.isWrapperFor(Class.forName("com.microsoft.sqlserver.jdbc.SQLServerConnectionPoolDataSource"))); + assertEquals(true, + xaDS.isWrapperFor(Class.forName("com.microsoft.sqlserver.jdbc.SQLServerConnectionPoolDataSource"))); assertEquals(true, xaDS.isWrapperFor(Class.forName("com.microsoft.sqlserver.jdbc.SQLServerXADataSource"))); assertEquals(true, xaDS.isWrapperFor(Class.forName("javax.sql.CommonDataSource"))); - ISQLServerDataSource ids3 = (ISQLServerDataSource) (xaDS.unwrap(Class.forName("com.microsoft.sqlserver.jdbc.ISQLServerDataSource"))); + ISQLServerDataSource ids3 = (ISQLServerDataSource) (xaDS + .unwrap(Class.forName("com.microsoft.sqlserver.jdbc.ISQLServerDataSource"))); ids3.setApplicationName("AppName"); } private SQLServerDataSource testSerial(SQLServerDataSource ds) throws IOException, ClassNotFoundException { try (java.io.ByteArrayOutputStream outputStream = new java.io.ByteArrayOutputStream(); - java.io.ObjectOutput objectOutput = new java.io.ObjectOutputStream(outputStream)) { - objectOutput.writeObject(ds); - objectOutput.flush(); - - try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(outputStream.toByteArray()))) { - SQLServerDataSource dtn; - dtn = (SQLServerDataSource) in.readObject(); - return dtn; - } + java.io.ObjectOutput objectOutput = new java.io.ObjectOutputStream(outputStream)) { + objectOutput.writeObject(ds); + objectOutput.flush(); + + try (ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(outputStream.toByteArray()))) { + SQLServerDataSource dtn; + dtn = (SQLServerDataSource) in.readObject(); + return dtn; + } } } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/connection/PoolingTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/connection/PoolingTest.java index cd58cac86..ef89129f9 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/connection/PoolingTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/connection/PoolingTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.connection; @@ -39,6 +36,7 @@ import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; + /** * Tests pooled connection * @@ -47,7 +45,8 @@ public class PoolingTest extends AbstractTest { @Test public void testPooling() throws SQLException { - assumeTrue(!DBConnection.isSqlAzure(DriverManager.getConnection(connectionString)), "Skipping test case on Azure SQL."); + assumeTrue(!DBConnection.isSqlAzure(DriverManager.getConnection(connectionString)), + "Skipping test case on Azure SQL."); String randomTableName = RandomUtil.getIdentifier("table"); @@ -60,17 +59,16 @@ public void testPooling() throws SQLException { PooledConnection pc = XADataSource1.getPooledConnection(); try (Connection conn = pc.getConnection()) { - - // create table in tempdb database - conn.createStatement().execute("create table [" + tempTableName + "] (myid int)"); - conn.createStatement().execute("insert into [" + tempTableName + "] values (1)"); + + // create table in tempdb database + conn.createStatement().execute("create table [" + tempTableName + "] (myid int)"); + conn.createStatement().execute("insert into [" + tempTableName + "] values (1)"); } boolean tempTableFileRemoved = false; try (Connection conn = pc.getConnection()) { conn.createStatement().executeQuery("select * from [" + tempTableName + "]"); - } - catch (SQLException e) { + } catch (SQLException e) { // make sure the temporary table is not found. if (e.getMessage().startsWith(TestResource.getResource("R_invalidObjectName"))) { tempTableFileRemoved = true; @@ -99,19 +97,20 @@ public void testConnectionPoolConnFunctions() throws SQLException { String tableName = RandomUtil.getIdentifier("table"); tableName = DBTable.escapeIdentifier(tableName); - String sql1 = "if exists (select * from dbo.sysobjects where name = '" + tableName + "' and type = 'U')\n" + "drop table " + tableName + "\n" - + "create table " + tableName + "\n" + "(\n" + "wibble_id int primary key not null,\n" + "counter int null\n" + ");"; - String sql2 = "if exists (select * from dbo.sysobjects where name = '" + tableName + "' and type = 'U')\n" + "drop table " + tableName + "\n"; + String sql1 = "if exists (select * from dbo.sysobjects where name = '" + tableName + "' and type = 'U')\n" + + "drop table " + tableName + "\n" + "create table " + tableName + "\n" + "(\n" + + "wibble_id int primary key not null,\n" + "counter int null\n" + ");"; + String sql2 = "if exists (select * from dbo.sysobjects where name = '" + tableName + "' and type = 'U')\n" + + "drop table " + tableName + "\n"; SQLServerXADataSource ds = new SQLServerXADataSource(); ds.setURL(connectionString); PooledConnection pc = ds.getPooledConnection(); - try (Connection con = pc.getConnection(); - Statement statement = con.createStatement()) { - statement.execute(sql1); - statement.execute(sql2); - con.clearWarnings(); + try (Connection con = pc.getConnection(); Statement statement = con.createStatement()) { + statement.execute(sql1); + statement.execute(sql2); + con.clearWarnings(); } pc.close(); } @@ -149,7 +148,7 @@ public void testConnectionPoolClientConnectionId() throws SQLException { assertEquals(Id1, Id2, TestResource.getResource("R_idFromPoolNotSame")); } - + /** * test connection pool with HikariCP * @@ -161,10 +160,9 @@ public void testHikariCP() throws SQLException { config.setJdbcUrl(connectionString); HikariDataSource ds = new HikariDataSource(config); - try{ + try { connect(ds); - } - finally{ + } finally { ds.close(); } } @@ -179,15 +177,13 @@ public void testApacheDBCP() throws SQLException { BasicDataSource ds = new BasicDataSource(); ds.setUrl(connectionString); - try{ + try { connect(ds); - } - finally{ + } finally { ds.close(); } } - /** * setup connection, get connection from pool, and test threads * @@ -207,12 +203,11 @@ private static void connect(DataSource ds) throws SQLException { // TODO : we are commenting this out due to AppVeyor failures. Will investigate later. // assertTrue(countTimeoutThreads() >= 1, "Timeout timer is missing."); - + while (rs.next()) { rs.getString(1); } - } - finally { + } finally { if (rs != null) { rs.close(); } @@ -236,10 +231,12 @@ private static int countTimeoutThreads() { int count = 0; String threadName = "mssql-jdbc-TimeoutTimer"; - ThreadInfo[] tinfos = ManagementFactory.getThreadMXBean().getThreadInfo(ManagementFactory.getThreadMXBean().getAllThreadIds(), 0); + ThreadInfo[] tinfos = ManagementFactory.getThreadMXBean() + .getThreadInfo(ManagementFactory.getThreadMXBean().getAllThreadIds(), 0); for (ThreadInfo ti : tinfos) { - if ((ti.getThreadName().startsWith(threadName)) && (ti.getThreadState().equals(java.lang.Thread.State.TIMED_WAITING))) { + if ((ti.getThreadName().startsWith(threadName)) + && (ti.getThreadState().equals(java.lang.Thread.State.TIMED_WAITING))) { count++; } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/connection/RequestBoundaryMethodsTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/connection/RequestBoundaryMethodsTest.java index 6f21fab11..0a2f73e12 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/connection/RequestBoundaryMethodsTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/connection/RequestBoundaryMethodsTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.connection; @@ -13,11 +10,15 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.CountDownLatch; import org.junit.jupiter.api.Test; @@ -31,6 +32,7 @@ import com.microsoft.sqlserver.testframework.Utils; import com.microsoft.sqlserver.testframework.util.RandomUtil; + /** * A class for testing Request Boundary Methods. */ @@ -56,6 +58,7 @@ public void testModifiableConnectionProperties() throws SQLException { int serverPreparedStatementDiscardThreshold1 = 10; boolean enablePrepareOnFirstPreparedStatementCall1 = false; String sCatalog1 = "master"; + boolean useBulkCopyForBatchInsert1 = true; boolean autoCommitMode2 = false; int transactionIsolationLevel2 = SQLServerConnection.TRANSACTION_SERIALIZABLE; @@ -67,6 +70,7 @@ public void testModifiableConnectionProperties() throws SQLException { int serverPreparedStatementDiscardThreshold2 = 100; boolean enablePrepareOnFirstPreparedStatementCall2 = true; String sCatalog2 = RandomUtil.getIdentifier("RequestBoundaryDatabase"); + boolean useBulkCopyForBatchInsert2 = false; try (SQLServerConnection con = connect()) { if (Utils.isJDBC43OrGreater(con)) { @@ -74,47 +78,56 @@ public void testModifiableConnectionProperties() throws SQLException { con.createStatement().executeUpdate("CREATE DATABASE [" + sCatalog2 + "]"); // First set of values. - setConnectionFields(con, autoCommitMode1, transactionIsolationLevel1, networkTimeout1, holdability1, sendTimeAsDatetime1, - statementPoolingCacheSize1, disableStatementPooling1, serverPreparedStatementDiscardThreshold1, - enablePrepareOnFirstPreparedStatementCall1, sCatalog1); + setConnectionFields(con, autoCommitMode1, transactionIsolationLevel1, networkTimeout1, holdability1, + sendTimeAsDatetime1, statementPoolingCacheSize1, disableStatementPooling1, + serverPreparedStatementDiscardThreshold1, enablePrepareOnFirstPreparedStatementCall1, sCatalog1, + useBulkCopyForBatchInsert1); con.beginRequest(); // Call setters with the second set of values inside beginRequest()/endRequest() block. - setConnectionFields(con, autoCommitMode2, transactionIsolationLevel2, networkTimeout2, holdability2, sendTimeAsDatetime2, - statementPoolingCacheSize2, disableStatementPooling2, serverPreparedStatementDiscardThreshold2, - enablePrepareOnFirstPreparedStatementCall2, sCatalog2); + setConnectionFields(con, autoCommitMode2, transactionIsolationLevel2, networkTimeout2, holdability2, + sendTimeAsDatetime2, statementPoolingCacheSize2, disableStatementPooling2, + serverPreparedStatementDiscardThreshold2, enablePrepareOnFirstPreparedStatementCall2, sCatalog2, + useBulkCopyForBatchInsert2); con.endRequest(); // Test if endRequest() resets the SQLServerConnection properties back to the first set of values. - compareValuesAgainstConnection(con, autoCommitMode1, transactionIsolationLevel1, networkTimeout1, holdability1, sendTimeAsDatetime1, - statementPoolingCacheSize1, disableStatementPooling1, serverPreparedStatementDiscardThreshold1, - enablePrepareOnFirstPreparedStatementCall1, sCatalog1); + compareValuesAgainstConnection(con, autoCommitMode1, transactionIsolationLevel1, networkTimeout1, + holdability1, sendTimeAsDatetime1, statementPoolingCacheSize1, disableStatementPooling1, + serverPreparedStatementDiscardThreshold1, enablePrepareOnFirstPreparedStatementCall1, sCatalog1, + useBulkCopyForBatchInsert1); // Multiple calls to beginRequest() without an intervening call to endRequest() are no-op. - setConnectionFields(con, autoCommitMode2, transactionIsolationLevel2, networkTimeout2, holdability2, sendTimeAsDatetime2, - statementPoolingCacheSize2, disableStatementPooling2, serverPreparedStatementDiscardThreshold2, - enablePrepareOnFirstPreparedStatementCall2, sCatalog2); + setConnectionFields(con, autoCommitMode2, transactionIsolationLevel2, networkTimeout2, holdability2, + sendTimeAsDatetime2, statementPoolingCacheSize2, disableStatementPooling2, + serverPreparedStatementDiscardThreshold2, enablePrepareOnFirstPreparedStatementCall2, sCatalog2, + useBulkCopyForBatchInsert2); con.beginRequest(); - setConnectionFields(con, autoCommitMode1, transactionIsolationLevel1, networkTimeout1, holdability1, sendTimeAsDatetime1, - statementPoolingCacheSize1, disableStatementPooling1, serverPreparedStatementDiscardThreshold1, - enablePrepareOnFirstPreparedStatementCall1, sCatalog1); + setConnectionFields(con, autoCommitMode1, transactionIsolationLevel1, networkTimeout1, holdability1, + sendTimeAsDatetime1, statementPoolingCacheSize1, disableStatementPooling1, + serverPreparedStatementDiscardThreshold1, enablePrepareOnFirstPreparedStatementCall1, sCatalog1, + useBulkCopyForBatchInsert1); con.beginRequest(); con.endRequest(); // Same values as before the first beginRequest() - compareValuesAgainstConnection(con, autoCommitMode2, transactionIsolationLevel2, networkTimeout2, holdability2, sendTimeAsDatetime2, - statementPoolingCacheSize2, disableStatementPooling2, serverPreparedStatementDiscardThreshold2, - enablePrepareOnFirstPreparedStatementCall2, sCatalog2); + compareValuesAgainstConnection(con, autoCommitMode2, transactionIsolationLevel2, networkTimeout2, + holdability2, sendTimeAsDatetime2, statementPoolingCacheSize2, disableStatementPooling2, + serverPreparedStatementDiscardThreshold2, enablePrepareOnFirstPreparedStatementCall2, sCatalog2, + useBulkCopyForBatchInsert2); // A call to endRequest() without an intervening call to beginRequest() is no-op. - setConnectionFields(con, autoCommitMode1, transactionIsolationLevel1, networkTimeout1, holdability1, sendTimeAsDatetime1, - statementPoolingCacheSize1, disableStatementPooling1, serverPreparedStatementDiscardThreshold1, - enablePrepareOnFirstPreparedStatementCall1, sCatalog1); - setConnectionFields(con, autoCommitMode2, transactionIsolationLevel2, networkTimeout2, holdability2, sendTimeAsDatetime2, - statementPoolingCacheSize2, disableStatementPooling2, serverPreparedStatementDiscardThreshold2, - enablePrepareOnFirstPreparedStatementCall2, sCatalog2); + setConnectionFields(con, autoCommitMode1, transactionIsolationLevel1, networkTimeout1, holdability1, + sendTimeAsDatetime1, statementPoolingCacheSize1, disableStatementPooling1, + serverPreparedStatementDiscardThreshold1, enablePrepareOnFirstPreparedStatementCall1, sCatalog1, + useBulkCopyForBatchInsert1); + setConnectionFields(con, autoCommitMode2, transactionIsolationLevel2, networkTimeout2, holdability2, + sendTimeAsDatetime2, statementPoolingCacheSize2, disableStatementPooling2, + serverPreparedStatementDiscardThreshold2, enablePrepareOnFirstPreparedStatementCall2, sCatalog2, + useBulkCopyForBatchInsert2); con.endRequest(); // No change. - compareValuesAgainstConnection(con, autoCommitMode2, transactionIsolationLevel2, networkTimeout2, holdability2, sendTimeAsDatetime2, - statementPoolingCacheSize2, disableStatementPooling2, serverPreparedStatementDiscardThreshold2, - enablePrepareOnFirstPreparedStatementCall2, sCatalog2); + compareValuesAgainstConnection(con, autoCommitMode2, transactionIsolationLevel2, networkTimeout2, + holdability2, sendTimeAsDatetime2, statementPoolingCacheSize2, disableStatementPooling2, + serverPreparedStatementDiscardThreshold2, enablePrepareOnFirstPreparedStatementCall2, sCatalog2, + useBulkCopyForBatchInsert2); // drop the database con.setCatalog("master"); Utils.dropDatabaseIfExists(sCatalog2, con.createStatement()); @@ -206,8 +219,10 @@ public void testStatements() throws SQLException { assertEquals(1, rs.getInt(1)); con.endRequest(); - assertTrue(!stmt1.isClosed(), "Statement created outside of beginRequest()/endRequest() block should not be closed."); - assertTrue(stmt.isClosed(), "Statment created inside beginRequest()/endRequest() block should be closed after endRequest()."); + assertTrue(!stmt1.isClosed(), + "Statement created outside of beginRequest()/endRequest() block should not be closed."); + assertTrue(stmt.isClosed(), + "Statment created inside beginRequest()/endRequest() block should be closed after endRequest()."); assertTrue(rs.isClosed(), "ResultSet should be closed after endRequest()."); stmt1.close(); @@ -237,8 +252,7 @@ public void testStatements() throws SQLException { assertTrue(cs.isClosed()); assertTrue(rs1.isClosed()); } - } - finally { + } finally { if (null != stmt) { stmt.close(); } @@ -278,8 +292,7 @@ public void run() { sharedVariables.con.setNetworkTimeout(null, 100); sharedVariables.con.setHoldability(ResultSet.CLOSE_CURSORS_AT_COMMIT); latch.countDown(); - } - catch (SQLException e) { + } catch (SQLException e) { e.printStackTrace(); Thread.currentThread().interrupt(); } @@ -294,8 +307,7 @@ public void run() { rs.next(); assertEquals(1, rs.getInt(1)); latch.countDown(); - } - catch (SQLException e) { + } catch (SQLException e) { e.printStackTrace(); Thread.currentThread().interrupt(); } @@ -310,8 +322,7 @@ public void run() { rs.next(); assertEquals(1, rs.getInt(1)); latch.countDown(); - } - catch (SQLException e) { + } catch (SQLException e) { e.printStackTrace(); Thread.currentThread().interrupt(); } @@ -333,12 +344,10 @@ public void run() { assertTrue(sharedVariables.stmt.isClosed()); assertTrue(sharedVariables.pstmt.isClosed()); } - } - catch (InterruptedException e) { + } catch (InterruptedException e) { e.printStackTrace(); Thread.currentThread().interrupt(); - } - finally { + } finally { if (null != sharedVariables.stmt) { sharedVariables.stmt.close(); } @@ -351,28 +360,41 @@ public void run() { } } + /** + * This is not really a test. The goal is to make the build fail if there are new public non-static methods in + * SQLServerConnection and notify the developer to decide whether it needs to be handled by + * beginRequest()/endRequest(). + * + * To fix the failure, you first need to check if the new method can modify connection local state after connection + * has been created. (See beginRequestInternal()/endRequestInternal() in SQLServerConnection). If yes, make sure it + * is handled by beginRequest()/endRequest() and then add it to verifiedMethodNames. If not, just + * adding the new method's name to the same list of verified methods is enough. + */ + @Test + public void testNewMethods() { + Method[] methods = SQLServerConnection.class.getDeclaredMethods(); + for (Method method : methods) { + assertTrue(isVerified(method), + "A failure is expected if you are adding a new public non-static method to SQLServerConnection." + + " See the test for instructions on how to fix the failure. "); + } + } + private SQLServerConnection connect() throws SQLException { SQLServerConnection connection = null; try { connection = PrepUtil.getConnection(getConfiguredProperty("mssql_jdbc_test_connection_properties")); - } - catch (ClassNotFoundException e) { + } catch (ClassNotFoundException e) { e.printStackTrace(); } return connection; } - private void setConnectionFields(SQLServerConnection con, - boolean autoCommitMode, - int transactionIsolationLevel, - int networkTimeout, - int holdability, - boolean sendTimeAsDatetime, - int statementPoolingCacheSize, - boolean disableStatementPooling, - int serverPreparedStatementDiscardThreshold, - boolean enablePrepareOnFirstPreparedStatementCall, - String sCatalog) throws SQLException { + private void setConnectionFields(SQLServerConnection con, boolean autoCommitMode, int transactionIsolationLevel, + int networkTimeout, int holdability, boolean sendTimeAsDatetime, int statementPoolingCacheSize, + boolean disableStatementPooling, int serverPreparedStatementDiscardThreshold, + boolean enablePrepareOnFirstPreparedStatementCall, String sCatalog, + boolean useBulkCopyForBatchInsert) throws SQLException { con.setAutoCommit(autoCommitMode); con.setTransactionIsolation(transactionIsolationLevel); con.setNetworkTimeout(null, networkTimeout); @@ -383,35 +405,87 @@ private void setConnectionFields(SQLServerConnection con, con.setServerPreparedStatementDiscardThreshold(serverPreparedStatementDiscardThreshold); con.setEnablePrepareOnFirstPreparedStatementCall(enablePrepareOnFirstPreparedStatementCall); con.setCatalog(sCatalog); + con.setUseBulkCopyForBatchInsert(useBulkCopyForBatchInsert); } - private void compareValuesAgainstConnection(SQLServerConnection con, - boolean autoCommitMode, - int transactionIsolationLevel, - int networkTimeout, - int holdability, - boolean sendTimeAsDatetime, - int statementPoolingCacheSize, - boolean disableStatementPooling, - int serverPreparedStatementDiscardThreshold, - boolean enablePrepareOnFirstPreparedStatementCall, - String sCatalog) throws SQLException { + private void compareValuesAgainstConnection(SQLServerConnection con, boolean autoCommitMode, + int transactionIsolationLevel, int networkTimeout, int holdability, boolean sendTimeAsDatetime, + int statementPoolingCacheSize, boolean disableStatementPooling, int serverPreparedStatementDiscardThreshold, + boolean enablePrepareOnFirstPreparedStatementCall, String sCatalog, + boolean useBulkCopyForBatchInsert) throws SQLException { final String description = " values do not match."; assertEquals(autoCommitMode, con.getAutoCommit(), "autoCommitmode" + description); - assertEquals(transactionIsolationLevel, con.getTransactionIsolation(), "transactionIsolationLevel" + description); + assertEquals(transactionIsolationLevel, con.getTransactionIsolation(), + "transactionIsolationLevel" + description); assertEquals(networkTimeout, con.getNetworkTimeout(), "networkTimeout" + description); assertEquals(holdability, con.getHoldability(), "holdability" + description); assertEquals(sendTimeAsDatetime, con.getSendTimeAsDatetime(), "sendTimeAsDatetime" + description); - assertEquals(statementPoolingCacheSize, con.getStatementPoolingCacheSize(), "statementPoolingCacheSize" + description); - assertEquals(disableStatementPooling, con.getDisableStatementPooling(), "disableStatementPooling" + description); + assertEquals(statementPoolingCacheSize, con.getStatementPoolingCacheSize(), + "statementPoolingCacheSize" + description); + assertEquals(disableStatementPooling, con.getDisableStatementPooling(), + "disableStatementPooling" + description); assertEquals(serverPreparedStatementDiscardThreshold, con.getServerPreparedStatementDiscardThreshold(), "serverPreparedStatementDiscardThreshold" + description); assertEquals(enablePrepareOnFirstPreparedStatementCall, con.getEnablePrepareOnFirstPreparedStatementCall(), "enablePrepareOnFirstPreparedStatementCall" + description); assertEquals(sCatalog, con.getCatalog(), "sCatalog" + description); + assertEquals(useBulkCopyForBatchInsert, con.getUseBulkCopyForBatchInsert(), + "useBulkCopyForBatchInsert" + description); } private void generateWarning(SQLServerConnection con) throws SQLException { con.setClientInfo("name", "value"); } + + private boolean isVerified(Method method) { + return (!Modifier.isPublic(method.getModifiers()) || Modifier.isStatic(method.getModifiers()) + || method.getName().startsWith("get") || getVerifiedMethodNames().contains(method.getName())); + } + + private List getVerifiedMethodNames() { + List verifiedMethodNames = new ArrayList(); + + verifiedMethodNames.add("toString"); + verifiedMethodNames.add("setReadOnly"); + verifiedMethodNames.add("close"); + verifiedMethodNames.add("unwrap"); + verifiedMethodNames.add("isReadOnly"); + verifiedMethodNames.add("abort"); + verifiedMethodNames.add("isValid"); + verifiedMethodNames.add("setServerPreparedStatementDiscardThreshold"); + verifiedMethodNames.add("setEnablePrepareOnFirstPreparedStatementCall"); + verifiedMethodNames.add("isClosed"); + verifiedMethodNames.add("setSendTimeAsDatetime"); + verifiedMethodNames.add("setStatementPoolingCacheSize"); + verifiedMethodNames.add("setDisableStatementPooling"); + verifiedMethodNames.add("setTransactionIsolation"); + verifiedMethodNames.add("setUseBulkCopyForBatchInsert"); + verifiedMethodNames.add("commit"); + verifiedMethodNames.add("clearWarnings"); + verifiedMethodNames.add("prepareStatement"); + verifiedMethodNames.add("prepareCall"); + verifiedMethodNames.add("setCatalog"); + verifiedMethodNames.add("setAutoCommit"); + verifiedMethodNames.add("createStatement"); + verifiedMethodNames.add("setClientInfo"); + verifiedMethodNames.add("setNetworkTimeout"); + verifiedMethodNames.add("setHoldability"); + verifiedMethodNames.add("closeUnreferencedPreparedStatementHandles"); + verifiedMethodNames.add("isStatementPoolingEnabled"); + verifiedMethodNames.add("rollback"); + verifiedMethodNames.add("releaseSavepoint"); + verifiedMethodNames.add("createStruct"); + verifiedMethodNames.add("createSQLXML"); + verifiedMethodNames.add("setSchema"); + verifiedMethodNames.add("createNClob"); + verifiedMethodNames.add("nativeSQL"); + verifiedMethodNames.add("setSavepoint"); + verifiedMethodNames.add("createClob"); + verifiedMethodNames.add("createBlob"); + verifiedMethodNames.add("isWrapperFor"); + verifiedMethodNames.add("setTypeMap"); + verifiedMethodNames.add("createArrayOf"); + + return verifiedMethodNames; + } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/connection/SSLProtocolTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/connection/SSLProtocolTest.java index e5eced4ad..cdab7c139 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/connection/SSLProtocolTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/connection/SSLProtocolTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.connection; @@ -15,7 +12,6 @@ import java.sql.DatabaseMetaData; import java.sql.DriverManager; import java.sql.Statement; - import java.text.MessageFormat; import org.junit.jupiter.api.Test; @@ -27,6 +23,7 @@ import com.microsoft.sqlserver.jdbc.TestResource; import com.microsoft.sqlserver.testframework.AbstractTest; + /** * Tests new connection property sslProtocol */ @@ -49,8 +46,7 @@ public void testWithSupportedProtocols(String sslProtocol) throws Exception { DatabaseMetaData dbmd = con.getMetaData(); assertNotNull(dbmd); assertTrue(!StringUtils.isEmpty(dbmd.getDatabaseProductName())); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { // Some older versions of SQLServer might not have all the TLS protocol versions enabled. // Example, if the highest TLS version enabled in the server is TLSv1.1, // the connection will fail if we enable only TLSv1.2 @@ -58,7 +54,6 @@ public void testWithSupportedProtocols(String sslProtocol) throws Exception { } } - /** * Connect with unsupported protocol * @@ -70,13 +65,13 @@ public void testWithUnSupportedProtocols(String sslProtocol) throws Exception { String url = connectionString + ";sslProtocol=" + sslProtocol; con = DriverManager.getConnection(url); assertFalse(true, TestResource.getResource("R_protocolVersion")); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { assertTrue(true, TestResource.getResource("R_shouldThrowException")); MessageFormat form = new MessageFormat(TestResource.getResource("R_invalidProtocolLabel")); Object[] msgArgs = {sslProtocol}; String errMsg = form.format(msgArgs); - assertTrue(errMsg.equals(e.getMessage()), TestResource.getResource("R_SQLServerResourceMessage") + e.getMessage()); + assertTrue(errMsg.equals(e.getMessage()), + TestResource.getResource("R_SQLServerResourceMessage") + e.getMessage()); } } @@ -87,7 +82,8 @@ public void testWithUnSupportedProtocols(String sslProtocol) throws Exception { */ @Test public void testConnectWithWrongProtocols() throws Exception { - String[] wrongProtocols = {"SSLv1111", "SSLv2222", "SSLv3111", "SSLv2Hello1111", "TLSv1.11", "TLSv2.4", "random"}; + String[] wrongProtocols = {"SSLv1111", "SSLv2222", "SSLv3111", "SSLv2Hello1111", "TLSv1.11", "TLSv2.4", + "random"}; for (String wrongProtocol : wrongProtocols) { testWithUnSupportedProtocols(wrongProtocol); } @@ -106,4 +102,3 @@ public void testConnectWithSupportedProtocols() throws Exception { } } } - diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/connection/TimeoutTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/connection/TimeoutTest.java index 2382dfeed..53d7f564b 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/connection/TimeoutTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/connection/TimeoutTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.connection; @@ -26,6 +23,7 @@ import com.microsoft.sqlserver.testframework.Utils; import com.microsoft.sqlserver.testframework.util.RandomUtil; + @RunWith(JUnitPlatform.class) public class TimeoutTest extends AbstractTest { String randomServer = RandomUtil.getIdentifier("Server"); @@ -41,8 +39,7 @@ public void testDefaultLoginTimeout() { timerStart = System.currentTimeMillis(); // Try a non existing server and see if the default timeout is 15 seconds DriverManager.getConnection("jdbc:sqlserver://" + randomServer + ";user=sa;password=pwd;"); - } - catch (Exception e) { + } catch (Exception e) { assertTrue(e.getMessage().contains(TestResource.getResource("R_tcpipConnectionToHost"))); timerEnd = System.currentTimeMillis(); } @@ -59,10 +56,9 @@ public void testFailoverInstanceResolution() throws SQLException { try { timerStart = System.currentTimeMillis(); // Try a non existing server and see if the default timeout is 15 seconds - DriverManager.getConnection("jdbc:sqlserver://" + randomServer + ";databaseName=FailoverDB_abc;failoverPartner=" + randomServer - + "\\foo;user=sa;password=pwd;"); - } - catch (Exception e) { + DriverManager.getConnection("jdbc:sqlserver://" + randomServer + + ";databaseName=FailoverDB_abc;failoverPartner=" + randomServer + "\\foo;user=sa;password=pwd;"); + } catch (Exception e) { assertTrue(e.getMessage().contains(TestResource.getResource("R_tcpipConnectionToHost"))); timerEnd = System.currentTimeMillis(); } @@ -79,10 +75,10 @@ public void testFOInstanceResolution2() throws SQLException { try { timerStart = System.currentTimeMillis(); // Try a non existing server and see if the default timeout is 15 secs at least - DriverManager.getConnection("jdbc:sqlserver://" + randomServer + "\\fooggg;databaseName=FailoverDB;failoverPartner=" + randomServer - + "\\foo;user=sa;password=pwd;"); - } - catch (Exception e) { + DriverManager.getConnection( + "jdbc:sqlserver://" + randomServer + "\\fooggg;databaseName=FailoverDB;failoverPartner=" + + randomServer + "\\foo;user=sa;password=pwd;"); + } catch (Exception e) { timerEnd = System.currentTimeMillis(); } assertTrue(0 != timerEnd, TestResource.getResource("R_shouldNotConnect")); @@ -92,7 +88,8 @@ public void testFOInstanceResolution2() throws SQLException { } /** - * When query timeout occurs, the connection is still usable. + * When query timeout occurs, the connection is still usable. + * * @throws Exception */ @Test @@ -102,27 +99,29 @@ public void testQueryTimeout() throws Exception { dropWaitForDelayProcedure(conn); createWaitForDelayPreocedure(conn); - conn = (SQLServerConnection) DriverManager.getConnection(connectionString + ";queryTimeout=" + (waitForDelaySeconds / 2) + ";"); - + conn = (SQLServerConnection) DriverManager + .getConnection(connectionString + ";queryTimeout=" + (waitForDelaySeconds / 2) + ";"); + try { conn.createStatement().execute("exec " + waitForDelaySPName); throw new Exception(TestResource.getResource("R_expectedExceptionNotThrown")); - } - catch (Exception e) { + } catch (Exception e) { if (!(e instanceof java.sql.SQLTimeoutException)) { throw e; } - assertEquals(e.getMessage(), TestResource.getResource("R_queryTimedOut"), TestResource.getResource("R_invalidExceptionMessage")); + assertEquals(e.getMessage(), TestResource.getResource("R_queryTimedOut"), + TestResource.getResource("R_invalidExceptionMessage")); } - try{ + try { conn.createStatement().execute("SELECT @@version"); - }catch (Exception e) { - fail(TestResource.getResource("R_unexpectedErrorMessage") + e.toString() ); + } catch (Exception e) { + fail(TestResource.getResource("R_unexpectedErrorMessage") + e.toString()); } } - + /** * Tests sanity of connection property. + * * @throws Exception */ @Test @@ -132,28 +131,30 @@ public void testCancelQueryTimeout() throws Exception { dropWaitForDelayProcedure(conn); createWaitForDelayPreocedure(conn); - conn = (SQLServerConnection) DriverManager.getConnection(connectionString + ";queryTimeout=" + (waitForDelaySeconds / 2) + ";cancelQueryTimeout=" + waitForDelaySeconds + ";"); - + conn = (SQLServerConnection) DriverManager.getConnection(connectionString + ";queryTimeout=" + + (waitForDelaySeconds / 2) + ";cancelQueryTimeout=" + waitForDelaySeconds + ";"); + try { SQLServerStatement statement = (SQLServerStatement) conn.createStatement(); statement.execute("exec " + waitForDelaySPName); throw new Exception(TestResource.getResource("R_expectedExceptionNotThrown")); - } - catch (Exception e) { + } catch (Exception e) { if (!(e instanceof java.sql.SQLTimeoutException)) { throw e; } - assertEquals(e.getMessage(), TestResource.getResource("R_queryTimedOut"), TestResource.getResource("R_invalidExceptionMessage")); + assertEquals(e.getMessage(), TestResource.getResource("R_queryTimedOut"), + TestResource.getResource("R_invalidExceptionMessage")); } - try{ + try { conn.createStatement().execute("SELECT @@version"); - }catch (Exception e) { - fail(TestResource.getResource("R_unexpectedErrorMessage") + e.toString() ); + } catch (Exception e) { + fail(TestResource.getResource("R_unexpectedErrorMessage") + e.toString()); } } /** * Tests sanity of connection property. + * * @throws Exception */ @Test @@ -164,29 +165,30 @@ public void testCancelQueryTimeoutOnStatement() throws Exception { createWaitForDelayPreocedure(conn); conn = (SQLServerConnection) DriverManager.getConnection(connectionString + ";"); - + try { SQLServerStatement statement = (SQLServerStatement) conn.createStatement(); - statement.setQueryTimeout(waitForDelaySeconds/2); + statement.setQueryTimeout(waitForDelaySeconds / 2); statement.setCancelQueryTimeout(waitForDelaySeconds); statement.execute("exec " + waitForDelaySPName); throw new Exception(TestResource.getResource("R_expectedExceptionNotThrown")); - } - catch (Exception e) { + } catch (Exception e) { if (!(e instanceof java.sql.SQLTimeoutException)) { throw e; } - assertEquals(e.getMessage(), TestResource.getResource("R_queryTimedOut"), TestResource.getResource("R_invalidExceptionMessage")); + assertEquals(e.getMessage(), TestResource.getResource("R_queryTimedOut"), + TestResource.getResource("R_invalidExceptionMessage")); } - try{ + try { conn.createStatement().execute("SELECT @@version"); - }catch (Exception e) { - fail(TestResource.getResource("R_unexpectedErrorMessage") + e.toString() ); + } catch (Exception e) { + fail(TestResource.getResource("R_unexpectedErrorMessage") + e.toString()); } } - + /** * When socketTimeout occurs, the connection will be marked as closed. + * * @throws Exception */ @Test @@ -196,22 +198,24 @@ public void testSocketTimeout() throws Exception { dropWaitForDelayProcedure(conn); createWaitForDelayPreocedure(conn); - conn = (SQLServerConnection) DriverManager.getConnection(connectionString + ";socketTimeout=" + (waitForDelaySeconds * 1000 / 2) + ";"); + conn = (SQLServerConnection) DriverManager + .getConnection(connectionString + ";socketTimeout=" + (waitForDelaySeconds * 1000 / 2) + ";"); try { conn.createStatement().execute("exec " + waitForDelaySPName); throw new Exception(TestResource.getResource("R_expectedExceptionNotThrown")); - } - catch (Exception e) { + } catch (Exception e) { if (!(e instanceof SQLException)) { throw e; } - assertEquals(e.getMessage(), TestResource.getResource("R_readTimedOut"), TestResource.getResource("R_invalidExceptionMessage")); + assertEquals(e.getMessage(), TestResource.getResource("R_readTimedOut"), + TestResource.getResource("R_invalidExceptionMessage")); } - try{ + try { conn.createStatement().execute("SELECT @@version"); - }catch (SQLException e) { - assertEquals(e.getMessage(), TestResource.getResource("R_connectionIsClosed"), TestResource.getResource("R_invalidExceptionMessage")); + } catch (SQLException e) { + assertEquals(e.getMessage(), TestResource.getResource("R_connectionIsClosed"), + TestResource.getResource("R_invalidExceptionMessage")); } } @@ -220,7 +224,8 @@ private void dropWaitForDelayProcedure(SQLServerConnection conn) throws SQLExcep } private void createWaitForDelayPreocedure(SQLServerConnection conn) throws SQLException { - String sql = "CREATE PROCEDURE " + waitForDelaySPName + " AS" + " BEGIN" + " WAITFOR DELAY '00:00:" + waitForDelaySeconds + "';" + " END"; + String sql = "CREATE PROCEDURE " + waitForDelaySPName + " AS" + " BEGIN" + " WAITFOR DELAY '00:00:" + + waitForDelaySeconds + "';" + " END"; conn.createStatement().execute(sql); } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/connection/WarningTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/connection/WarningTest.java index 6b3cccbf4..45d15dc20 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/connection/WarningTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/connection/WarningTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.connection; @@ -25,6 +22,7 @@ import com.microsoft.sqlserver.jdbc.TestResource; import com.microsoft.sqlserver.testframework.AbstractTest; + @RunWith(JUnitPlatform.class) public class WarningTest extends AbstractTest { @Test diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/databasemetadata/DatabaseMetaDataForeignKeyTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/databasemetadata/DatabaseMetaDataForeignKeyTest.java index 403d876e2..8c38b10d8 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/databasemetadata/DatabaseMetaDataForeignKeyTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/databasemetadata/DatabaseMetaDataForeignKeyTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.databasemetadata; @@ -29,6 +26,7 @@ import com.microsoft.sqlserver.testframework.AbstractTest; import com.microsoft.sqlserver.testframework.Utils; + /** * Test class for testing DatabaseMetaData with foreign keys. */ @@ -42,43 +40,48 @@ public class DatabaseMetaDataForeignKeyTest extends AbstractTest { private static String table3 = "DatabaseMetaDataForeignKeyTest_table_3"; private static String table4 = "DatabaseMetaDataForeignKeyTest_table_4"; private static String table5 = "DatabaseMetaDataForeignKeyTest_table_5"; - + private static String schema = null; private static String catalog = null; - + @BeforeAll - private static void setupVariation() throws SQLException { + public static void setupVariation() throws SQLException { conn = (SQLServerConnection) DriverManager.getConnection(connectionString); SQLServerStatement stmt = (SQLServerStatement) conn.createStatement(); catalog = conn.getCatalog(); schema = conn.getSchema(); - connection.createStatement().executeUpdate("if object_id('" + table1 + "','U') is not null drop table " + table1); + connection.createStatement() + .executeUpdate("if object_id('" + table1 + "','U') is not null drop table " + table1); - connection.createStatement().executeUpdate("if object_id('" + table2 + "','U') is not null drop table " + table2); + connection.createStatement() + .executeUpdate("if object_id('" + table2 + "','U') is not null drop table " + table2); stmt.execute("Create table " + table2 + " (c21 int NOT NULL PRIMARY KEY)"); - connection.createStatement().executeUpdate("if object_id('" + table3 + "','U') is not null drop table " + table3); + connection.createStatement() + .executeUpdate("if object_id('" + table3 + "','U') is not null drop table " + table3); stmt.execute("Create table " + table3 + " (c31 int NOT NULL PRIMARY KEY)"); - connection.createStatement().executeUpdate("if object_id('" + table4 + "','U') is not null drop table " + table4); + connection.createStatement() + .executeUpdate("if object_id('" + table4 + "','U') is not null drop table " + table4); stmt.execute("Create table " + table4 + " (c41 int NOT NULL PRIMARY KEY)"); - connection.createStatement().executeUpdate("if object_id('" + table5 + "','U') is not null drop table " + table5); + connection.createStatement() + .executeUpdate("if object_id('" + table5 + "','U') is not null drop table " + table5); stmt.execute("Create table " + table5 + " (c51 int NOT NULL PRIMARY KEY)"); - connection.createStatement().executeUpdate("if object_id('" + table1 + "','U') is not null drop table " + table1); - stmt.execute("Create table " + table1 + " (c11 int primary key," - + " c12 int FOREIGN KEY REFERENCES " + table2 + "(c21) ON DELETE no action ON UPDATE set default," - + " c13 int FOREIGN KEY REFERENCES " + table3 + "(c31) ON DELETE cascade ON UPDATE set null," - + " c14 int FOREIGN KEY REFERENCES " + table4 + "(c41) ON DELETE set null ON UPDATE cascade," - + " c15 int FOREIGN KEY REFERENCES " + table5 + "(c51) ON DELETE set default ON UPDATE no action," - + ")"); + connection.createStatement() + .executeUpdate("if object_id('" + table1 + "','U') is not null drop table " + table1); + stmt.execute("Create table " + table1 + " (c11 int primary key," + " c12 int FOREIGN KEY REFERENCES " + table2 + + "(c21) ON DELETE no action ON UPDATE set default," + " c13 int FOREIGN KEY REFERENCES " + table3 + + "(c31) ON DELETE cascade ON UPDATE set null," + " c14 int FOREIGN KEY REFERENCES " + table4 + + "(c41) ON DELETE set null ON UPDATE cascade," + " c15 int FOREIGN KEY REFERENCES " + table5 + + "(c51) ON DELETE set default ON UPDATE no action," + ")"); } @AfterAll - private static void terminateVariation() throws SQLException { + public static void terminateVariation() throws SQLException { conn = (SQLServerConnection) DriverManager.getConnection(connectionString); stmt = (SQLServerStatement) conn.createStatement(); @@ -93,7 +96,7 @@ private static void terminateVariation() throws SQLException { * test getImportedKeys() methods * * @throws SQLException - * @throws SQLTimeoutException + * @throws SQLTimeoutException */ @Test public void testGetImportedKeys() throws SQLException { @@ -111,8 +114,7 @@ public void testGetImportedKeys() throws SQLException { try { dmd.getImportedKeys("", schema, table1); fail(TestResource.getResource("R_expectedExceptionNotThrown")); - } - catch (SQLException e) { + } catch (SQLException e) { assertTrue(e.getMessage().startsWith(TestResource.getResource("R_dbNameIsCurrentDB"))); } } @@ -120,48 +122,44 @@ public void testGetImportedKeys() throws SQLException { private void validateGetImportedKeysResults(SQLServerResultSet rs) throws SQLException { int expectedRowCount = 4; int rowCount = 0; - + rs.next(); assertEquals(4, rs.getInt("UPDATE_RULE")); assertEquals(3, rs.getInt("DELETE_RULE")); rowCount++; - + rs.next(); assertEquals(2, rs.getInt("UPDATE_RULE")); assertEquals(0, rs.getInt("DELETE_RULE")); rowCount++; - + rs.next(); assertEquals(0, rs.getInt("UPDATE_RULE")); assertEquals(2, rs.getInt("DELETE_RULE")); rowCount++; - + rs.next(); assertEquals(3, rs.getInt("UPDATE_RULE")); assertEquals(4, rs.getInt("DELETE_RULE")); rowCount++; - if(expectedRowCount != rowCount) { + if (expectedRowCount != rowCount) { assertEquals(expectedRowCount, rowCount, TestResource.getResource("R_numKeysIncorrect")); } } - + /** * test getExportedKeys() methods * * @throws SQLException - * @throws SQLTimeoutException + * @throws SQLTimeoutException */ @Test public void testGetExportedKeys() throws SQLException { String[] tableNames = {table2, table3, table4, table5}; int[][] values = { // expected UPDATE_RULE, expected DELETE_RULE - {4, 3}, - {2, 0}, - {0, 2}, - {3, 4} - }; + {4, 3}, {2, 0}, {0, 2}, {3, 4}}; SQLServerDatabaseMetaData dmd = (SQLServerDatabaseMetaData) connection.getMetaData(); @@ -185,18 +183,17 @@ public void testGetExportedKeys() throws SQLException { try { dmd.getExportedKeys("", schema, pkTable); fail(TestResource.getResource("R_expectedExceptionNotThrown")); - } - catch (SQLException e) { + } catch (SQLException e) { assertTrue(e.getMessage().startsWith(TestResource.getResource("R_dbNameIsCurrentDB"))); } } } - + /** * test getCrossReference() methods * * @throws SQLException - * @throws SQLTimeoutException + * @throws SQLTimeoutException */ @Test public void testGetCrossReference() throws SQLException { @@ -204,27 +201,26 @@ public void testGetCrossReference() throws SQLException { String[] tableNames = {table2, table3, table4, table5}; int[][] values = { // expected UPDATE_RULE, expected DELETE_RULE - {4, 3}, - {2, 0}, - {0, 2}, - {3, 4} - }; + {4, 3}, {2, 0}, {0, 2}, {3, 4}}; SQLServerDatabaseMetaData dmd = (SQLServerDatabaseMetaData) connection.getMetaData(); for (int i = 0; i < tableNames.length; i++) { String pkTable = tableNames[i]; - SQLServerResultSet rs1 = (SQLServerResultSet) dmd.getCrossReference(null, null, pkTable, null, null, fkTable); + SQLServerResultSet rs1 = (SQLServerResultSet) dmd.getCrossReference(null, null, pkTable, null, null, + fkTable); rs1.next(); assertEquals(values[i][0], rs1.getInt("UPDATE_RULE")); assertEquals(values[i][1], rs1.getInt("DELETE_RULE")); - SQLServerResultSet rs2 = (SQLServerResultSet) dmd.getCrossReference(catalog, schema, pkTable, catalog, schema, fkTable); + SQLServerResultSet rs2 = (SQLServerResultSet) dmd.getCrossReference(catalog, schema, pkTable, catalog, + schema, fkTable); rs2.next(); assertEquals(values[i][0], rs2.getInt("UPDATE_RULE")); assertEquals(values[i][1], rs2.getInt("DELETE_RULE")); - SQLServerResultSet rs3 = (SQLServerResultSet) dmd.getCrossReference(catalog, "", pkTable, catalog, "", fkTable); + SQLServerResultSet rs3 = (SQLServerResultSet) dmd.getCrossReference(catalog, "", pkTable, catalog, "", + fkTable); rs3.next(); assertEquals(values[i][0], rs3.getInt("UPDATE_RULE")); assertEquals(values[i][1], rs3.getInt("DELETE_RULE")); @@ -232,8 +228,7 @@ public void testGetCrossReference() throws SQLException { try { dmd.getCrossReference("", schema, pkTable, "", schema, fkTable); fail(TestResource.getResource("R_expectedExceptionNotThrown")); - } - catch (SQLException e) { + } catch (SQLException e) { assertEquals(TestResource.getResource("R_dbNameIsCurrentDB"), e.getMessage()); } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/databasemetadata/DatabaseMetaDataTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/databasemetadata/DatabaseMetaDataTest.java index 403ccfd79..95f0c2799 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/databasemetadata/DatabaseMetaDataTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/databasemetadata/DatabaseMetaDataTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.databasemetadata; @@ -26,10 +23,10 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import java.text.MessageFormat; import java.util.UUID; import java.util.jar.Attributes; import java.util.jar.Manifest; -import java.text.MessageFormat; import org.junit.jupiter.api.Test; import org.junit.platform.runner.JUnitPlatform; @@ -41,6 +38,7 @@ import com.microsoft.sqlserver.testframework.AbstractTest; import com.microsoft.sqlserver.testframework.Utils; + /** * Test class for testing DatabaseMetaData. */ @@ -62,15 +60,17 @@ public void testDatabaseMetaDataWrapper() throws SQLException { } /** - * Testing if driver version is matching with manifest file or not. Will be useful while releasing preview / RTW release. + * Testing if driver version is matching with manifest file or not. Will be useful while releasing preview / RTW + * release. * - * //TODO: OSGI: Test for capability 1.7 for JDK 1.7 and 1.8 for 1.8 //Require-Capability: osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))" //String - * capability = attributes.getValue("Require-Capability"); + * //TODO: OSGI: Test for capability 1.7 for JDK 1.7 and 1.8 for 1.8 //Require-Capability: + * osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=1.8))" //String capability = + * attributes.getValue("Require-Capability"); * * @throws SQLException - * SQL Exception + * SQL Exception * @throws IOException - * IOExcption + * IOExcption */ @Test public void testDriverVersion() throws SQLException, IOException { @@ -104,12 +104,9 @@ public void testDriverVersion() throws SQLException, IOException { int intDriverVersion = Integer.valueOf(driverVersion); if (isSnapshot) { - assertTrue(intDriverVersion < intBuildVersion, - TestResource.getResource("R_buildVersionError")); - } - else { - assertTrue(intDriverVersion == intBuildVersion, - TestResource.getResource("R_buildVersionError")); + assertTrue(intDriverVersion < intBuildVersion, TestResource.getResource("R_buildVersionError")); + } else { + assertTrue(intDriverVersion == intBuildVersion, TestResource.getResource("R_buildVersionError")); } } @@ -147,8 +144,7 @@ public void testDBUserLogin() throws SQLException { startIndex = connectionString.indexOf("username="); endIndex = connectionString.indexOf(";", startIndex); startIndex = startIndex + "username=".length(); - } - else if (connectionString.contains("user")) { + } else if (connectionString.contains("user")) { startIndex = connectionString.indexOf("user="); endIndex = connectionString.indexOf(";", startIndex); startIndex = startIndex + "user=".length(); @@ -159,12 +155,12 @@ else if (connectionString.contains("user")) { assertNotNull(userName, TestResource.getResource("R_userNameNull")); - assertTrue(userName.equalsIgnoreCase(userFromConnectionString), - TestResource.getResource("R_userNameNotMatch")); + assertTrue(userName.equalsIgnoreCase(userFromConnectionString), TestResource.getResource("R_userNameNotMatch")); } /** * Testing of {@link SQLServerDatabaseMetaData#getSchemas()} + * * @throws SQLException */ @Test @@ -179,9 +175,10 @@ public void testDBSchema() throws SQLException { assertTrue(!StringUtils.isEmpty(rs.getString(1)), form.format(msgArgs)); } } - + /** - * Tests that the catalog parameter containing - is escaped by {@link SQLServerDatabaseMetaData#getSchemas(String catalog, String schemaPattern)}. + * Tests that the catalog parameter containing - is escaped by + * {@link SQLServerDatabaseMetaData#getSchemas(String catalog, String schemaPattern)}. * * @throws SQLException */ @@ -192,7 +189,8 @@ public void testDBSchemasForDashedCatalogName() throws SQLException { String testSchema = "some-schema" + id; try (Statement stmt = connection.createStatement()) { - try (Connection dashConn = DriverManager.getConnection(connectionString); Statement dashStatement = dashConn.createStatement()) { + try (Connection dashConn = DriverManager.getConnection(connectionString); + Statement dashStatement = dashConn.createStatement()) { Utils.dropDatabaseIfExists(testCatalog, stmt); stmt.execute(String.format("CREATE DATABASE [%s]", testCatalog)); @@ -216,8 +214,7 @@ public void testDBSchemasForDashedCatalogName() throws SQLException { if (schemaName.equals(testSchema)) { hasDashCatalogSchema = true; assertEquals(catalogName, testCatalog); - } - else { + } else { assertNull(catalogName); } } @@ -227,15 +224,15 @@ public void testDBSchemasForDashedCatalogName() throws SQLException { MessageFormat dashCatalogFormat = new MessageFormat(TestResource.getResource("R_atLeastOneFound")); assertTrue(hasDashCatalogSchema, dashCatalogFormat.format(new Object[] {testSchema})); - } - finally { + } finally { Utils.dropDatabaseIfExists(testCatalog, stmt); } } } /** - * Tests that the catalog parameter containing - is escaped by {@link SQLServerDatabaseMetaData#getSchemas(String catalog, String schemaPattern)}. + * Tests that the catalog parameter containing - is escaped by + * {@link SQLServerDatabaseMetaData#getSchemas(String catalog, String schemaPattern)}. * * @throws SQLException */ @@ -246,7 +243,8 @@ public void testDBSchemasForDashedCatalogNameWithPattern() throws SQLException { String testSchema = "some-schema" + id; try (Statement stmt = connection.createStatement()) { - try (Connection dashConn = DriverManager.getConnection(connectionString); Statement dashStatement = dashConn.createStatement()) { + try (Connection dashConn = DriverManager.getConnection(connectionString); + Statement dashStatement = dashConn.createStatement()) { Utils.dropDatabaseIfExists(testCatalog, stmt); stmt.execute(String.format("CREATE DATABASE [%s]", testCatalog)); @@ -274,8 +272,7 @@ public void testDBSchemasForDashedCatalogNameWithPattern() throws SQLException { MessageFormat atLeastOneFoundFormat = new MessageFormat(TestResource.getResource("R_atLeastOneFound")); assertTrue(hasResults, atLeastOneFoundFormat.format(schemaMsgArgs)); - } - finally { + } finally { Utils.dropDatabaseIfExists(testCatalog, stmt); } } @@ -289,16 +286,16 @@ public void testDBSchemasForDashedCatalogNameWithPattern() throws SQLException { @Test public void testDBTables() throws SQLException { DatabaseMetaData databaseMetaData = connection.getMetaData(); - + ResultSet rsCatalog = databaseMetaData.getCatalogs(); - + MessageFormat form1 = new MessageFormat(TestResource.getResource("R_atLeastOneFound")); Object[] msgArgs1 = {"catalog"}; assertTrue(rsCatalog.next(), form1.format(msgArgs1)); - + String[] types = {"TABLE"}; ResultSet rs = databaseMetaData.getTables(rsCatalog.getString("TABLE_CAT"), null, "%", types); - + MessageFormat form2 = new MessageFormat(TestResource.getResource("R_nameEmpty")); Object[] msgArgs2 = {"Table"}; while (rs.next()) { @@ -307,12 +304,14 @@ public void testDBTables() throws SQLException { } /** - * Testing DB Columns.

+ * Testing DB Columns. + *

* We can Improve this test scenario by following way. *

    - *
  • Create table with appropriate column size, data types,auto increment, NULLABLE etc. - *
  • Then get databasemetatadata.getColumns to see if there is any mismatch. + *
  • Create table with appropriate column size, data types,auto increment, NULLABLE etc. + *
  • Then get databasemetatadata.getColumns to see if there is any mismatch. *
+ * * @throws SQLException */ @Test @@ -320,17 +319,18 @@ public void testGetDBColumn() throws SQLException { DatabaseMetaData databaseMetaData = connection.getMetaData(); String[] types = {"TABLE"}; ResultSet rs = databaseMetaData.getTables(null, null, "%", types); - - //Fetch one table + + // Fetch one table MessageFormat form1 = new MessageFormat(TestResource.getResource("R_atLeastOneFound")); Object[] msgArgs1 = {"table"}; assertTrue(rs.next(), form1.format(msgArgs1)); - - //Go through all columns. + + // Go through all columns. ResultSet rs1 = databaseMetaData.getColumns(null, null, rs.getString("TABLE_NAME"), "%"); - + MessageFormat form2 = new MessageFormat(TestResource.getResource("R_nameEmpty")); - Object[][] msgArgs2 = {{"Category"}, {"SCHEMA"}, {"Table"}, {"COLUMN"}, {"Data Type"}, {"Type"}, {"Column Size"}, {"Nullable value"}, {"IS_NULLABLE"}, {"IS_AUTOINCREMENT"}}; + Object[][] msgArgs2 = {{"Category"}, {"SCHEMA"}, {"Table"}, {"COLUMN"}, {"Data Type"}, {"Type"}, + {"Column Size"}, {"Nullable value"}, {"IS_NULLABLE"}, {"IS_AUTOINCREMENT"}}; while (rs1.next()) { assertTrue(!StringUtils.isEmpty(rs1.getString("TABLE_CAT")), form2.format(msgArgs2[0])); assertTrue(!StringUtils.isEmpty(rs1.getString("TABLE_SCHEM")), form2.format(msgArgs2[1])); @@ -344,13 +344,14 @@ public void testGetDBColumn() throws SQLException { assertTrue(!StringUtils.isEmpty(rs1.getString("IS_AUTOINCREMENT")), form2.format(msgArgs2[9])); // 22 } } - + /** - * We can improve this test case by following manner: + * We can improve this test case by following manner: *
    - *
  • We can check if PRIVILEGE is in between CRUD / REFERENCES / SELECT / INSERT etc. - *
  • IS_GRANTABLE can have only 2 values YES / NO + *
  • We can check if PRIVILEGE is in between CRUD / REFERENCES / SELECT / INSERT etc. + *
  • IS_GRANTABLE can have only 2 values YES / NO *
+ * * @throws SQLException */ @Test @@ -358,18 +359,19 @@ public void testGetColumnPrivileges() throws SQLException { DatabaseMetaData databaseMetaData = connection.getMetaData(); String[] types = {"TABLE"}; ResultSet rsTables = databaseMetaData.getTables(null, null, "%", types); - - //Fetch one table + + // Fetch one table MessageFormat form1 = new MessageFormat(TestResource.getResource("R_atLeastOneFound")); Object[] msgArgs1 = {"table"}; assertTrue(rsTables.next(), form1.format(msgArgs1)); - - //Go through all columns. + + // Go through all columns. ResultSet rs1 = databaseMetaData.getColumnPrivileges(null, null, rsTables.getString("TABLE_NAME"), "%"); - + MessageFormat form2 = new MessageFormat(TestResource.getResource("R_nameEmpty")); - Object[][] msgArgs2 = {{"Category"}, {"SCHEMA"}, {"Table"}, {"COLUMN"}, {"GRANTOR"}, {"GRANTEE"}, {"PRIVILEGE"}, {"IS_GRANTABLE"}}; - while(rs1.next()) { + Object[][] msgArgs2 = {{"Category"}, {"SCHEMA"}, {"Table"}, {"COLUMN"}, {"GRANTOR"}, {"GRANTEE"}, {"PRIVILEGE"}, + {"IS_GRANTABLE"}}; + while (rs1.next()) { assertTrue(!StringUtils.isEmpty(rs1.getString("TABLE_CAT")), form2.format(msgArgs2[0])); assertTrue(!StringUtils.isEmpty(rs1.getString("TABLE_SCHEM")), form2.format(msgArgs2[1])); assertTrue(!StringUtils.isEmpty(rs1.getString("TABLE_NAME")), form2.format(msgArgs2[2])); @@ -380,36 +382,39 @@ public void testGetColumnPrivileges() throws SQLException { assertTrue(!StringUtils.isEmpty(rs1.getString("IS_GRANTABLE")), form2.format(msgArgs2[7])); } } - + /** - * TODO: Check JDBC Specs: Can we have any tables/functions without category? + * TODO: Check JDBC Specs: Can we have any tables/functions without category? * * Testing {@link SQLServerDatabaseMetaData#getFunctions(String, String, String)} with sending wrong category. + * * @throws SQLException */ @Test public void testGetFunctionsWithWrongParams() throws SQLException { try { - DatabaseMetaData databaseMetaData = connection.getMetaData(); - databaseMetaData.getFunctions("", null, "xp_%"); - assertTrue(false, TestResource.getResource("R_noSchemaShouldFail")); - } catch(Exception ae) { - + DatabaseMetaData databaseMetaData = connection.getMetaData(); + databaseMetaData.getFunctions("", null, "xp_%"); + assertTrue(false, TestResource.getResource("R_noSchemaShouldFail")); + } catch (Exception ae) { + } } - + /** * Test {@link SQLServerDatabaseMetaData#getFunctions(String, String, String)} + * * @throws SQLException */ @Test public void testGetFunctions() throws SQLException { DatabaseMetaData databaseMetaData = connection.getMetaData(); ResultSet rs = databaseMetaData.getFunctions(null, null, "xp_%"); - + MessageFormat form = new MessageFormat(TestResource.getResource("R_nameNull")); - Object[][] msgArgs = {{"FUNCTION_CAT"}, {"FUNCTION_SCHEM"}, {"FUNCTION_NAME"}, {"NUM_INPUT_PARAMS"}, {"NUM_OUPUT_PARAMS"}, {"NUM_RESULT_SETS"}, {"FUNCTION_TYPE"}}; - while(rs.next()) { + Object[][] msgArgs = {{"FUNCTION_CAT"}, {"FUNCTION_SCHEM"}, {"FUNCTION_NAME"}, {"NUM_INPUT_PARAMS"}, + {"NUM_OUPUT_PARAMS"}, {"NUM_RESULT_SETS"}, {"FUNCTION_TYPE"}}; + while (rs.next()) { assertTrue(!StringUtils.isEmpty(rs.getString("FUNCTION_CAT")), form.format(msgArgs[0])); assertTrue(!StringUtils.isEmpty(rs.getString("FUNCTION_SCHEM")), form.format(msgArgs[1])); assertTrue(!StringUtils.isEmpty(rs.getString("FUNCTION_NAME")), form.format(msgArgs[2])); @@ -420,27 +425,29 @@ public void testGetFunctions() throws SQLException { } rs.close(); } - + /** * Te + * * @throws SQLException */ @Test - public void testGetFunctionColumns() throws SQLException{ + public void testGetFunctionColumns() throws SQLException { DatabaseMetaData databaseMetaData = connection.getMetaData(); ResultSet rsFunctions = databaseMetaData.getFunctions(null, null, "%"); - - //Fetch one Function + + // Fetch one Function MessageFormat form1 = new MessageFormat(TestResource.getResource("R_atLeastOneFound")); Object[] msgArgs1 = {"function"}; assertTrue(rsFunctions.next(), form1.format(msgArgs1)); - - //Go through all columns. + + // Go through all columns. ResultSet rs = databaseMetaData.getFunctionColumns(null, null, rsFunctions.getString("FUNCTION_NAME"), "%"); - + MessageFormat form2 = new MessageFormat(TestResource.getResource("R_nameNull")); - Object[][] msgArgs2 = {{"FUNCTION_CAT"}, {"FUNCTION_SCHEM"}, {"FUNCTION_NAME"}, {"COLUMN_NAME"}, {"COLUMN_TYPE"}, {"DATA_TYPE"}, {"TYPE_NAME"}, {"NULLABLE"}, {"IS_NULLABLE"}}; - while(rs.next()) { + Object[][] msgArgs2 = {{"FUNCTION_CAT"}, {"FUNCTION_SCHEM"}, {"FUNCTION_NAME"}, {"COLUMN_NAME"}, + {"COLUMN_TYPE"}, {"DATA_TYPE"}, {"TYPE_NAME"}, {"NULLABLE"}, {"IS_NULLABLE"}}; + while (rs.next()) { assertTrue(!StringUtils.isEmpty(rs.getString("FUNCTION_CAT")), form2.format(msgArgs2[0])); assertTrue(!StringUtils.isEmpty(rs.getString("FUNCTION_SCHEM")), form2.format(msgArgs2[1])); assertTrue(!StringUtils.isEmpty(rs.getString("FUNCTION_NAME")), form2.format(msgArgs2[2])); @@ -448,10 +455,10 @@ public void testGetFunctionColumns() throws SQLException{ assertTrue(!StringUtils.isEmpty(rs.getString("COLUMN_TYPE")), form2.format(msgArgs2[4])); assertTrue(!StringUtils.isEmpty(rs.getString("DATA_TYPE")), form2.format(msgArgs2[5])); assertTrue(!StringUtils.isEmpty(rs.getString("TYPE_NAME")), form2.format(msgArgs2[6])); - assertTrue(!StringUtils.isEmpty(rs.getString("NULLABLE")), form2.format(msgArgs2[7])); //12 - assertTrue(!StringUtils.isEmpty(rs.getString("IS_NULLABLE")), form2.format(msgArgs2[8])); //19 + assertTrue(!StringUtils.isEmpty(rs.getString("NULLABLE")), form2.format(msgArgs2[7])); // 12 + assertTrue(!StringUtils.isEmpty(rs.getString("IS_NULLABLE")), form2.format(msgArgs2[8])); // 19 } - + } - + } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/BulkCopyWithSqlVariantTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/BulkCopyWithSqlVariantTest.java index 2c4a41980..4cd0bcb4b 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/BulkCopyWithSqlVariantTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/BulkCopyWithSqlVariantTest.java @@ -1,717 +1,716 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ -package com.microsoft.sqlserver.jdbc.datatypes; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.io.IOException; -import java.math.BigDecimal; -import java.sql.DriverManager; -import java.sql.SQLException; -import java.sql.Statement; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.platform.runner.JUnitPlatform; -import org.junit.runner.RunWith; - -import com.microsoft.sqlserver.jdbc.SQLServerBulkCopy; -import com.microsoft.sqlserver.jdbc.SQLServerConnection; -import com.microsoft.sqlserver.jdbc.SQLServerResultSet; -import com.microsoft.sqlserver.testframework.AbstractTest; -import com.microsoft.sqlserver.testframework.Utils; - -/** - * Test Bulkcopy with sql_variant datatype, testing all underlying supported datatypes - * - */ -@RunWith(JUnitPlatform.class) -public class BulkCopyWithSqlVariantTest extends AbstractTest { - - static SQLServerConnection con = null; - static Statement stmt = null; - static String tableName = "sqlVariantTestSrcTable"; - static String destTableName = "sqlVariantDestTable"; - static SQLServerResultSet rs = null; - - /** - * Test integer value - * - * @throws SQLException - */ - @Test - public void bulkCopyTestInt() throws SQLException { - int col1Value = 5; - beforeEachSetup("int", col1Value); - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); - - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); - bulkCopy.setDestinationTableName(destTableName); - bulkCopy.writeToServer(rs); - bulkCopy.close(); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); - while (rs.next()) { - assertEquals(rs.getInt(1), 5); - } - } - - /** - * Test smallInt value - * - * @throws SQLException - */ - @Test - public void bulkCopyTestSmallInt() throws SQLException { - int col1Value = 5; - beforeEachSetup("smallint", col1Value); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); - - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); - bulkCopy.setDestinationTableName(destTableName); - bulkCopy.writeToServer(rs); - bulkCopy.close(); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); - while (rs.next()) { - assertEquals(rs.getShort(1), 5); - } - bulkCopy.close(); - } - - /** - * Test tinyInt value - * - * @throws SQLException - */ - @Test - public void bulkCopyTestTinyint() throws SQLException { - int col1Value = 5; - beforeEachSetup("tinyint", col1Value); - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); - - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); - bulkCopy.setDestinationTableName(destTableName); - bulkCopy.writeToServer(rs); - bulkCopy.close(); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); - while (rs.next()) { - assertEquals(rs.getByte(1), 5); - } - bulkCopy.close(); - } - - /** - * test Bigint value - * - * @throws SQLException - */ - @Test - public void bulkCopyTestBigint() throws SQLException { - int col1Value = 5; - beforeEachSetup("bigint", col1Value); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); - - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); - bulkCopy.setDestinationTableName(destTableName); - bulkCopy.writeToServer(rs); - bulkCopy.close(); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); - while (rs.next()) { - assertEquals(rs.getLong(1), col1Value); - } - } - - /** - * test float value - * - * @throws SQLException - */ - @Test - public void bulkCopyTestFloat() throws SQLException { - int col1Value = 5; - beforeEachSetup("float", col1Value); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); - - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); - bulkCopy.setDestinationTableName(destTableName); - bulkCopy.writeToServer(rs); - bulkCopy.close(); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); - while (rs.next()) { - assertEquals(rs.getDouble(1), col1Value); - } - } - - /** - * test real value - * - * @throws SQLException - */ - @Test - public void bulkCopyTestReal() throws SQLException { - int col1Value = 5; - beforeEachSetup("real", col1Value); - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); - - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); - bulkCopy.setDestinationTableName(destTableName); - bulkCopy.writeToServer(rs); - bulkCopy.close(); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); - while (rs.next()) { - assertEquals(rs.getFloat(1), col1Value); - } - - } - - /** - * test money value - * - * @throws SQLException - */ - @Test - public void bulkCopyTestMoney() throws SQLException { - String col1Value = "126.1230"; - beforeEachSetup("money", col1Value); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); - - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); - bulkCopy.setDestinationTableName(destTableName); - bulkCopy.writeToServer(rs); - bulkCopy.close(); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); - while (rs.next()) { - assertEquals(rs.getMoney(1), new BigDecimal(col1Value)); - } - - } - - /** - * test smallmoney - * - * @throws SQLException - */ - @Test - public void bulkCopyTestSmallmoney() throws SQLException { - String col1Value = "126.1230"; - String destTableName = "dest_sqlVariant"; - Utils.dropTableIfExists(tableName, stmt); - Utils.dropTableIfExists(destTableName, stmt); - stmt.executeUpdate("create table " + tableName + " (col1 sql_variant)"); - stmt.executeUpdate("INSERT into " + tableName + "(col1) values (CAST (" + col1Value + " AS " + "smallmoney" + ") )"); - stmt.executeUpdate("create table " + destTableName + " (col1 sql_variant)"); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); - - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); - bulkCopy.setDestinationTableName(destTableName); - bulkCopy.writeToServer(rs); - bulkCopy.close(); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); - while (rs.next()) { - assertEquals(rs.getSmallMoney(1), new BigDecimal(col1Value)); - } - - } - - /** - * test date value - * - * @throws SQLException - */ - @Test - public void bulkCopyTestDate() throws SQLException { - String col1Value = "2015-05-05"; - beforeEachSetup("date", "'" + col1Value + "'"); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); - - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); - bulkCopy.setDestinationTableName(destTableName); - bulkCopy.writeToServer(rs); - bulkCopy.close(); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); - while (rs.next()) { - assertEquals("" + rs.getDate(1), col1Value); - } - - } - - /** - * Test bulkcoping two column with sql_variant datatype - * - * @throws SQLException - */ - @Test - public void bulkCopyTestTwoCols() throws SQLException { - String col1Value = "2015-05-05"; - String col2Value = "126.1230"; - String destTableName = "dest_sqlVariant"; - Utils.dropTableIfExists(tableName, stmt); - Utils.dropTableIfExists(destTableName, stmt); - stmt.executeUpdate("create table " + tableName + " (col1 sql_variant, col2 sql_variant)"); - stmt.executeUpdate("INSERT into " + tableName + "(col1, col2) values (CAST ('" + col1Value + "' AS " + "date" + ")" + ",CAST (" + col2Value - + " AS " + "smallmoney" + ") )"); - stmt.executeUpdate("create table " + destTableName + " (col1 sql_variant, col2 sql_variant)"); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); - - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); - bulkCopy.setDestinationTableName(destTableName); - bulkCopy.writeToServer(rs); - bulkCopy.close(); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); - while (rs.next()) { - assertEquals("" + rs.getDate(1), col1Value); - assertEquals(rs.getSmallMoney(2), new BigDecimal(col2Value)); - } - - } - - /** - * test time with scale value - * - * @throws SQLException - */ - @Test - public void bulkCopyTestTimeWithScale() throws SQLException { - String col1Value = "'12:26:27.1452367'"; - beforeEachSetup("time(2)", col1Value); - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); - - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); - bulkCopy.setDestinationTableName(destTableName); - bulkCopy.writeToServer(rs); - bulkCopy.close(); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); - while (rs.next()) { - assertEquals("" + rs.getString(1), "12:26:27.15"); // getTime does not work - } - - } - - /** - * test char value - * - * @throws SQLException - */ - @Test - public void bulkCopyTestChar() throws SQLException { - String col1Value = "'sample'"; - - beforeEachSetup("char", col1Value); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); - - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); - bulkCopy.setDestinationTableName(destTableName); - bulkCopy.writeToServer(rs); - bulkCopy.close(); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); - while (rs.next()) { - assertEquals("'" + rs.getString(1).trim() + "'", col1Value); // adds space between - } - - } - - /** - * test nchar value - * - * @throws SQLException - */ - @Test - public void bulkCopyTestNchar() throws SQLException { - String col1Value = "'a'"; - - beforeEachSetup("nchar", col1Value); - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); - - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); - bulkCopy.setDestinationTableName(destTableName); - bulkCopy.writeToServer(rs); - bulkCopy.close(); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); - while (rs.next()) { - assertEquals("'" + rs.getNString(1).trim() + "'", col1Value); - } - - } - - /** - * test varchar value - * - * @throws SQLException - */ - @Test - public void bulkCopyTestVarchar() throws SQLException { - String col1Value = "'hello'"; - - beforeEachSetup("varchar", col1Value); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); - - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); - bulkCopy.setDestinationTableName(destTableName); - bulkCopy.writeToServer(rs); - bulkCopy.close(); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); - while (rs.next()) { - assertEquals("'" + rs.getString(1).trim() + "'", col1Value); - } - - } - - /** - * test nvarchar value - * - * @throws SQLException - */ - @Test - public void bulkCopyTestNvarchar() throws SQLException { - String col1Value = "'hello'"; - beforeEachSetup("nvarchar", col1Value); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); - - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); - bulkCopy.setDestinationTableName(destTableName); - bulkCopy.writeToServer(rs); - bulkCopy.close(); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); - while (rs.next()) { - assertEquals("'" + rs.getString(1).trim() + "'", col1Value); - } - - } - - /** - * test Binary value - * - * @throws SQLException - */ - @Test - public void bulkCopyTestBinary20() throws SQLException { - String col1Value = "hello"; - beforeEachSetup("binary(20)", "'" + col1Value + "'"); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); - - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); - bulkCopy.setDestinationTableName(destTableName); - bulkCopy.writeToServer(rs); - bulkCopy.close(); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); - while (rs.next()) { - assertTrue(Utils.parseByte(rs.getBytes(1), col1Value.getBytes())); - } - } - - /** - * test varbinary value - * - * @throws SQLException - */ - @Test - public void bulkCopyTestVarbinary20() throws SQLException { - String col1Value = "hello"; - - beforeEachSetup("varbinary(20)", "'" + col1Value + "'"); - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); - - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); - bulkCopy.setDestinationTableName(destTableName); - bulkCopy.writeToServer(rs); - bulkCopy.close(); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); - while (rs.next()) { - assertTrue(Utils.parseByte(rs.getBytes(1), col1Value.getBytes())); - } - } - - /** - * test varbinary8000 - * - * @throws SQLException - */ - @Test - public void bulkCopyTestVarbinary8000() throws SQLException { - String col1Value = "hello"; - beforeEachSetup("binary(8000)", "'" + col1Value + "'"); - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); - - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); - bulkCopy.setDestinationTableName(destTableName); - bulkCopy.writeToServer(rs); - bulkCopy.close(); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); - while (rs.next()) { - assertTrue(Utils.parseByte(rs.getBytes(1), col1Value.getBytes())); - } - } - - /** - * test null value for underlying bit data type - * - * @throws SQLException - */ - @Test // TODO: check bitnull - public void bulkCopyTestBitNull() throws SQLException { - beforeEachSetup("bit", null); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); - - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); - bulkCopy.setDestinationTableName(destTableName); - bulkCopy.writeToServer(rs); - bulkCopy.close(); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); - while (rs.next()) { - assertEquals(rs.getBoolean(1), false); - } - } - - /** - * test bit value - * - * @throws SQLException - */ - @Test - public void bulkCopyTestBit() throws SQLException { - int col1Value = 5000; - beforeEachSetup("bit", col1Value); - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); - - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); - bulkCopy.setDestinationTableName(destTableName); - bulkCopy.writeToServer(rs); - bulkCopy.close(); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); - while (rs.next()) { - assertEquals(rs.getBoolean(1), true); - } - } - - /** - * test datetime value - * - * @throws SQLException - */ - @Test - public void bulkCopyTestDatetime() throws SQLException { - String col1Value = "2015-05-08 12:26:24.0"; - beforeEachSetup("datetime", "'" + col1Value + "'"); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); - - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); - bulkCopy.setDestinationTableName(destTableName); - bulkCopy.writeToServer(rs); - bulkCopy.close(); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); - while (rs.next()) { - assertEquals("" + rs.getDateTime(1), col1Value); - - } - - } - - /** - * test smalldatetime - * - * @throws SQLException - */ - @Test - public void bulkCopyTestSmalldatetime() throws SQLException { - String col1Value = "2015-05-08 12:26:24"; - beforeEachSetup("smalldatetime", "'" + col1Value + "'"); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); - - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); - bulkCopy.setDestinationTableName(destTableName); - bulkCopy.writeToServer(rs); - bulkCopy.close(); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); - while (rs.next()) { - assertEquals("" + rs.getSmallDateTime(1), "2015-05-08 12:26:00.0"); - } - - } - - /** - * test datetime2 - * - * @throws SQLException - */ - @Test - public void bulkCopyTestDatetime2() throws SQLException { - String col1Value = "2015-05-08 12:26:24.12645"; - beforeEachSetup("datetime2(2)", "'" + col1Value + "'"); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); - - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); - bulkCopy.setDestinationTableName(destTableName); - bulkCopy.writeToServer(rs); - bulkCopy.close(); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); - while (rs.next()) { - assertEquals("" + rs.getTimestamp(1), "2015-05-08 12:26:24.13"); - } - - } - - /** - * test time - * - * @throws SQLException - */ - @Test - public void bulkCopyTestTime() throws SQLException { - String col1Value = "'12:26:27.1452367'"; - String destTableName = "dest_sqlVariant"; - Utils.dropTableIfExists(tableName, stmt); - Utils.dropTableIfExists(destTableName, stmt); - stmt.executeUpdate("create table " + tableName + " (col1 sql_variant)"); - stmt.executeUpdate("INSERT into " + tableName + "(col1) values (CAST (" + col1Value + " AS " + "time(2)" + ") )"); - stmt.executeUpdate("create table " + destTableName + " (col1 sql_variant)"); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); - - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); - bulkCopy.setDestinationTableName(destTableName); - bulkCopy.writeToServer(rs); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); - rs.next(); - assertEquals("" + rs.getObject(1).toString(), "12:26:27"); - } - - /** - * Read GUID stored in SqlVariant - * - * @throws SQLException - */ - @Test - public void bulkCopyTestReadGUID() throws SQLException { - String col1Value = "1AE740A2-2272-4B0F-8086-3DDAC595BC11"; - beforeEachSetup("uniqueidentifier", "'" + col1Value + "'"); - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); - - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); - bulkCopy.setDestinationTableName(destTableName); - bulkCopy.writeToServer(rs); - bulkCopy.close(); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); - while (rs.next()) { - assertEquals("" + rs.getUniqueIdentifier(1), col1Value); - - } - } - - /** - * Read VarChar8000 from SqlVariant - * - * @throws SQLException - */ - @Test - public void bulkCopyTestVarChar8000() throws SQLException { - StringBuffer buffer = new StringBuffer(); - for (int i = 0; i < 8000; i++) { - buffer.append("a"); - } - String col1Value = buffer.toString(); - beforeEachSetup("varchar(8000)", "'" + col1Value + "'"); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); - - SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); - bulkCopy.setDestinationTableName(destTableName); - bulkCopy.writeToServer(rs); - bulkCopy.close(); - - rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); - while (rs.next()) { - assertEquals(rs.getString(1), col1Value); - } - } - - private void beforeEachSetup(String colType, - Object colValue) throws SQLException { - Utils.dropTableIfExists(tableName, stmt); - Utils.dropTableIfExists(destTableName, stmt); - stmt.executeUpdate("create table " + tableName + " (col1 sql_variant)"); - stmt.executeUpdate("INSERT into " + tableName + "(col1) values (CAST (" + colValue + " AS " + colType + ") )"); - stmt.executeUpdate("create table " + destTableName + " (col1 sql_variant)"); - } - - /** - * Prepare test - * - * @throws SQLException - * @throws SecurityException - * @throws IOException - */ - @BeforeAll - public static void setupHere() throws SQLException, SecurityException, IOException { - con = (SQLServerConnection) DriverManager.getConnection(connectionString); - stmt = con.createStatement(); - } - - /** - * drop the tables - * - * @throws SQLException - */ - @AfterAll - public static void afterAll() throws SQLException { - Utils.dropTableIfExists(tableName, stmt); - Utils.dropTableIfExists(destTableName, stmt); - - if (null != stmt) { - stmt.close(); - } - - if (null != rs) { - rs.close(); - } - - if (null != con) { - con.close(); - } - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package com.microsoft.sqlserver.jdbc.datatypes; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.math.BigDecimal; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.Statement; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.platform.runner.JUnitPlatform; +import org.junit.runner.RunWith; + +import com.microsoft.sqlserver.jdbc.SQLServerBulkCopy; +import com.microsoft.sqlserver.jdbc.SQLServerConnection; +import com.microsoft.sqlserver.jdbc.SQLServerResultSet; +import com.microsoft.sqlserver.testframework.AbstractTest; +import com.microsoft.sqlserver.testframework.Utils; + + +/** + * Test Bulkcopy with sql_variant datatype, testing all underlying supported datatypes + * + */ +@RunWith(JUnitPlatform.class) +public class BulkCopyWithSqlVariantTest extends AbstractTest { + + static SQLServerConnection con = null; + static Statement stmt = null; + static String tableName = "sqlVariantTestSrcTable"; + static String destTableName = "sqlVariantDestTable"; + static SQLServerResultSet rs = null; + + /** + * Test integer value + * + * @throws SQLException + */ + @Test + public void bulkCopyTestInt() throws SQLException { + int col1Value = 5; + beforeEachSetup("int", col1Value); + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); + + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); + bulkCopy.setDestinationTableName(destTableName); + bulkCopy.writeToServer(rs); + bulkCopy.close(); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); + while (rs.next()) { + assertEquals(rs.getInt(1), 5); + } + } + + /** + * Test smallInt value + * + * @throws SQLException + */ + @Test + public void bulkCopyTestSmallInt() throws SQLException { + int col1Value = 5; + beforeEachSetup("smallint", col1Value); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); + + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); + bulkCopy.setDestinationTableName(destTableName); + bulkCopy.writeToServer(rs); + bulkCopy.close(); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); + while (rs.next()) { + assertEquals(rs.getShort(1), 5); + } + bulkCopy.close(); + } + + /** + * Test tinyInt value + * + * @throws SQLException + */ + @Test + public void bulkCopyTestTinyint() throws SQLException { + int col1Value = 5; + beforeEachSetup("tinyint", col1Value); + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); + + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); + bulkCopy.setDestinationTableName(destTableName); + bulkCopy.writeToServer(rs); + bulkCopy.close(); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); + while (rs.next()) { + assertEquals(rs.getByte(1), 5); + } + bulkCopy.close(); + } + + /** + * test Bigint value + * + * @throws SQLException + */ + @Test + public void bulkCopyTestBigint() throws SQLException { + int col1Value = 5; + beforeEachSetup("bigint", col1Value); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); + + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); + bulkCopy.setDestinationTableName(destTableName); + bulkCopy.writeToServer(rs); + bulkCopy.close(); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); + while (rs.next()) { + assertEquals(rs.getLong(1), col1Value); + } + } + + /** + * test float value + * + * @throws SQLException + */ + @Test + public void bulkCopyTestFloat() throws SQLException { + int col1Value = 5; + beforeEachSetup("float", col1Value); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); + + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); + bulkCopy.setDestinationTableName(destTableName); + bulkCopy.writeToServer(rs); + bulkCopy.close(); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); + while (rs.next()) { + assertEquals(rs.getDouble(1), col1Value); + } + } + + /** + * test real value + * + * @throws SQLException + */ + @Test + public void bulkCopyTestReal() throws SQLException { + int col1Value = 5; + beforeEachSetup("real", col1Value); + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); + + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); + bulkCopy.setDestinationTableName(destTableName); + bulkCopy.writeToServer(rs); + bulkCopy.close(); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); + while (rs.next()) { + assertEquals(rs.getFloat(1), col1Value); + } + + } + + /** + * test money value + * + * @throws SQLException + */ + @Test + public void bulkCopyTestMoney() throws SQLException { + String col1Value = "126.1230"; + beforeEachSetup("money", col1Value); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); + + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); + bulkCopy.setDestinationTableName(destTableName); + bulkCopy.writeToServer(rs); + bulkCopy.close(); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); + while (rs.next()) { + assertEquals(rs.getMoney(1), new BigDecimal(col1Value)); + } + + } + + /** + * test smallmoney + * + * @throws SQLException + */ + @Test + public void bulkCopyTestSmallmoney() throws SQLException { + String col1Value = "126.1230"; + String destTableName = "dest_sqlVariant"; + Utils.dropTableIfExists(tableName, stmt); + Utils.dropTableIfExists(destTableName, stmt); + stmt.executeUpdate("create table " + tableName + " (col1 sql_variant)"); + stmt.executeUpdate( + "INSERT into " + tableName + "(col1) values (CAST (" + col1Value + " AS " + "smallmoney" + ") )"); + stmt.executeUpdate("create table " + destTableName + " (col1 sql_variant)"); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); + + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); + bulkCopy.setDestinationTableName(destTableName); + bulkCopy.writeToServer(rs); + bulkCopy.close(); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); + while (rs.next()) { + assertEquals(rs.getSmallMoney(1), new BigDecimal(col1Value)); + } + + } + + /** + * test date value + * + * @throws SQLException + */ + @Test + public void bulkCopyTestDate() throws SQLException { + String col1Value = "2015-05-05"; + beforeEachSetup("date", "'" + col1Value + "'"); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); + + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); + bulkCopy.setDestinationTableName(destTableName); + bulkCopy.writeToServer(rs); + bulkCopy.close(); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); + while (rs.next()) { + assertEquals("" + rs.getDate(1), col1Value); + } + + } + + /** + * Test bulkcoping two column with sql_variant datatype + * + * @throws SQLException + */ + @Test + public void bulkCopyTestTwoCols() throws SQLException { + String col1Value = "2015-05-05"; + String col2Value = "126.1230"; + String destTableName = "dest_sqlVariant"; + Utils.dropTableIfExists(tableName, stmt); + Utils.dropTableIfExists(destTableName, stmt); + stmt.executeUpdate("create table " + tableName + " (col1 sql_variant, col2 sql_variant)"); + stmt.executeUpdate("INSERT into " + tableName + "(col1, col2) values (CAST ('" + col1Value + "' AS " + "date" + + ")" + ",CAST (" + col2Value + " AS " + "smallmoney" + ") )"); + stmt.executeUpdate("create table " + destTableName + " (col1 sql_variant, col2 sql_variant)"); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); + + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); + bulkCopy.setDestinationTableName(destTableName); + bulkCopy.writeToServer(rs); + bulkCopy.close(); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); + while (rs.next()) { + assertEquals("" + rs.getDate(1), col1Value); + assertEquals(rs.getSmallMoney(2), new BigDecimal(col2Value)); + } + + } + + /** + * test time with scale value + * + * @throws SQLException + */ + @Test + public void bulkCopyTestTimeWithScale() throws SQLException { + String col1Value = "'12:26:27.1452367'"; + beforeEachSetup("time(2)", col1Value); + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); + + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); + bulkCopy.setDestinationTableName(destTableName); + bulkCopy.writeToServer(rs); + bulkCopy.close(); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); + while (rs.next()) { + assertEquals("" + rs.getString(1), "12:26:27.15"); // getTime does not work + } + + } + + /** + * test char value + * + * @throws SQLException + */ + @Test + public void bulkCopyTestChar() throws SQLException { + String col1Value = "'sample'"; + + beforeEachSetup("char", col1Value); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); + + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); + bulkCopy.setDestinationTableName(destTableName); + bulkCopy.writeToServer(rs); + bulkCopy.close(); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); + while (rs.next()) { + assertEquals("'" + rs.getString(1).trim() + "'", col1Value); // adds space between + } + + } + + /** + * test nchar value + * + * @throws SQLException + */ + @Test + public void bulkCopyTestNchar() throws SQLException { + String col1Value = "'a'"; + + beforeEachSetup("nchar", col1Value); + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); + + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); + bulkCopy.setDestinationTableName(destTableName); + bulkCopy.writeToServer(rs); + bulkCopy.close(); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); + while (rs.next()) { + assertEquals("'" + rs.getNString(1).trim() + "'", col1Value); + } + + } + + /** + * test varchar value + * + * @throws SQLException + */ + @Test + public void bulkCopyTestVarchar() throws SQLException { + String col1Value = "'hello'"; + + beforeEachSetup("varchar", col1Value); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); + + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); + bulkCopy.setDestinationTableName(destTableName); + bulkCopy.writeToServer(rs); + bulkCopy.close(); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); + while (rs.next()) { + assertEquals("'" + rs.getString(1).trim() + "'", col1Value); + } + + } + + /** + * test nvarchar value + * + * @throws SQLException + */ + @Test + public void bulkCopyTestNvarchar() throws SQLException { + String col1Value = "'hello'"; + beforeEachSetup("nvarchar", col1Value); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); + + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); + bulkCopy.setDestinationTableName(destTableName); + bulkCopy.writeToServer(rs); + bulkCopy.close(); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); + while (rs.next()) { + assertEquals("'" + rs.getString(1).trim() + "'", col1Value); + } + + } + + /** + * test Binary value + * + * @throws SQLException + */ + @Test + public void bulkCopyTestBinary20() throws SQLException { + String col1Value = "hello"; + beforeEachSetup("binary(20)", "'" + col1Value + "'"); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); + + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); + bulkCopy.setDestinationTableName(destTableName); + bulkCopy.writeToServer(rs); + bulkCopy.close(); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); + while (rs.next()) { + assertTrue(Utils.parseByte(rs.getBytes(1), col1Value.getBytes())); + } + } + + /** + * test varbinary value + * + * @throws SQLException + */ + @Test + public void bulkCopyTestVarbinary20() throws SQLException { + String col1Value = "hello"; + + beforeEachSetup("varbinary(20)", "'" + col1Value + "'"); + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); + + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); + bulkCopy.setDestinationTableName(destTableName); + bulkCopy.writeToServer(rs); + bulkCopy.close(); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); + while (rs.next()) { + assertTrue(Utils.parseByte(rs.getBytes(1), col1Value.getBytes())); + } + } + + /** + * test varbinary8000 + * + * @throws SQLException + */ + @Test + public void bulkCopyTestVarbinary8000() throws SQLException { + String col1Value = "hello"; + beforeEachSetup("binary(8000)", "'" + col1Value + "'"); + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); + + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); + bulkCopy.setDestinationTableName(destTableName); + bulkCopy.writeToServer(rs); + bulkCopy.close(); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); + while (rs.next()) { + assertTrue(Utils.parseByte(rs.getBytes(1), col1Value.getBytes())); + } + } + + /** + * test null value for underlying bit data type + * + * @throws SQLException + */ + @Test // TODO: check bitnull + public void bulkCopyTestBitNull() throws SQLException { + beforeEachSetup("bit", null); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); + + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); + bulkCopy.setDestinationTableName(destTableName); + bulkCopy.writeToServer(rs); + bulkCopy.close(); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); + while (rs.next()) { + assertEquals(rs.getBoolean(1), false); + } + } + + /** + * test bit value + * + * @throws SQLException + */ + @Test + public void bulkCopyTestBit() throws SQLException { + int col1Value = 5000; + beforeEachSetup("bit", col1Value); + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); + + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); + bulkCopy.setDestinationTableName(destTableName); + bulkCopy.writeToServer(rs); + bulkCopy.close(); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); + while (rs.next()) { + assertEquals(rs.getBoolean(1), true); + } + } + + /** + * test datetime value + * + * @throws SQLException + */ + @Test + public void bulkCopyTestDatetime() throws SQLException { + String col1Value = "2015-05-08 12:26:24.0"; + beforeEachSetup("datetime", "'" + col1Value + "'"); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); + + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); + bulkCopy.setDestinationTableName(destTableName); + bulkCopy.writeToServer(rs); + bulkCopy.close(); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); + while (rs.next()) { + assertEquals("" + rs.getDateTime(1), col1Value); + + } + + } + + /** + * test smalldatetime + * + * @throws SQLException + */ + @Test + public void bulkCopyTestSmalldatetime() throws SQLException { + String col1Value = "2015-05-08 12:26:24"; + beforeEachSetup("smalldatetime", "'" + col1Value + "'"); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); + + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); + bulkCopy.setDestinationTableName(destTableName); + bulkCopy.writeToServer(rs); + bulkCopy.close(); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); + while (rs.next()) { + assertEquals("" + rs.getSmallDateTime(1), "2015-05-08 12:26:00.0"); + } + + } + + /** + * test datetime2 + * + * @throws SQLException + */ + @Test + public void bulkCopyTestDatetime2() throws SQLException { + String col1Value = "2015-05-08 12:26:24.12645"; + beforeEachSetup("datetime2(2)", "'" + col1Value + "'"); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); + + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); + bulkCopy.setDestinationTableName(destTableName); + bulkCopy.writeToServer(rs); + bulkCopy.close(); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); + while (rs.next()) { + assertEquals("" + rs.getTimestamp(1), "2015-05-08 12:26:24.13"); + } + + } + + /** + * test time + * + * @throws SQLException + */ + @Test + public void bulkCopyTestTime() throws SQLException { + String col1Value = "'12:26:27.1452367'"; + String destTableName = "dest_sqlVariant"; + Utils.dropTableIfExists(tableName, stmt); + Utils.dropTableIfExists(destTableName, stmt); + stmt.executeUpdate("create table " + tableName + " (col1 sql_variant)"); + stmt.executeUpdate( + "INSERT into " + tableName + "(col1) values (CAST (" + col1Value + " AS " + "time(2)" + ") )"); + stmt.executeUpdate("create table " + destTableName + " (col1 sql_variant)"); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); + + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); + bulkCopy.setDestinationTableName(destTableName); + bulkCopy.writeToServer(rs); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); + rs.next(); + assertEquals("" + rs.getObject(1).toString(), "12:26:27"); + } + + /** + * Read GUID stored in SqlVariant + * + * @throws SQLException + */ + @Test + public void bulkCopyTestReadGUID() throws SQLException { + String col1Value = "1AE740A2-2272-4B0F-8086-3DDAC595BC11"; + beforeEachSetup("uniqueidentifier", "'" + col1Value + "'"); + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); + + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); + bulkCopy.setDestinationTableName(destTableName); + bulkCopy.writeToServer(rs); + bulkCopy.close(); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); + while (rs.next()) { + assertEquals("" + rs.getUniqueIdentifier(1), col1Value); + + } + } + + /** + * Read VarChar8000 from SqlVariant + * + * @throws SQLException + */ + @Test + public void bulkCopyTestVarChar8000() throws SQLException { + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < 8000; i++) { + buffer.append("a"); + } + String col1Value = buffer.toString(); + beforeEachSetup("varchar(8000)", "'" + col1Value + "'"); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); + + SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con); + bulkCopy.setDestinationTableName(destTableName); + bulkCopy.writeToServer(rs); + bulkCopy.close(); + + rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTableName); + while (rs.next()) { + assertEquals(rs.getString(1), col1Value); + } + } + + private void beforeEachSetup(String colType, Object colValue) throws SQLException { + Utils.dropTableIfExists(tableName, stmt); + Utils.dropTableIfExists(destTableName, stmt); + stmt.executeUpdate("create table " + tableName + " (col1 sql_variant)"); + stmt.executeUpdate("INSERT into " + tableName + "(col1) values (CAST (" + colValue + " AS " + colType + ") )"); + stmt.executeUpdate("create table " + destTableName + " (col1 sql_variant)"); + } + + /** + * Prepare test + * + * @throws SQLException + * @throws SecurityException + * @throws IOException + */ + @BeforeAll + public static void setupHere() throws SQLException, SecurityException, IOException { + con = (SQLServerConnection) DriverManager.getConnection(connectionString); + stmt = con.createStatement(); + } + + /** + * drop the tables + * + * @throws SQLException + */ + @AfterAll + public static void afterAll() throws SQLException { + Utils.dropTableIfExists(tableName, stmt); + Utils.dropTableIfExists(destTableName, stmt); + + if (null != stmt) { + stmt.close(); + } + + if (null != rs) { + rs.close(); + } + + if (null != con) { + con.close(); + } + } +} diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/DateAndTimeTypeTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/DateAndTimeTypeTest.java index 44a7c0b87..86e0b78f8 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/DateAndTimeTypeTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/DateAndTimeTypeTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.datatypes; @@ -34,6 +31,7 @@ import com.microsoft.sqlserver.testframework.DBConnection; import com.microsoft.sqlserver.testframework.Utils; + @RunWith(JUnitPlatform.class) public class DateAndTimeTypeTest extends AbstractTest { @@ -105,7 +103,7 @@ public void testQueryDateTVP() throws SQLException { tvp.addRow(DATE_TO_TEST); String sPrepStmt = "select * from dateandtime where my_date IN (select * from ?)"; pstmt = connection.prepareStatement(sPrepStmt); - ((SQLServerPreparedStatement)pstmt).setStructured(1, "dateTVP", tvp); + ((SQLServerPreparedStatement) pstmt).setStructured(1, "dateTVP", tvp); rs = pstmt.executeQuery(); rs.next(); @@ -124,7 +122,7 @@ public void testQueryTimestampTVP() throws SQLException { tvp.addRow(TIMESTAMP_TO_TEST); String sPrepStmt = "select * from dateandtime where my_timestamp IN (select * from ?)"; pstmt = connection.prepareStatement(sPrepStmt); - ((SQLServerPreparedStatement)pstmt).setStructured(1, "timestampTVP", tvp); + ((SQLServerPreparedStatement) pstmt).setStructured(1, "timestampTVP", tvp); rs = pstmt.executeQuery(); rs.next(); @@ -143,7 +141,7 @@ public void testQueryTimeTVP() throws SQLException { tvp.addRow(TIME_TO_TEST); String sPrepStmt = "select * from dateandtime where my_time IN (select * from ?)"; pstmt = connection.prepareStatement(sPrepStmt); - ((SQLServerPreparedStatement)pstmt).setStructured(1, "timeTVP", tvp); + ((SQLServerPreparedStatement) pstmt).setStructured(1, "timeTVP", tvp); rs = pstmt.executeQuery(); rs.next(); @@ -151,17 +149,18 @@ public void testQueryTimeTVP() throws SQLException { rs.close(); pstmt.close(); } + private void createTVPs(String tvpName, String tvpType) throws SQLException { - stmt.executeUpdate("IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvpName + "') " + " drop type " + tvpName); - String TVPCreateCmd = "CREATE TYPE " + tvpName + " as table (c1 " + tvpType + " null)"; - stmt.executeUpdate(TVPCreateCmd); + stmt.executeUpdate("IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvpName + "') " + + " drop type " + tvpName); + String TVPCreateCmd = "CREATE TYPE " + tvpName + " as table (c1 " + tvpType + " null)"; + stmt.executeUpdate(TVPCreateCmd); } @BeforeEach public void testSetup() throws TestAbortedException, Exception { try (DBConnection dbc = new DBConnection(connectionString)) { - assumeTrue(9 <= dbc.getServerVersion(), - "Aborting test case as SQL Server version does not support TIME"); + assumeTrue(9 <= dbc.getServerVersion(), "Aborting test case as SQL Server version does not support TIME"); } // To get TIME & setTime working on Servers >= 2008, we must add 'sendTimeAsDatetime=false' // by default to the connection. See issue https://github.com/Microsoft/mssql-jdbc/issues/559 @@ -175,9 +174,9 @@ public void testSetup() throws TestAbortedException, Exception { String sPrepStmt = "insert into dateandtime (id, my_date, my_time, my_timestamp) values (?, ?, ?, ?)"; pstmt = connection.prepareStatement(sPrepStmt); pstmt.setInt(1, 42); - pstmt.setDate(2, DATE_TO_TEST); + pstmt.setDate(2, DATE_TO_TEST); pstmt.setTime(3, TIME_TO_TEST); - pstmt.setTimestamp(4, TIMESTAMP_TO_TEST); + pstmt.setTimestamp(4, TIMESTAMP_TO_TEST); pstmt.execute(); pstmt.close(); createTVPs("dateTVP", "date"); @@ -203,4 +202,4 @@ public static void terminateVariation() throws SQLException { rs.close(); } } -} \ No newline at end of file +} diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/SQLServerSpatialDatatypeTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/SQLServerSpatialDatatypeTest.java index bd6945e83..5dc76d12b 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/SQLServerSpatialDatatypeTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/SQLServerSpatialDatatypeTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.datatypes; @@ -41,7 +38,7 @@ * */ @RunWith(JUnitPlatform.class) -public class SQLServerSpatialDatatypeTest extends AbstractTest { +public class SQLServerSpatialDatatypeTest extends AbstractTest { static SQLServerConnection con = null; static Statement stmt = null; @@ -55,8 +52,10 @@ public class SQLServerSpatialDatatypeTest extends AbstractTest { @Test public void testPointWkb() throws SQLException { String geoWKT = "POINT(3 40 5 6)"; - byte[] geomWKB = hexStringToByteArray("00000000010F0000000000000840000000000000444000000000000014400000000000001840"); - byte[] geogWKB = hexStringToByteArray("E6100000010F0000000000004440000000000000084000000000000014400000000000001840"); + byte[] geomWKB = hexStringToByteArray( + "00000000010F0000000000000840000000000000444000000000000014400000000000001840"); + byte[] geogWKB = hexStringToByteArray( + "E6100000010F0000000000004440000000000000084000000000000014400000000000001840"); Geometry geomWKT = Geometry.deserialize(geomWKB); Geography geogWKT = Geography.deserialize(geogWKB); assertEquals(geomWKT.asTextZM(), geoWKT); @@ -66,8 +65,10 @@ public void testPointWkb() throws SQLException { @Test public void testLineStringWkb() throws SQLException { String geoWKT = "LINESTRING(1 0, 0 1, -1 0)"; - byte[] geomWKB = hexStringToByteArray("00000000010403000000000000000000F03F00000000000000000000000000000000000000000000F03F000000000000F0BF000000000000000001000000010000000001000000FFFFFFFF0000000002"); - byte[] geogWKB = hexStringToByteArray("E61000000104030000000000000000000000000000000000F03F000000000000F03F00000000000000000000000000000000000000000000F0BF01000000010000000001000000FFFFFFFF0000000002"); + byte[] geomWKB = hexStringToByteArray( + "00000000010403000000000000000000F03F00000000000000000000000000000000000000000000F03F000000000000F0BF000000000000000001000000010000000001000000FFFFFFFF0000000002"); + byte[] geogWKB = hexStringToByteArray( + "E61000000104030000000000000000000000000000000000F03F000000000000F03F00000000000000000000000000000000000000000000F0BF01000000010000000001000000FFFFFFFF0000000002"); Geometry geomWKT = Geometry.deserialize(geomWKB); Geography geogWKT = Geography.deserialize(geogWKB); assertEquals(geomWKT.asTextZM(), geoWKT); @@ -77,8 +78,10 @@ public void testLineStringWkb() throws SQLException { @Test public void testPolygonWkb() throws SQLException { String geoWKT = "POLYGON((0 0, 0 3, 3 3, 3 0, 0 0), (1 1, 1 2, 2 1, 1 1))"; - byte[] geomWKB = hexStringToByteArray("000000000104090000000000000000000000000000000000000000000000000000000000000000000840000000000000084000000000000008400000000000000840000000000000000000000000000000000000000000000000000000000000F03F000000000000F03F000000000000F03F00000000000000400000000000000040000000000000F03F000000000000F03F000000000000F03F020000000200000000000500000001000000FFFFFFFF0000000003"); - byte[] geogWKB = hexStringToByteArray("E61000000200090000000000000000000000000000000000000000000000000008400000000000000000000000000000084000000000000008400000000000000000000000000000084000000000000000000000000000000000000000000000F03F000000000000F03F0000000000000040000000000000F03F000000000000F03F0000000000000040000000000000F03F000000000000F03F020000000100000000010500000001000000FFFFFFFF0000000003"); + byte[] geomWKB = hexStringToByteArray( + "000000000104090000000000000000000000000000000000000000000000000000000000000000000840000000000000084000000000000008400000000000000840000000000000000000000000000000000000000000000000000000000000F03F000000000000F03F000000000000F03F00000000000000400000000000000040000000000000F03F000000000000F03F000000000000F03F020000000200000000000500000001000000FFFFFFFF0000000003"); + byte[] geogWKB = hexStringToByteArray( + "E61000000200090000000000000000000000000000000000000000000000000008400000000000000000000000000000084000000000000008400000000000000000000000000000084000000000000000000000000000000000000000000000F03F000000000000F03F0000000000000040000000000000F03F000000000000F03F0000000000000040000000000000F03F000000000000F03F020000000100000000010500000001000000FFFFFFFF0000000003"); Geometry geomWKT = Geometry.deserialize(geomWKB); Geography geogWKT = Geography.deserialize(geogWKB); assertEquals(geomWKT.asTextZM(), geoWKT); @@ -88,8 +91,10 @@ public void testPolygonWkb() throws SQLException { @Test public void testMultiPointWkb() throws SQLException { String geoWKT = "MULTIPOINT((2 3), (7 8 9.5))"; - byte[] geomWKB = hexStringToByteArray("00000000010502000000000000000000004000000000000008400000000000001C400000000000002040000000000000F8FF0000000000002340020000000100000000010100000003000000FFFFFFFF0000000004000000000000000001000000000100000001"); - byte[] geogWKB = hexStringToByteArray("E61000000105020000000000000000000840000000000000004000000000000020400000000000001C40000000000000F8FF0000000000002340020000000100000000010100000003000000FFFFFFFF0000000004000000000000000001000000000100000001"); + byte[] geomWKB = hexStringToByteArray( + "00000000010502000000000000000000004000000000000008400000000000001C400000000000002040000000000000F8FF0000000000002340020000000100000000010100000003000000FFFFFFFF0000000004000000000000000001000000000100000001"); + byte[] geogWKB = hexStringToByteArray( + "E61000000105020000000000000000000840000000000000004000000000000020400000000000001C40000000000000F8FF0000000000002340020000000100000000010100000003000000FFFFFFFF0000000004000000000000000001000000000100000001"); Geometry geomWKT = Geometry.deserialize(geomWKB); Geography geogWKT = Geography.deserialize(geogWKB); assertEquals(geomWKT.asTextZM(), geoWKT); @@ -99,8 +104,10 @@ public void testMultiPointWkb() throws SQLException { @Test public void testMultiLineStringWkb() throws SQLException { String geoWKT = "MULTILINESTRING((0 2, 1 1), (1 0, 1 1))"; - byte[] geomWKB = hexStringToByteArray("0000000001040400000000000000000000000000000000000040000000000000F03F000000000000F03F000000000000F03F0000000000000000000000000000F03F000000000000F03F020000000100000000010200000003000000FFFFFFFF0000000005000000000000000002000000000100000002"); - byte[] geogWKB = hexStringToByteArray("E610000001040400000000000000000000400000000000000000000000000000F03F000000000000F03F0000000000000000000000000000F03F000000000000F03F000000000000F03F020000000100000000010200000003000000FFFFFFFF0000000005000000000000000002000000000100000002"); + byte[] geomWKB = hexStringToByteArray( + "0000000001040400000000000000000000000000000000000040000000000000F03F000000000000F03F000000000000F03F0000000000000000000000000000F03F000000000000F03F020000000100000000010200000003000000FFFFFFFF0000000005000000000000000002000000000100000002"); + byte[] geogWKB = hexStringToByteArray( + "E610000001040400000000000000000000400000000000000000000000000000F03F000000000000F03F0000000000000000000000000000F03F000000000000F03F000000000000F03F020000000100000000010200000003000000FFFFFFFF0000000005000000000000000002000000000100000002"); Geometry geomWKT = Geometry.deserialize(geomWKB); Geography geogWKT = Geography.deserialize(geogWKB); assertEquals(geomWKT.asTextZM(), geoWKT); @@ -110,8 +117,10 @@ public void testMultiLineStringWkb() throws SQLException { @Test public void testMultiPolygonWkb() throws SQLException { String geoWKT = "MULTIPOLYGON(((1 1, 1 2, 2 1, 1 1), (0 0, 0 3, 3 3, 3 0, 0 0 7)), ((9 9, 9 10, 10 9, 9 9)))"; - byte[] geomWKB = hexStringToByteArray("0000000001010D000000000000000000F03F000000000000F03F000000000000F03F00000000000000400000000000000040000000000000F03F000000000000F03F000000000000F03F000000000000000000000000000000000000000000000000000000000000084000000000000008400000000000000840000000000000084000000000000000000000000000000000000000000000000000000000000022400000000000002240000000000000224000000000000024400000000000002440000000000000224000000000000022400000000000002240000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF0000000000001C40000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF0300000002000000000004000000020900000003000000FFFFFFFF0000000006000000000000000003000000000200000003"); - byte[] geogWKB = hexStringToByteArray("E610000002010D000000000000000000F03F000000000000F03F0000000000000040000000000000F03F000000000000F03F0000000000000040000000000000F03F000000000000F03F000000000000000000000000000000000000000000000840000000000000000000000000000008400000000000000840000000000000000000000000000008400000000000000000000000000000000000000000000022400000000000002240000000000000244000000000000022400000000000002240000000000000244000000000000022400000000000002240000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF0000000000001C40000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF0300000001000000000104000000010900000003000000FFFFFFFF0000000006000000000000000003000000000200000003"); + byte[] geomWKB = hexStringToByteArray( + "0000000001010D000000000000000000F03F000000000000F03F000000000000F03F00000000000000400000000000000040000000000000F03F000000000000F03F000000000000F03F000000000000000000000000000000000000000000000000000000000000084000000000000008400000000000000840000000000000084000000000000000000000000000000000000000000000000000000000000022400000000000002240000000000000224000000000000024400000000000002440000000000000224000000000000022400000000000002240000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF0000000000001C40000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF0300000002000000000004000000020900000003000000FFFFFFFF0000000006000000000000000003000000000200000003"); + byte[] geogWKB = hexStringToByteArray( + "E610000002010D000000000000000000F03F000000000000F03F0000000000000040000000000000F03F000000000000F03F0000000000000040000000000000F03F000000000000F03F000000000000000000000000000000000000000000000840000000000000000000000000000008400000000000000840000000000000000000000000000008400000000000000000000000000000000000000000000022400000000000002240000000000000244000000000000022400000000000002240000000000000244000000000000022400000000000002240000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF0000000000001C40000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF0300000001000000000104000000010900000003000000FFFFFFFF0000000006000000000000000003000000000200000003"); Geometry geomWKT = Geometry.deserialize(geomWKB); Geography geogWKT = Geography.deserialize(geogWKB); assertEquals(geomWKT.asTextZM(), geoWKT); @@ -121,8 +130,10 @@ public void testMultiPolygonWkb() throws SQLException { @Test public void testGeometryCollectionWkb() throws SQLException { String geoWKT = "GEOMETRYCOLLECTION(POINT(3 3 1), LINESTRING(1 0, 0 1, -1 0), CIRCULARSTRING(1 3, 3 5, 4 7, 7 3, 1 3), POLYGON((0 0 2, 1 10 3, 1 0 4, 0 0 2), (0 0 2, 1 10 3, 1 0 4, 0 0 2), (0 0 2, 1 10 3, 1 0 4, 0 0 2)), MULTIPOINT((2 3), (7 8 9.5)), MULTILINESTRING((0 2, 1 1), (1 0, 1 1)), MULTIPOLYGON(((0 0, 0 3, 3 3, 3 0, 0 0), (1 1, 1 2, 2 1, 1 1)), ((9 9, 9 10, 10 9, 9 9))), COMPOUNDCURVE(CIRCULARSTRING(1 0 3, 0 1 3, 9 6 3, 8 7 3, -1 0 3), CIRCULARSTRING(-1 0 3, 7 9 3, -10 2 3), (-10 2 3, 77 77 77, 88 88 88, 2 6 4), (2 6 4, 3 3 6, 7 7 1)), CURVEPOLYGON((0 0, 0 0, 0 0, 0 0), COMPOUNDCURVE((0 -23.43778, 0 23.43778), CIRCULARSTRING(0 23.43778, -45 -23.43778, 0 -23.43778)), COMPOUNDCURVE((0 -23.43778, 7 7, 0 23.43778), CIRCULARSTRING(0 23.43778, 8 8, 8 8, -45 23.43778, -90 23.43778), (-90 23.43778, -90 -23.43778), CIRCULARSTRING(-90 -23.43778, -45 -23.43778, 0 -23.43778))), POLYGON((0 0 2, 1 10 3, 1 0 4, 0 0 2)))"; - byte[] geomWKB = hexStringToByteArray("0100000002014A00000000000000000008400000000000000840000000000000F03F00000000000000000000000000000000000000000000F03F000000000000F0BF0000000000000000000000000000F03F00000000000008400000000000000840000000000000144000000000000010400000000000001C400000000000001C400000000000000840000000000000F03F000000000000084000000000000000000000000000000000000000000000F03F0000000000002440000000000000F03F00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F03F0000000000002440000000000000F03F00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F03F0000000000002440000000000000F03F000000000000000000000000000000000000000000000000000000000000004000000000000008400000000000001C40000000000000204000000000000000000000000000000040000000000000F03F000000000000F03F000000000000F03F0000000000000000000000000000F03F000000000000F03F0000000000000000000000000000000000000000000000000000000000000840000000000000084000000000000008400000000000000840000000000000000000000000000000000000000000000000000000000000F03F000000000000F03F000000000000F03F00000000000000400000000000000040000000000000F03F000000000000F03F000000000000F03F00000000000022400000000000002240000000000000224000000000000024400000000000002440000000000000224000000000000022400000000000002240000000000000F03F00000000000000000000000000000000000000000000F03F0000000000002240000000000000184000000000000020400000000000001C40000000000000F0BF00000000000000000000000000001C40000000000000224000000000000024C00000000000000040000000000040534000000000004053400000000000005640000000000000564000000000000000400000000000001840000000000000084000000000000008400000000000001C400000000000001C40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C7D79E59127037C00000000000000000C7D79E591270374000000000008046C0C7D79E59127037C00000000000000000C7D79E59127037C00000000000000000C7D79E59127037C00000000000001C400000000000001C400000000000000000C7D79E5912703740000000000000204000000000000020400000000000002040000000000000204000000000008046C0C7D79E591270374000000000008056C0C7D79E591270374000000000008056C0C7D79E59127037C000000000008046C0C7D79E59127037C00000000000000000C7D79E59127037C000000000000000000000000000000000000000000000F03F0000000000002440000000000000F03F000000000000000000000000000000000000000000000000000000000000F03F000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000004000000000000008400000000000001040000000000000004000000000000000400000000000000840000000000000104000000000000000400000000000000040000000000000084000000000000010400000000000000040000000000000F8FF0000000000002340000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF00000000000008400000000000000840000000000000084000000000000008400000000000000840000000000000084000000000000008400000000000405340000000000000564000000000000010400000000000001840000000000000F03F000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF0000000000000040000000000000084000000000000010400000000000000040120000000100000000010100000002040000000109000000010D00000001110000000115000000011600000001170000000119000000011B00000001200000000124000000032800000001340000000338000000033C000000014600000011000000FFFFFFFF0000000007000000000000000001000000000100000002000000000200000008000000000300000003000000000600000004050000000600000001050000000700000001000000000800000005080000000800000002080000000900000002000000000A000000060B0000000A000000030B0000000C00000003000000000D00000009000000000E0000000A0000000011000000031000000003010302000002000203020003010203"); - byte[] geogWKB = hexStringToByteArray("E610000002214A000000000000000000084000000000000008400000000000000000000000000000F03F000000000000F03F00000000000000000000000000000000000000000000F0BF0000000000000840000000000000F03F000000000000144000000000000008400000000000001C40000000000000104000000000000008400000000000001C400000000000000840000000000000F03F000000000000000000000000000000000000000000002440000000000000F03F0000000000000000000000000000F03F00000000000000000000000000000000000000000000000000000000000000000000000000002440000000000000F03F0000000000000000000000000000F03F00000000000000000000000000000000000000000000000000000000000000000000000000002440000000000000F03F0000000000000000000000000000F03F000000000000000000000000000000000000000000000840000000000000004000000000000020400000000000001C4000000000000000400000000000000000000000000000F03F000000000000F03F0000000000000000000000000000F03F000000000000F03F000000000000F03F0000000000000000000000000000000000000000000008400000000000000000000000000000084000000000000008400000000000000000000000000000084000000000000000000000000000000000000000000000F03F000000000000F03F0000000000000040000000000000F03F000000000000F03F0000000000000040000000000000F03F000000000000F03F000000000000224000000000000022400000000000002440000000000000224000000000000022400000000000002440000000000000224000000000000022400000000000000000000000000000F03F000000000000F03F0000000000000000000000000000184000000000000022400000000000001C4000000000000020400000000000000000000000000000F0BF00000000000022400000000000001C40000000000000004000000000000024C0000000000040534000000000004053400000000000005640000000000000564000000000000018400000000000000040000000000000084000000000000008400000000000001C400000000000001C4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C7D79E59127037C00000000000000000C7D79E59127037400000000000000000C7D79E59127037C000000000008046C0C7D79E59127037C00000000000000000C7D79E59127037C000000000000000000000000000001C400000000000001C40C7D79E591270374000000000000000000000000000002040000000000000204000000000000020400000000000002040C7D79E591270374000000000008046C0C7D79E591270374000000000008056C0C7D79E59127037C000000000008056C0C7D79E59127037C000000000008046C0C7D79E59127037C00000000000000000000000000000000000000000000000000000000000002440000000000000F03F0000000000000000000000000000F03F00000000000000000000000000000000000000000000F03F000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000004000000000000008400000000000001040000000000000004000000000000000400000000000000840000000000000104000000000000000400000000000000040000000000000084000000000000010400000000000000040000000000000F8FF0000000000002340000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF00000000000008400000000000000840000000000000084000000000000008400000000000000840000000000000084000000000000008400000000000405340000000000000564000000000000010400000000000001840000000000000F03F000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF0000000000000040000000000000084000000000000010400000000000000040120000000100000000010100000002040000000109000000010D00000001110000000115000000011600000001170000000119000000011B00000001200000000124000000032800000001340000000338000000033C000000014600000011000000FFFFFFFF0000000007000000000000000001000000000100000002000000000200000008000000000300000003000000000600000004050000000600000001050000000700000001000000000800000005080000000800000002080000000900000002000000000A000000060B0000000A000000030B0000000C00000003000000000D00000009000000000E0000000A0000000011000000031000000003010302000002000203020003010203"); + byte[] geomWKB = hexStringToByteArray( + "0100000002014A00000000000000000008400000000000000840000000000000F03F00000000000000000000000000000000000000000000F03F000000000000F0BF0000000000000000000000000000F03F00000000000008400000000000000840000000000000144000000000000010400000000000001C400000000000001C400000000000000840000000000000F03F000000000000084000000000000000000000000000000000000000000000F03F0000000000002440000000000000F03F00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F03F0000000000002440000000000000F03F00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F03F0000000000002440000000000000F03F000000000000000000000000000000000000000000000000000000000000004000000000000008400000000000001C40000000000000204000000000000000000000000000000040000000000000F03F000000000000F03F000000000000F03F0000000000000000000000000000F03F000000000000F03F0000000000000000000000000000000000000000000000000000000000000840000000000000084000000000000008400000000000000840000000000000000000000000000000000000000000000000000000000000F03F000000000000F03F000000000000F03F00000000000000400000000000000040000000000000F03F000000000000F03F000000000000F03F00000000000022400000000000002240000000000000224000000000000024400000000000002440000000000000224000000000000022400000000000002240000000000000F03F00000000000000000000000000000000000000000000F03F0000000000002240000000000000184000000000000020400000000000001C40000000000000F0BF00000000000000000000000000001C40000000000000224000000000000024C00000000000000040000000000040534000000000004053400000000000005640000000000000564000000000000000400000000000001840000000000000084000000000000008400000000000001C400000000000001C40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C7D79E59127037C00000000000000000C7D79E591270374000000000008046C0C7D79E59127037C00000000000000000C7D79E59127037C00000000000000000C7D79E59127037C00000000000001C400000000000001C400000000000000000C7D79E5912703740000000000000204000000000000020400000000000002040000000000000204000000000008046C0C7D79E591270374000000000008056C0C7D79E591270374000000000008056C0C7D79E59127037C000000000008046C0C7D79E59127037C00000000000000000C7D79E59127037C000000000000000000000000000000000000000000000F03F0000000000002440000000000000F03F000000000000000000000000000000000000000000000000000000000000F03F000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000004000000000000008400000000000001040000000000000004000000000000000400000000000000840000000000000104000000000000000400000000000000040000000000000084000000000000010400000000000000040000000000000F8FF0000000000002340000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF00000000000008400000000000000840000000000000084000000000000008400000000000000840000000000000084000000000000008400000000000405340000000000000564000000000000010400000000000001840000000000000F03F000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF0000000000000040000000000000084000000000000010400000000000000040120000000100000000010100000002040000000109000000010D00000001110000000115000000011600000001170000000119000000011B00000001200000000124000000032800000001340000000338000000033C000000014600000011000000FFFFFFFF0000000007000000000000000001000000000100000002000000000200000008000000000300000003000000000600000004050000000600000001050000000700000001000000000800000005080000000800000002080000000900000002000000000A000000060B0000000A000000030B0000000C00000003000000000D00000009000000000E0000000A0000000011000000031000000003010302000002000203020003010203"); + byte[] geogWKB = hexStringToByteArray( + "E610000002214A000000000000000000084000000000000008400000000000000000000000000000F03F000000000000F03F00000000000000000000000000000000000000000000F0BF0000000000000840000000000000F03F000000000000144000000000000008400000000000001C40000000000000104000000000000008400000000000001C400000000000000840000000000000F03F000000000000000000000000000000000000000000002440000000000000F03F0000000000000000000000000000F03F00000000000000000000000000000000000000000000000000000000000000000000000000002440000000000000F03F0000000000000000000000000000F03F00000000000000000000000000000000000000000000000000000000000000000000000000002440000000000000F03F0000000000000000000000000000F03F000000000000000000000000000000000000000000000840000000000000004000000000000020400000000000001C4000000000000000400000000000000000000000000000F03F000000000000F03F0000000000000000000000000000F03F000000000000F03F000000000000F03F0000000000000000000000000000000000000000000008400000000000000000000000000000084000000000000008400000000000000000000000000000084000000000000000000000000000000000000000000000F03F000000000000F03F0000000000000040000000000000F03F000000000000F03F0000000000000040000000000000F03F000000000000F03F000000000000224000000000000022400000000000002440000000000000224000000000000022400000000000002440000000000000224000000000000022400000000000000000000000000000F03F000000000000F03F0000000000000000000000000000184000000000000022400000000000001C4000000000000020400000000000000000000000000000F0BF00000000000022400000000000001C40000000000000004000000000000024C0000000000040534000000000004053400000000000005640000000000000564000000000000018400000000000000040000000000000084000000000000008400000000000001C400000000000001C4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000C7D79E59127037C00000000000000000C7D79E59127037400000000000000000C7D79E59127037C000000000008046C0C7D79E59127037C00000000000000000C7D79E59127037C000000000000000000000000000001C400000000000001C40C7D79E591270374000000000000000000000000000002040000000000000204000000000000020400000000000002040C7D79E591270374000000000008046C0C7D79E591270374000000000008056C0C7D79E59127037C000000000008056C0C7D79E59127037C000000000008046C0C7D79E59127037C00000000000000000000000000000000000000000000000000000000000002440000000000000F03F0000000000000000000000000000F03F00000000000000000000000000000000000000000000F03F000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000004000000000000008400000000000001040000000000000004000000000000000400000000000000840000000000000104000000000000000400000000000000040000000000000084000000000000010400000000000000040000000000000F8FF0000000000002340000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF00000000000008400000000000000840000000000000084000000000000008400000000000000840000000000000084000000000000008400000000000405340000000000000564000000000000010400000000000001840000000000000F03F000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF0000000000000040000000000000084000000000000010400000000000000040120000000100000000010100000002040000000109000000010D00000001110000000115000000011600000001170000000119000000011B00000001200000000124000000032800000001340000000338000000033C000000014600000011000000FFFFFFFF0000000007000000000000000001000000000100000002000000000200000008000000000300000003000000000600000004050000000600000001050000000700000001000000000800000005080000000800000002080000000900000002000000000A000000060B0000000A000000030B0000000C00000003000000000D00000009000000000E0000000A0000000011000000031000000003010302000002000203020003010203"); Geometry geomWKT = Geometry.deserialize(geomWKB); Geography geogWKT = Geography.deserialize(geogWKB); assertEquals(geomWKT.asTextZM(), geoWKT); @@ -132,8 +143,10 @@ public void testGeometryCollectionWkb() throws SQLException { @Test public void testCircularStringWkb() throws SQLException { String geoWKT = "CIRCULARSTRING(2 1 3 4, 1 2 3, 0 7 3, 1 0 3, 2 1 3)"; - byte[] geomWKB = hexStringToByteArray("000000000207050000000000000000000040000000000000F03F000000000000F03F000000000000004000000000000000000000000000001C40000000000000F03F00000000000000000000000000000040000000000000F03F000000000000084000000000000008400000000000000840000000000000084000000000000008400000000000001040000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF01000000020000000001000000FFFFFFFF0000000008"); - byte[] geogWKB = hexStringToByteArray("E6100000020705000000000000000000F03F00000000000000400000000000000040000000000000F03F0000000000001C4000000000000000000000000000000000000000000000F03F000000000000F03F0000000000000040000000000000084000000000000008400000000000000840000000000000084000000000000008400000000000001040000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF01000000020000000001000000FFFFFFFF0000000008"); + byte[] geomWKB = hexStringToByteArray( + "000000000207050000000000000000000040000000000000F03F000000000000F03F000000000000004000000000000000000000000000001C40000000000000F03F00000000000000000000000000000040000000000000F03F000000000000084000000000000008400000000000000840000000000000084000000000000008400000000000001040000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF01000000020000000001000000FFFFFFFF0000000008"); + byte[] geogWKB = hexStringToByteArray( + "E6100000020705000000000000000000F03F00000000000000400000000000000040000000000000F03F0000000000001C4000000000000000000000000000000000000000000000F03F000000000000F03F0000000000000040000000000000084000000000000008400000000000000840000000000000084000000000000008400000000000001040000000000000F8FF000000000000F8FF000000000000F8FF000000000000F8FF01000000020000000001000000FFFFFFFF0000000008"); Geometry geomWKT = Geometry.deserialize(geomWKB); Geography geogWKT = Geography.deserialize(geogWKB); assertEquals(geomWKT.asTextZM(), geoWKT); @@ -143,25 +156,29 @@ public void testCircularStringWkb() throws SQLException { @Test public void testCompoundCurveWkb() throws SQLException { String geoWKT = "COMPOUNDCURVE(CIRCULARSTRING(1 0 3, 0 1 3, 9 6 3, 8 7 3, -1 0 3), CIRCULARSTRING(-1 0 3, 7 9 3, -10 2 3), (-10 2 3, 77 77 77, 88 88 88, 2 6 4), (2 6 4, 3 3 6, 7 7 1))"; - byte[] geomWKB = hexStringToByteArray("0000000002050C000000000000000000F03F00000000000000000000000000000000000000000000F03F0000000000002240000000000000184000000000000020400000000000001C40000000000000F0BF00000000000000000000000000001C40000000000000224000000000000024C00000000000000040000000000040534000000000004053400000000000005640000000000000564000000000000000400000000000001840000000000000084000000000000008400000000000001C400000000000001C4000000000000008400000000000000840000000000000084000000000000008400000000000000840000000000000084000000000000008400000000000405340000000000000564000000000000010400000000000001840000000000000F03F01000000030000000001000000FFFFFFFF0000000009080000000301030200000200"); - byte[] geogWKB = hexStringToByteArray("E610000002050C0000000000000000000000000000000000F03F000000000000F03F0000000000000000000000000000184000000000000022400000000000001C4000000000000020400000000000000000000000000000F0BF00000000000022400000000000001C40000000000000004000000000000024C0000000000040534000000000004053400000000000005640000000000000564000000000000018400000000000000040000000000000084000000000000008400000000000001C400000000000001C4000000000000008400000000000000840000000000000084000000000000008400000000000000840000000000000084000000000000008400000000000405340000000000000564000000000000010400000000000001840000000000000F03F01000000030000000001000000FFFFFFFF0000000009080000000301030200000200"); + byte[] geomWKB = hexStringToByteArray( + "0000000002050C000000000000000000F03F00000000000000000000000000000000000000000000F03F0000000000002240000000000000184000000000000020400000000000001C40000000000000F0BF00000000000000000000000000001C40000000000000224000000000000024C00000000000000040000000000040534000000000004053400000000000005640000000000000564000000000000000400000000000001840000000000000084000000000000008400000000000001C400000000000001C4000000000000008400000000000000840000000000000084000000000000008400000000000000840000000000000084000000000000008400000000000405340000000000000564000000000000010400000000000001840000000000000F03F01000000030000000001000000FFFFFFFF0000000009080000000301030200000200"); + byte[] geogWKB = hexStringToByteArray( + "E610000002050C0000000000000000000000000000000000F03F000000000000F03F0000000000000000000000000000184000000000000022400000000000001C4000000000000020400000000000000000000000000000F0BF00000000000022400000000000001C40000000000000004000000000000024C0000000000040534000000000004053400000000000005640000000000000564000000000000018400000000000000040000000000000084000000000000008400000000000001C400000000000001C4000000000000008400000000000000840000000000000084000000000000008400000000000000840000000000000084000000000000008400000000000405340000000000000564000000000000010400000000000001840000000000000F03F01000000030000000001000000FFFFFFFF0000000009080000000301030200000200"); Geometry geomWKT = Geometry.deserialize(geomWKB); Geography geogWKT = Geography.deserialize(geogWKB); assertEquals(geomWKT.asTextZM(), geoWKT); assertEquals(geogWKT.asTextZM(), geoWKT); } - + @Test public void testCurvePolygonWkb() throws SQLException { String geoWKT = "CURVEPOLYGON((0 0, 0 0, 0 0, 0 0), CIRCULARSTRING(1 3, 3 5, 4 7, 7 3, 1 3), COMPOUNDCURVE((0 -23.43778, 0 23.43778), CIRCULARSTRING(0 23.43778, -45 -23.43778, 0 -23.43778)), COMPOUNDCURVE((0 -23.43778, 7 7, 0 23.43778), CIRCULARSTRING(0 23.43778, 8 8, 8 8, -45 23.43778, -90 23.43778), (-90 23.43778, -90 -23.43778), CIRCULARSTRING(-90 -23.43778, -45 -23.43778, 0 -23.43778)))"; - byte[] geomWKB = hexStringToByteArray("0A00000002001700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F03F00000000000008400000000000000840000000000000144000000000000010400000000000001C400000000000001C400000000000000840000000000000F03F00000000000008400000000000000000C7D79E59127037C00000000000000000C7D79E591270374000000000008046C0C7D79E59127037C00000000000000000C7D79E59127037C00000000000000000C7D79E59127037C00000000000001C400000000000001C400000000000000000C7D79E5912703740000000000000204000000000000020400000000000002040000000000000204000000000008046C0C7D79E591270374000000000008056C0C7D79E591270374000000000008056C0C7D79E59127037C000000000008046C0C7D79E59127037C00000000000000000C7D79E59127037C004000000010000000002040000000309000000030D00000001000000FFFFFFFF000000000A080000000203020003010203"); - byte[] geogWKB = hexStringToByteArray("E6100000020017000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000840000000000000F03F000000000000144000000000000008400000000000001C40000000000000104000000000000008400000000000001C400000000000000840000000000000F03FC7D79E59127037C00000000000000000C7D79E59127037400000000000000000C7D79E59127037C000000000008046C0C7D79E59127037C00000000000000000C7D79E59127037C000000000000000000000000000001C400000000000001C40C7D79E591270374000000000000000000000000000002040000000000000204000000000000020400000000000002040C7D79E591270374000000000008046C0C7D79E591270374000000000008056C0C7D79E59127037C000000000008056C0C7D79E59127037C000000000008046C0C7D79E59127037C0000000000000000004000000010000000002040000000309000000030D00000001000000FFFFFFFF000000000A080000000203020003010203"); + byte[] geomWKB = hexStringToByteArray( + "0A00000002001700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000F03F00000000000008400000000000000840000000000000144000000000000010400000000000001C400000000000001C400000000000000840000000000000F03F00000000000008400000000000000000C7D79E59127037C00000000000000000C7D79E591270374000000000008046C0C7D79E59127037C00000000000000000C7D79E59127037C00000000000000000C7D79E59127037C00000000000001C400000000000001C400000000000000000C7D79E5912703740000000000000204000000000000020400000000000002040000000000000204000000000008046C0C7D79E591270374000000000008056C0C7D79E591270374000000000008056C0C7D79E59127037C000000000008046C0C7D79E59127037C00000000000000000C7D79E59127037C004000000010000000002040000000309000000030D00000001000000FFFFFFFF000000000A080000000203020003010203"); + byte[] geogWKB = hexStringToByteArray( + "E6100000020017000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000840000000000000F03F000000000000144000000000000008400000000000001C40000000000000104000000000000008400000000000001C400000000000000840000000000000F03FC7D79E59127037C00000000000000000C7D79E59127037400000000000000000C7D79E59127037C000000000008046C0C7D79E59127037C00000000000000000C7D79E59127037C000000000000000000000000000001C400000000000001C40C7D79E591270374000000000000000000000000000002040000000000000204000000000000020400000000000002040C7D79E591270374000000000008046C0C7D79E591270374000000000008056C0C7D79E59127037C000000000008056C0C7D79E59127037C000000000008046C0C7D79E59127037C0000000000000000004000000010000000002040000000309000000030D00000001000000FFFFFFFF000000000A080000000203020003010203"); Geometry geomWKT = Geometry.deserialize(geomWKB); Geography geogWKT = Geography.deserialize(geogWKB); assertEquals(geomWKT.asTextZM(), geoWKT); assertEquals(geogWKT.asTextZM(), geoWKT); } - + @Test public void testFullGlobeWkb() throws SQLException { String geoWKT = "FULLGLOBE"; @@ -272,7 +289,7 @@ public void testCompoundCurveWkt() throws SQLException { testWkt(geoWKT); } } - + @Test public void testCurvePolygonWkt() throws SQLException { if (isDenaliOrLater) { @@ -284,170 +301,164 @@ public void testCurvePolygonWkt() throws SQLException { testWkt(geoWKT); } } - + @Test public void testFullGlobeWkt() throws SQLException { if (isDenaliOrLater) { beforeEachSetup(); - + String geoWKT = "FULLGLOBE"; Geography geogWKT = Geography.STGeomFromText(geoWKT, 4326); try { Geometry.STGeomFromText(geoWKT, 0); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { assertEquals(e.getMessage(), "Fullglobe is not supported for Geometry."); } - - pstmt = (SQLServerPreparedStatement) con.prepareStatement("insert into "+ geogTableName + " values (?)"); - pstmt.setGeography(1, geogWKT); - pstmt.execute(); - - rs = (SQLServerResultSet) stmt.executeQuery("select c1 from " + geogTableName); - rs.next(); - assertEquals(rs.getGeography(1).asTextZM(), geoWKT); + + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con + .prepareStatement("insert into " + geogTableName + " values (?)");) { + pstmt.setGeography(1, geogWKT); + pstmt.execute(); + + rs = (SQLServerResultSet) stmt.executeQuery("select c1 from " + geogTableName); + rs.next(); + assertEquals(rs.getGeography(1).asTextZM(), geoWKT); + } } } - + @Test public void testIrregularCases() throws SQLException { beforeEachSetup(); - + String geoWKT = " GeOMETRyCOLlECTION(POINT( 3e2 2E1 1 ), GEOMETRYCOLLECTION EmPTy , GeometryCollection(GEometryCOLLEction(GEometryCOLLEction Empty)), " + "POLYGON( (0 0 2, 1 10 3, 1 0 4, 0 0 2)) )"; String geoWKTSS = "GEOMETRYCOLLECTION(POINT(300 20 1), GEOMETRYCOLLECTION EMPTY, GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(GEOMETRYCOLLECTION EMPTY)), POLYGON((0 0 2, 1 10 3, 1 0 4, 0 0 2)))"; - + testWkt(geoWKT, geoWKTSS); } - + @Test public void testIllegalCases() throws SQLException { - //Not enough closing bracket case + // Not enough closing bracket case String geoWKT = "MULTIPOLYGON(((1 1, 1 2, 2 1, 1 1), (0 0, 0 3, 3 3, 3 0, 0 0 7)), ((9 9, 9 10, 10 9, 9 9))"; - + try { testWkt(geoWKT); + } catch (SQLServerException e) { + MessageFormat form = new MessageFormat(TestResource.getResource("R_illegalCharWktPosition")); + Object[] msgArgs1 = {"90"}; + assertEquals(e.getMessage(), form.format(msgArgs1)); } - catch (SQLServerException e) { - assertEquals(e.getMessage(), TestResource.getResource("R_illegalCharWkt")); - } - - //Not enough closing and opening bracket case + + // Not enough closing and opening bracket case geoWKT = "MULTIPOLYGON((1 1, 1 2, 2 1, 1 1), (0 0, 0 3, 3 3, 3 0, 0 0 7)), ((9 9, 9 10, 10 9, 9 9))"; - + try { testWkt(geoWKT); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { MessageFormat form = new MessageFormat(TestResource.getResource("R_illegalCharWktPosition")); Object[] msgArgs1 = {"14"}; assertEquals(e.getMessage(), form.format(msgArgs1)); } - - //Too many closing bracket + + // Too many closing bracket geoWKT = "MULTIPOLYGON(((1 1, 1 2, 2 1, 1 1), (0 0, 0 3, 3 3, 3 0, 0 0 7)), ((9 9, 9 10, 10 9, 9 9))))"; - + try { testWkt(geoWKT); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { MessageFormat form = new MessageFormat(TestResource.getResource("R_illegalCharWktPosition")); Object[] msgArgs1 = {"91"}; assertEquals(e.getMessage(), form.format(msgArgs1)); } - - //Too many opening bracket + + // Too many opening bracket geoWKT = "MULTIPOLYGON((((1 1, 1 2, 2 1, 1 1), (0 0, 0 3, 3 3, 3 0, 0 0 7)), ((9 9, 9 10, 10 9, 9 9)))"; - + try { testWkt(geoWKT); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { MessageFormat form = new MessageFormat(TestResource.getResource("R_illegalCharWktPosition")); Object[] msgArgs1 = {"15"}; assertEquals(e.getMessage(), form.format(msgArgs1)); } - - //Too many coordinates + + // Too many coordinates geoWKT = "MULTIPOLYGON(((1 1 3 4 5, 1 2, 2 1, 1 1), (0 0, 0 3, 3 3, 3 0, 0 0 7)), ((9 9, 9 10, 10 9, 9 9)))"; - + try { testWkt(geoWKT); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { MessageFormat form = new MessageFormat(TestResource.getResource("R_illegalCharWktPosition")); Object[] msgArgs1 = {"23"}; assertEquals(e.getMessage(), form.format(msgArgs1)); } - - //Too little coordinates + + // Too little coordinates geoWKT = "MULTIPOLYGON(((1 , 1 2, 2 1, 1 1), (0 0, 0 3, 3 3, 3 0, 0 0 7)), ((9 9, 9 10, 10 9, 9 9)))"; - + try { testWkt(geoWKT); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { MessageFormat form = new MessageFormat(TestResource.getResource("R_illegalCharWktPosition")); Object[] msgArgs1 = {"17"}; assertEquals(e.getMessage(), form.format(msgArgs1)); } - - //Incorrect data type + + // Incorrect data type geoWKT = "IvnalidPolygon(((1 , 1 2, 2 1, 1 1), (0 0, 0 3, 3 3, 3 0, 0 0 7)), ((9 9, 9 10, 10 9, 9 9)))"; - + try { testWkt(geoWKT); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { MessageFormat form = new MessageFormat(TestResource.getResource("R_illegalCharWktPosition")); Object[] msgArgs1 = {"14"}; assertEquals(e.getMessage(), form.format(msgArgs1)); } - + // too many commas geoWKT = "MULTIPOLYGON(((1 1, 1 2, 2 1, 1 1),, (0 0, 0 3, 3 3, 3 0, 0 0 7)), ((9 9, 9 10, 10 9, 9 9)))"; try { testWkt(geoWKT); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { MessageFormat form = new MessageFormat(TestResource.getResource("R_illegalCharWktPosition")); Object[] msgArgs1 = {"35"}; assertEquals(e.getMessage(), form.format(msgArgs1)); } - + // too little commas geoWKT = "MULTIPOLYGON(((1 1, 1 2, 2 1, 1 1) (0 0, 0 3, 3 3, 3 0, 0 0 7)), ((9 9, 9 10, 10 9, 9 9)))"; - + try { testWkt(geoWKT); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { MessageFormat form = new MessageFormat(TestResource.getResource("R_illegalCharWktPosition")); Object[] msgArgs1 = {"35"}; assertEquals(e.getMessage(), form.format(msgArgs1)); } } - + @Test public void testAllTypes() throws SQLException { if (isDenaliOrLater) { beforeEachSetup(); - + String geoWKTPoint = "POINT(30 12.12312312 5 6)"; - String geoWKTLineString = "LINESTRING(1 1, 2 4 3, 3 9 123 332)"; + String geoWKTLineString = "LINESTRING(1 1 0 0, 2 4 3 0, 3 9 123 332)"; String geoWKTCircularString = "CIRCULARSTRING(1 1, 2 4, 3 9)"; String geoWKTCompoundCurve = "COMPOUNDCURVE((1 1, 1 3), (1 3, 3 3), (3 3, 3 1), (3 1, 1 1))"; String geoWKTCurvePolygon = "CURVEPOLYGON(CIRCULARSTRING(2 4, 4 2, 6 4, 4 6, 2 4))"; String geoWKTPolygon = "POLYGON((0 0, 0 3, 3 3, 3 0, 0 0), (1 1, 1 2, 2 1, 1 1))"; - String geoWKTMultiPoint = "MULTIPOINT((2 3), (7 8 9.5))"; + String geoWKTMultiPoint = "MULTIPOINT((2 3), (7 8 9.5 4))"; String geoWKTMultiLineString = "MULTILINESTRING((0 2, 1 1), (1 0, 1 1))"; String geoWKTMultiPolygon = "MULTIPOLYGON(((0 0, 0 3, 3 3, 3 0, 0 0), (1 1, 1 2, 2 1, 1 1)), ((9 9, 9 10, 10 9, 9 9)))"; String geoWKTGeometryCollection = "GEOMETRYCOLLECTION(POLYGON((0 0 2, 1 10 3, 1 0 4, 0 0 2)), POINT(3 3 1 2.5), LINESTRING(1 0, 0 1, -1 0), GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(1 2 3 4))), GEOMETRYCOLLECTION(GEOMETRYCOLLECTION EMPTY), CURVEPOLYGON((0 0, 0 0, 0 0, 0 0), CIRCULARSTRING(1 3, 3 5, 4 7, 7 3, 1 3), COMPOUNDCURVE((0 -23.43778, 0 23.43778), CIRCULARSTRING(0 23.43778, -45 -23.43778, 0 -23.43778)), COMPOUNDCURVE((0 -23.43778, 7 7, 0 23.43778), CIRCULARSTRING(0 23.43778, 8 8, 8 8, -45 23.43778, -90 23.43778), (-90 23.43778, -90 -23.43778), CIRCULARSTRING(-90 -23.43778, -45 -23.43778, 0 -23.43778))))"; - + List geoWKTList = new ArrayList(); - + geoWKTList.add(geoWKTPoint); geoWKTList.add(geoWKTLineString); geoWKTList.add(geoWKTCircularString); @@ -458,126 +469,128 @@ public void testAllTypes() throws SQLException { geoWKTList.add(geoWKTMultiLineString); geoWKTList.add(geoWKTMultiPolygon); geoWKTList.add(geoWKTGeometryCollection); - + Geometry geomWKT; Geography geogWKT; - - //Geometry - pstmt = (SQLServerPreparedStatement) con.prepareStatement("insert into "+ geomTableName + " values (?)"); - - geomWKT = Geometry.STGeomFromText(geoWKTPoint, 0); - pstmt.setGeometry(1, geomWKT); - pstmt.executeUpdate(); - - geomWKT = Geometry.STGeomFromText(geoWKTLineString, 0); - pstmt.setGeometry(1, geomWKT); - pstmt.executeUpdate(); - - geomWKT = Geometry.STGeomFromText(geoWKTCircularString, 0); - pstmt.setGeometry(1, geomWKT); - pstmt.executeUpdate(); - - geomWKT = Geometry.STGeomFromText(geoWKTCompoundCurve, 0); - pstmt.setGeometry(1, geomWKT); - pstmt.executeUpdate(); - - geomWKT = Geometry.STGeomFromText(geoWKTCurvePolygon, 0); - pstmt.setGeometry(1, geomWKT); - pstmt.executeUpdate(); - - geomWKT = Geometry.STGeomFromText(geoWKTPolygon, 0); - pstmt.setGeometry(1, geomWKT); - pstmt.executeUpdate(); - - geomWKT = Geometry.STGeomFromText(geoWKTMultiPoint, 0); - pstmt.setGeometry(1, geomWKT); - pstmt.executeUpdate(); - - geomWKT = Geometry.STGeomFromText(geoWKTMultiLineString, 0); - pstmt.setGeometry(1, geomWKT); - pstmt.executeUpdate(); - - geomWKT = Geometry.STGeomFromText(geoWKTMultiPolygon, 0); - pstmt.setGeometry(1, geomWKT); - pstmt.executeUpdate(); - - geomWKT = Geometry.STGeomFromText(geoWKTGeometryCollection, 0); - pstmt.setGeometry(1, geomWKT); - pstmt.executeUpdate(); - - rs = (SQLServerResultSet) stmt.executeQuery("select c1 from " + geomTableName); - for (int i = 0; i < geoWKTList.size(); i++) { - rs.next(); - assertEquals(rs.getGeometry(1).asTextZM(), geoWKTList.get(i)); + + // Geometry + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con + .prepareStatement("insert into " + geomTableName + " values (?)");) { + geomWKT = Geometry.STGeomFromText(geoWKTPoint, 0); + pstmt.setGeometry(1, geomWKT); + pstmt.executeUpdate(); + + geomWKT = Geometry.STGeomFromText(geoWKTLineString, 0); + pstmt.setGeometry(1, geomWKT); + pstmt.executeUpdate(); + + geomWKT = Geometry.STGeomFromText(geoWKTCircularString, 0); + pstmt.setGeometry(1, geomWKT); + pstmt.executeUpdate(); + + geomWKT = Geometry.STGeomFromText(geoWKTCompoundCurve, 0); + pstmt.setGeometry(1, geomWKT); + pstmt.executeUpdate(); + + geomWKT = Geometry.STGeomFromText(geoWKTCurvePolygon, 0); + pstmt.setGeometry(1, geomWKT); + pstmt.executeUpdate(); + + geomWKT = Geometry.STGeomFromText(geoWKTPolygon, 0); + pstmt.setGeometry(1, geomWKT); + pstmt.executeUpdate(); + + geomWKT = Geometry.STGeomFromText(geoWKTMultiPoint, 0); + pstmt.setGeometry(1, geomWKT); + pstmt.executeUpdate(); + + geomWKT = Geometry.STGeomFromText(geoWKTMultiLineString, 0); + pstmt.setGeometry(1, geomWKT); + pstmt.executeUpdate(); + + geomWKT = Geometry.STGeomFromText(geoWKTMultiPolygon, 0); + pstmt.setGeometry(1, geomWKT); + pstmt.executeUpdate(); + + geomWKT = Geometry.STGeomFromText(geoWKTGeometryCollection, 0); + pstmt.setGeometry(1, geomWKT); + pstmt.executeUpdate(); + + rs = (SQLServerResultSet) stmt.executeQuery("select c1 from " + geomTableName); + for (int i = 0; i < geoWKTList.size(); i++) { + rs.next(); + assertEquals(rs.getGeometry(1).asTextZM(), geoWKTList.get(i)); + } } - - //Geography - pstmt = (SQLServerPreparedStatement) con.prepareStatement("insert into "+ geogTableName + " values (?)"); - - geogWKT = Geography.STGeomFromText(geoWKTPoint, 4326); - pstmt.setGeography(1, geogWKT); - - pstmt.executeUpdate(); - - geogWKT = Geography.STGeomFromText(geoWKTLineString, 4326); - pstmt.setGeography(1, geogWKT); - - pstmt.executeUpdate(); - - geogWKT = Geography.STGeomFromText(geoWKTCircularString, 4326); - pstmt.setGeography(1, geogWKT); - - pstmt.executeUpdate(); - - geogWKT = Geography.STGeomFromText(geoWKTCompoundCurve, 4326); - pstmt.setGeography(1, geogWKT); - - pstmt.executeUpdate(); - - geogWKT = Geography.STGeomFromText(geoWKTCurvePolygon, 4326); - pstmt.setGeography(1, geogWKT); - - pstmt.executeUpdate(); - - geogWKT = Geography.STGeomFromText(geoWKTPolygon, 4326); - pstmt.setGeography(1, geogWKT); - - pstmt.executeUpdate(); - - geogWKT = Geography.STGeomFromText(geoWKTMultiPoint, 4326); - pstmt.setGeography(1, geogWKT); - - pstmt.executeUpdate(); - - geogWKT = Geography.STGeomFromText(geoWKTMultiLineString, 4326); - pstmt.setGeography(1, geogWKT); - - pstmt.executeUpdate(); - - geogWKT = Geography.STGeomFromText(geoWKTMultiPolygon, 4326); - pstmt.setGeography(1, geogWKT); - - pstmt.executeUpdate(); - - geogWKT = Geography.STGeomFromText(geoWKTGeometryCollection, 4326); - pstmt.setGeography(1, geogWKT); - - pstmt.executeUpdate(); - - rs = (SQLServerResultSet) stmt.executeQuery("select c1 from " + geogTableName); - for (int i = 0; i < geoWKTList.size(); i++) { - rs.next(); - assertEquals(rs.getGeography(1).asTextZM(), geoWKTList.get(i)); + + // Geography + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con + .prepareStatement("insert into " + geogTableName + " values (?)");) { + geogWKT = Geography.STGeomFromText(geoWKTPoint, 4326); + pstmt.setGeography(1, geogWKT); + + pstmt.executeUpdate(); + + geogWKT = Geography.STGeomFromText(geoWKTLineString, 4326); + pstmt.setGeography(1, geogWKT); + + pstmt.executeUpdate(); + + geogWKT = Geography.STGeomFromText(geoWKTCircularString, 4326); + pstmt.setGeography(1, geogWKT); + + pstmt.executeUpdate(); + + geogWKT = Geography.STGeomFromText(geoWKTCompoundCurve, 4326); + pstmt.setGeography(1, geogWKT); + + pstmt.executeUpdate(); + + geogWKT = Geography.STGeomFromText(geoWKTCurvePolygon, 4326); + pstmt.setGeography(1, geogWKT); + + pstmt.executeUpdate(); + + geogWKT = Geography.STGeomFromText(geoWKTPolygon, 4326); + pstmt.setGeography(1, geogWKT); + + pstmt.executeUpdate(); + + geogWKT = Geography.STGeomFromText(geoWKTMultiPoint, 4326); + pstmt.setGeography(1, geogWKT); + + pstmt.executeUpdate(); + + geogWKT = Geography.STGeomFromText(geoWKTMultiLineString, 4326); + pstmt.setGeography(1, geogWKT); + + pstmt.executeUpdate(); + + geogWKT = Geography.STGeomFromText(geoWKTMultiPolygon, 4326); + pstmt.setGeography(1, geogWKT); + + pstmt.executeUpdate(); + + geogWKT = Geography.STGeomFromText(geoWKTGeometryCollection, 4326); + pstmt.setGeography(1, geogWKT); + + pstmt.executeUpdate(); + + rs = (SQLServerResultSet) stmt.executeQuery("select c1 from " + geogTableName); + for (int i = 0; i < geoWKTList.size(); i++) { + rs.next(); + assertEquals(rs.getGeography(1).asTextZM(), geoWKTList.get(i)); + } } } } - + @Test public void testMixedAllTypes() throws SQLException { if (isDenaliOrLater) { beforeEachSetupSpatialDatatype(); - - String geoWKTPoint = "POINT(30 12.12312312 5 6)"; + + String geoWKTPoint = "POINT(30 12.12312312 0)"; String geoWKTLineString = "LINESTRING(1 1, 2 4 3, 3 9 123 332)"; String geoWKTCircularString = "CIRCULARSTRING(1 1, 2 4, 3 9)"; String geoWKTCompoundCurve = "COMPOUNDCURVE((1 1, 1 3), (1 3, 3 3), (3 3, 3 1), (3 1, 1 1))"; @@ -587,13 +600,13 @@ public void testMixedAllTypes() throws SQLException { String geoWKTMultiLineString = "MULTILINESTRING((0 2, 1 1), (1 0, 1 1))"; String geoWKTMultiPolygon = "MULTIPOLYGON(((0 0, 0 3, 3 3, 3 0, 0 0), (1 1, 1 2, 2 1, 1 1)), ((9 9, 9 10, 10 9, 9 9)))"; String geoWKTGeometryCollection = "GEOMETRYCOLLECTION(POLYGON((0 0 2, 1 10 3, 1 0 4, 0 0 2)), POINT(3 3 1 2.5), LINESTRING(1 0, 0 1, -1 0), GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(POINT(1 2 3 4))), GEOMETRYCOLLECTION(GEOMETRYCOLLECTION EMPTY), CURVEPOLYGON((0 0, 0 0, 0 0, 0 0), CIRCULARSTRING(1 3, 3 5, 4 7, 7 3, 1 3), COMPOUNDCURVE((0 -23.43778, 0 23.43778), CIRCULARSTRING(0 23.43778, -45 -23.43778, 0 -23.43778)), COMPOUNDCURVE((0 -23.43778, 7 7, 0 23.43778), CIRCULARSTRING(0 23.43778, 8 8, 8 8, -45 23.43778, -90 23.43778), (-90 23.43778, -90 -23.43778), CIRCULARSTRING(-90 -23.43778, -45 -23.43778, 0 -23.43778))))"; - + String s = "some string"; Double d = 31.34; int i2 = 5; - + List geoWKTList = new ArrayList(); - + geoWKTList.add(geoWKTPoint); geoWKTList.add(geoWKTLineString); geoWKTList.add(geoWKTCircularString); @@ -604,120 +617,121 @@ public void testMixedAllTypes() throws SQLException { geoWKTList.add(geoWKTMultiLineString); geoWKTList.add(geoWKTMultiPolygon); geoWKTList.add(geoWKTGeometryCollection); - + Geometry geomWKT; Geography geogWKT; - - pstmt = (SQLServerPreparedStatement) con.prepareStatement("insert into "+ spatialDatatypeTableName + " values (?, ?, ?, ?, ?)"); - - geomWKT = Geometry.STGeomFromText(geoWKTPoint, 0); - geogWKT = Geography.STGeomFromText(geoWKTPoint, 4326); - pstmt.setGeometry(1, geomWKT); - pstmt.setGeography(2, geogWKT); - pstmt.setString(3, s); - pstmt.setDouble(4, d); - pstmt.setInt(5, i2); - - pstmt.executeUpdate(); - - geomWKT = Geometry.STGeomFromText(geoWKTLineString, 0); - geogWKT = Geography.STGeomFromText(geoWKTLineString, 4326); - pstmt.setGeometry(1, geomWKT); - pstmt.setGeography(2, geogWKT); - pstmt.setString(3, s); - pstmt.setDouble(4, d); - pstmt.setInt(5, i2); - - pstmt.executeUpdate(); - - geomWKT = Geometry.STGeomFromText(geoWKTCircularString, 0); - geogWKT = Geography.STGeomFromText(geoWKTCircularString, 4326); - pstmt.setGeometry(1, geomWKT); - pstmt.setGeography(2, geogWKT); - pstmt.setString(3, s); - pstmt.setDouble(4, d); - pstmt.setInt(5, i2); - - pstmt.executeUpdate(); - - geomWKT = Geometry.STGeomFromText(geoWKTCompoundCurve, 0); - geogWKT = Geography.STGeomFromText(geoWKTCompoundCurve, 4326); - pstmt.setGeometry(1, geomWKT); - pstmt.setGeography(2, geogWKT); - pstmt.setString(3, s); - pstmt.setDouble(4, d); - pstmt.setInt(5, i2); - - pstmt.executeUpdate(); - - geomWKT = Geometry.STGeomFromText(geoWKTCurvePolygon, 0); - geogWKT = Geography.STGeomFromText(geoWKTCurvePolygon, 4326); - pstmt.setGeometry(1, geomWKT); - pstmt.setGeography(2, geogWKT); - pstmt.setString(3, s); - pstmt.setDouble(4, d); - pstmt.setInt(5, i2); - - pstmt.executeUpdate(); - - geomWKT = Geometry.STGeomFromText(geoWKTPolygon, 0); - geogWKT = Geography.STGeomFromText(geoWKTPolygon, 4326); - pstmt.setGeometry(1, geomWKT); - pstmt.setGeography(2, geogWKT); - pstmt.setString(3, s); - pstmt.setDouble(4, d); - pstmt.setInt(5, i2); - - pstmt.executeUpdate(); - - geomWKT = Geometry.STGeomFromText(geoWKTMultiPoint, 0); - geogWKT = Geography.STGeomFromText(geoWKTMultiPoint, 4326); - pstmt.setGeometry(1, geomWKT); - pstmt.setGeography(2, geogWKT); - pstmt.setString(3, s); - pstmt.setDouble(4, d); - pstmt.setInt(5, i2); - - pstmt.executeUpdate(); - - geomWKT = Geometry.STGeomFromText(geoWKTMultiLineString, 0); - geogWKT = Geography.STGeomFromText(geoWKTMultiLineString, 4326); - pstmt.setGeometry(1, geomWKT); - pstmt.setGeography(2, geogWKT); - pstmt.setString(3, s); - pstmt.setDouble(4, d); - pstmt.setInt(5, i2); - - pstmt.executeUpdate(); - - geomWKT = Geometry.STGeomFromText(geoWKTMultiPolygon, 0); - geogWKT = Geography.STGeomFromText(geoWKTMultiPolygon, 4326); - pstmt.setGeometry(1, geomWKT); - pstmt.setGeography(2, geogWKT); - pstmt.setString(3, s); - pstmt.setDouble(4, d); - pstmt.setInt(5, i2); - - pstmt.executeUpdate(); - - geomWKT = Geometry.STGeomFromText(geoWKTGeometryCollection, 0); - geogWKT = Geography.STGeomFromText(geoWKTGeometryCollection, 4326); - pstmt.setGeometry(1, geomWKT); - pstmt.setGeography(2, geogWKT); - pstmt.setString(3, s); - pstmt.setDouble(4, d); - pstmt.setInt(5, i2); - - pstmt.executeUpdate(); - - rs = (SQLServerResultSet) stmt.executeQuery("select * from " + spatialDatatypeTableName); - for (int i = 0; i < geoWKTList.size(); i++) { - rs.next(); - assertEquals(rs.getGeometry(1).asTextZM(), geoWKTList.get(i)); - assertEquals(rs.getGeography(2).asTextZM(), geoWKTList.get(i)); - assertEquals(rs.getString(3), s); - assertEquals((Double) rs.getDouble(4), d); - assertEquals(rs.getInt(5), i2); + + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con + .prepareStatement("insert into " + spatialDatatypeTableName + " values (?, ?, ?, ?, ?)");) { + geomWKT = Geometry.STGeomFromText(geoWKTPoint, 0); + geogWKT = Geography.STGeomFromText(geoWKTPoint, 4326); + pstmt.setGeometry(1, geomWKT); + pstmt.setGeography(2, geogWKT); + pstmt.setString(3, s); + pstmt.setDouble(4, d); + pstmt.setInt(5, i2); + + pstmt.executeUpdate(); + + geomWKT = Geometry.STGeomFromText(geoWKTLineString, 0); + geogWKT = Geography.STGeomFromText(geoWKTLineString, 4326); + pstmt.setGeometry(1, geomWKT); + pstmt.setGeography(2, geogWKT); + pstmt.setString(3, s); + pstmt.setDouble(4, d); + pstmt.setInt(5, i2); + + pstmt.executeUpdate(); + + geomWKT = Geometry.STGeomFromText(geoWKTCircularString, 0); + geogWKT = Geography.STGeomFromText(geoWKTCircularString, 4326); + pstmt.setGeometry(1, geomWKT); + pstmt.setGeography(2, geogWKT); + pstmt.setString(3, s); + pstmt.setDouble(4, d); + pstmt.setInt(5, i2); + + pstmt.executeUpdate(); + + geomWKT = Geometry.STGeomFromText(geoWKTCompoundCurve, 0); + geogWKT = Geography.STGeomFromText(geoWKTCompoundCurve, 4326); + pstmt.setGeometry(1, geomWKT); + pstmt.setGeography(2, geogWKT); + pstmt.setString(3, s); + pstmt.setDouble(4, d); + pstmt.setInt(5, i2); + + pstmt.executeUpdate(); + + geomWKT = Geometry.STGeomFromText(geoWKTCurvePolygon, 0); + geogWKT = Geography.STGeomFromText(geoWKTCurvePolygon, 4326); + pstmt.setGeometry(1, geomWKT); + pstmt.setGeography(2, geogWKT); + pstmt.setString(3, s); + pstmt.setDouble(4, d); + pstmt.setInt(5, i2); + + pstmt.executeUpdate(); + + geomWKT = Geometry.STGeomFromText(geoWKTPolygon, 0); + geogWKT = Geography.STGeomFromText(geoWKTPolygon, 4326); + pstmt.setGeometry(1, geomWKT); + pstmt.setGeography(2, geogWKT); + pstmt.setString(3, s); + pstmt.setDouble(4, d); + pstmt.setInt(5, i2); + + pstmt.executeUpdate(); + + geomWKT = Geometry.STGeomFromText(geoWKTMultiPoint, 0); + geogWKT = Geography.STGeomFromText(geoWKTMultiPoint, 4326); + pstmt.setGeometry(1, geomWKT); + pstmt.setGeography(2, geogWKT); + pstmt.setString(3, s); + pstmt.setDouble(4, d); + pstmt.setInt(5, i2); + + pstmt.executeUpdate(); + + geomWKT = Geometry.STGeomFromText(geoWKTMultiLineString, 0); + geogWKT = Geography.STGeomFromText(geoWKTMultiLineString, 4326); + pstmt.setGeometry(1, geomWKT); + pstmt.setGeography(2, geogWKT); + pstmt.setString(3, s); + pstmt.setDouble(4, d); + pstmt.setInt(5, i2); + + pstmt.executeUpdate(); + + geomWKT = Geometry.STGeomFromText(geoWKTMultiPolygon, 0); + geogWKT = Geography.STGeomFromText(geoWKTMultiPolygon, 4326); + pstmt.setGeometry(1, geomWKT); + pstmt.setGeography(2, geogWKT); + pstmt.setString(3, s); + pstmt.setDouble(4, d); + pstmt.setInt(5, i2); + + pstmt.executeUpdate(); + + geomWKT = Geometry.STGeomFromText(geoWKTGeometryCollection, 0); + geogWKT = Geography.STGeomFromText(geoWKTGeometryCollection, 4326); + pstmt.setGeometry(1, geomWKT); + pstmt.setGeography(2, geogWKT); + pstmt.setString(3, s); + pstmt.setDouble(4, d); + pstmt.setInt(5, i2); + + pstmt.executeUpdate(); + + rs = (SQLServerResultSet) stmt.executeQuery("select * from " + spatialDatatypeTableName); + for (int i = 0; i < geoWKTList.size(); i++) { + rs.next(); + assertEquals(rs.getGeometry(1).asTextZM(), geoWKTList.get(i)); + assertEquals(rs.getGeography(2).asTextZM(), geoWKTList.get(i)); + assertEquals(rs.getString(3), s); + assertEquals((Double) rs.getDouble(4), d); + assertEquals(rs.getInt(5), i2); + } } } } @@ -725,209 +739,303 @@ public void testMixedAllTypes() throws SQLException { @Test public void testDecimalRounding() throws SQLException { beforeEachSetup(); - + String geoWKT = "POINT(3 40.7777777777777777777 5 6)"; String geoWKTSS = "POINT(3 40.77777777777778 5 6)"; - + testWkt(geoWKT, geoWKTSS); } - + @Test public void testParse() throws SQLException { beforeEachSetup(); - + String geoWKT = "GEOMETRYCOLLECTION(POINT(300 20 1), GEOMETRYCOLLECTION EMPTY, GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(GEOMETRYCOLLECTION EMPTY)), POLYGON((0 0 2, 1 10 3, 1 0 4, 0 0 2)))"; - + Geometry geomWKT = Geometry.parse(geoWKT); Geography geogWKT = Geography.parse(geoWKT); - - pstmt = (SQLServerPreparedStatement) con.prepareStatement("insert into "+ geomTableName + " values (?)"); - pstmt.setGeometry(1, geomWKT); - pstmt.execute(); - - rs = (SQLServerResultSet) stmt.executeQuery("select c1 from " + geomTableName); - rs.next(); - assertEquals(rs.getGeometry(1).asTextZM(), geoWKT); - assertEquals(rs.getGeometry(1).getSrid(), 0); - - pstmt = (SQLServerPreparedStatement) con.prepareStatement("insert into "+ geogTableName + " values (?)"); - pstmt.setGeography(1, geogWKT); - pstmt.execute(); - - rs = (SQLServerResultSet) stmt.executeQuery("select c1 from " + geogTableName); - rs.next(); - assertEquals(rs.getGeography(1).asTextZM(), geoWKT); - assertEquals(rs.getGeography(1).getSrid(), 4326); + + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con + .prepareStatement("insert into " + geomTableName + " values (?)");) { + pstmt.setGeometry(1, geomWKT); + pstmt.execute(); + + rs = (SQLServerResultSet) stmt.executeQuery("select c1 from " + geomTableName); + rs.next(); + assertEquals(rs.getGeometry(1).asTextZM(), geoWKT); + assertEquals(rs.getGeometry(1).getSrid(), 0); + } + + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con + .prepareStatement("insert into " + geogTableName + " values (?)");) { + pstmt.setGeography(1, geogWKT); + pstmt.execute(); + + rs = (SQLServerResultSet) stmt.executeQuery("select c1 from " + geogTableName); + rs.next(); + assertEquals(rs.getGeography(1).asTextZM(), geoWKT); + assertEquals(rs.getGeography(1).getSrid(), 4326); + } } - + @Test public void testPoint() throws SQLException { beforeEachSetup(); - + String geoWKT = "POINT(1 2)"; - + Geometry geomWKT = Geometry.point(1, 2, 0); Geography geogWKT = Geography.point(1, 2, 4326); - - pstmt = (SQLServerPreparedStatement) con.prepareStatement("insert into "+ geomTableName + " values (?)"); - pstmt.setGeometry(1, geomWKT); - pstmt.execute(); - - rs = (SQLServerResultSet) stmt.executeQuery("select c1 from " + geomTableName); - rs.next(); - assertEquals(rs.getGeometry(1).asTextZM(), geoWKT); - assertEquals(rs.getGeometry(1).getSrid(), 0); - - pstmt = (SQLServerPreparedStatement) con.prepareStatement("insert into "+ geogTableName + " values (?)"); - pstmt.setGeography(1, geogWKT); - pstmt.execute(); - - rs = (SQLServerResultSet) stmt.executeQuery("select c1 from " + geogTableName); - rs.next(); - assertEquals(rs.getGeography(1).asTextZM(), geoWKT); - assertEquals(rs.getGeography(1).getSrid(), 4326); + + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con + .prepareStatement("insert into " + geomTableName + " values (?)");) { + pstmt.setGeometry(1, geomWKT); + pstmt.execute(); + + rs = (SQLServerResultSet) stmt.executeQuery("select c1 from " + geomTableName); + rs.next(); + assertEquals(rs.getGeometry(1).asTextZM(), geoWKT); + assertEquals(rs.getGeometry(1).getSrid(), 0); + } + + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con + .prepareStatement("insert into " + geogTableName + " values (?)");) { + pstmt.setGeography(1, geogWKT); + pstmt.execute(); + + rs = (SQLServerResultSet) stmt.executeQuery("select c1 from " + geogTableName); + rs.next(); + assertEquals(rs.getGeography(1).asTextZM(), geoWKT); + assertEquals(rs.getGeography(1).getSrid(), 4326); + } } - + @Test public void testSTAsText() throws SQLException { beforeEachSetup(); - + String geoWKT = "GEOMETRYCOLLECTION(POINT(300 20 1), GEOMETRYCOLLECTION EMPTY, GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(GEOMETRYCOLLECTION EMPTY)), POLYGON((0 0 2, 1 10 3, 1 0 4, 0 0 2)))"; String geoWKTSS = "GEOMETRYCOLLECTION(POINT(300 20), GEOMETRYCOLLECTION EMPTY, GEOMETRYCOLLECTION(GEOMETRYCOLLECTION(GEOMETRYCOLLECTION EMPTY)), POLYGON((0 0, 1 10, 1 0, 0 0)))"; - + Geometry geomWKT = Geometry.STGeomFromText(geoWKT, 0); Geography geogWKT = Geography.STGeomFromText(geoWKT, 4326); - - pstmt = (SQLServerPreparedStatement) con.prepareStatement("insert into "+ geomTableName + " values (?)"); - pstmt.setGeometry(1, geomWKT); - pstmt.execute(); - - rs = (SQLServerResultSet) stmt.executeQuery("select c1 from " + geomTableName); - rs.next(); - assertEquals(rs.getGeometry(1).STAsText(), geoWKTSS); - - pstmt = (SQLServerPreparedStatement) con.prepareStatement("insert into "+ geogTableName + " values (?)"); - pstmt.setGeography(1, geogWKT); - pstmt.execute(); - - rs = (SQLServerResultSet) stmt.executeQuery("select c1 from " + geogTableName); - rs.next(); - assertEquals(rs.getGeography(1).STAsText(), geoWKTSS); + + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con + .prepareStatement("insert into " + geomTableName + " values (?)");) { + pstmt.setGeometry(1, geomWKT); + pstmt.execute(); + + rs = (SQLServerResultSet) stmt.executeQuery("select c1 from " + geomTableName); + rs.next(); + assertEquals(rs.getGeometry(1).STAsText(), geoWKTSS); + } + + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con + .prepareStatement("insert into " + geogTableName + " values (?)");) { + pstmt.setGeography(1, geogWKT); + pstmt.execute(); + + rs = (SQLServerResultSet) stmt.executeQuery("select c1 from " + geogTableName); + rs.next(); + assertEquals(rs.getGeography(1).STAsText(), geoWKTSS); + } } - + @Test public void testSTAsBinary() throws SQLException { beforeEachSetup(); - + String geoWKT = "POINT(3 40 5 6)"; String geoWKT2 = "POINT(3 40)"; - + Geometry geomWKT = Geometry.STGeomFromText(geoWKT, 0); Geography geogWKT = Geography.STGeomFromText(geoWKT, 4326); - + byte[] geomWKB = geomWKT.STAsBinary(); byte[] geogWKB = geogWKT.STAsBinary(); - + Geometry geomWKT2 = Geometry.STGeomFromText(geoWKT2, 0); Geography geogWKT2 = Geography.STGeomFromText(geoWKT2, 4326); - + byte[] geomWKB2 = geomWKT2.STAsBinary(); byte[] geogWKB2 = geogWKT2.STAsBinary(); - + assertEquals(geomWKB, geomWKB2); assertEquals(geogWKB, geogWKB2); } public void testCheckGeomMetaData() throws SQLException { beforeEachSetup(); - - pstmt = (SQLServerPreparedStatement) connection.prepareStatement("INSERT INTO " + geomTableName +" (c1) VALUES (?)"); - ParameterMetaData paramMetaData = pstmt.getParameterMetaData(); - Geometry g = Geometry.STGeomFromText("POINT (1 2 3 4)", 0); - pstmt.setGeometry(1, g); - pstmt.execute(); - - int sqlType = paramMetaData.getParameterType(1); - String sqlTypeName = paramMetaData.getParameterTypeName(1); - assertEquals(sqlType, -157); - assertEquals(sqlTypeName, "geometry"); - SQLServerResultSet rs = (SQLServerResultSet) stmt.executeQuery("select * from " + geomTableName); - ResultSetMetaData rsmd = rs.getMetaData(); - assertEquals(rsmd.getColumnType(1), -157); - } - + + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection + .prepareStatement("INSERT INTO " + geomTableName + " (c1) VALUES (?)");) { + ParameterMetaData paramMetaData = pstmt.getParameterMetaData(); + Geometry g = Geometry.STGeomFromText("POINT (1 2 3 4)", 0); + pstmt.setGeometry(1, g); + pstmt.execute(); + + int sqlType = paramMetaData.getParameterType(1); + String sqlTypeName = paramMetaData.getParameterTypeName(1); + assertEquals(sqlType, -157); + assertEquals(sqlTypeName, "geometry"); + SQLServerResultSet rs = (SQLServerResultSet) stmt.executeQuery("select * from " + geomTableName); + ResultSetMetaData rsmd = rs.getMetaData(); + assertEquals(rsmd.getColumnType(1), -157); + } + } + @Test public void testCheckGeogMetaData() throws SQLException { beforeEachSetup(); - - pstmt = (SQLServerPreparedStatement) connection.prepareStatement("INSERT INTO " + geogTableName +" (c1) VALUES (?)"); - ParameterMetaData paramMetaData = pstmt.getParameterMetaData(); - Geography g = Geography.STGeomFromText("POINT (1 2 3 4)", 4326); - pstmt.setGeography(1, g); - pstmt.execute(); - - int sqlType = paramMetaData.getParameterType(1); - String sqlTypeName = paramMetaData.getParameterTypeName(1); - assertEquals(sqlType, -158); - assertEquals(sqlTypeName, "geography"); - SQLServerResultSet rs = (SQLServerResultSet) stmt.executeQuery("select * from " + geogTableName); - ResultSetMetaData rsmd = rs.getMetaData(); - assertEquals(rsmd.getColumnType(1), -158); - } - + + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection + .prepareStatement("INSERT INTO " + geogTableName + " (c1) VALUES (?)");) { + ParameterMetaData paramMetaData = pstmt.getParameterMetaData(); + Geography g = Geography.STGeomFromText("POINT (1 2 3 4)", 4326); + pstmt.setGeography(1, g); + pstmt.execute(); + + int sqlType = paramMetaData.getParameterType(1); + String sqlTypeName = paramMetaData.getParameterTypeName(1); + assertEquals(sqlType, -158); + assertEquals(sqlTypeName, "geography"); + SQLServerResultSet rs = (SQLServerResultSet) stmt.executeQuery("select * from " + geogTableName); + ResultSetMetaData rsmd = rs.getMetaData(); + assertEquals(rsmd.getColumnType(1), -158); + } + } + + @Test + public void testGetXGetY() throws SQLException { + Geometry geom = Geometry.STGeomFromText("POINT (1 2 3 4)", 0); + Geography geog = Geography.STGeomFromText("POINT (1 2 3 4)", 4326); + + double x = geom.getX(); + double y = geom.getY(); + assertEquals(x, 1); + assertEquals(y, 2); + + x = geog.getLatitude(); + y = geog.getLongitude(); + assertEquals(x, 1); + assertEquals(y, 2); + } + + @Test + public void testNull() throws SQLException { + if (isDenaliOrLater) { + beforeEachSetupSpatialDatatype(); + + String geoWKTPoint = "POINT(30 12.12312312 NULL 6)"; + String geoWKTLineString = "LINESTRING(1 1 NULL NULL, 2 4 0 42, 3 9 NULL 332)"; + + String geoWKTPointExpected = "POINT(30 12.12312312 NULL 6)"; + String geoWKTLineStringExpected = "LINESTRING(1 1, 2 4 0 42, 3 9 NULL 332)"; + + String s = "some string"; + Double d = 31.34; + int i2 = 5; + + List geoWKTList = new ArrayList(); + + geoWKTList.add(geoWKTPoint); + geoWKTList.add(geoWKTLineString); + + List geoWKTListExpected = new ArrayList(); + + geoWKTListExpected.add(geoWKTPointExpected); + geoWKTListExpected.add(geoWKTLineStringExpected); + + Geometry geomWKT; + Geography geogWKT; + + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con + .prepareStatement("insert into " + spatialDatatypeTableName + " values (?, ?, ?, ?, ?)");) { + geomWKT = Geometry.STGeomFromText(geoWKTPoint, 0); + geogWKT = Geography.STGeomFromText(geoWKTPoint, 4326); + pstmt.setGeometry(1, geomWKT); + pstmt.setGeography(2, geogWKT); + pstmt.setString(3, s); + pstmt.setDouble(4, d); + pstmt.setInt(5, i2); + + pstmt.executeUpdate(); + + geomWKT = Geometry.STGeomFromText(geoWKTLineString, 0); + geogWKT = Geography.STGeomFromText(geoWKTLineString, 4326); + pstmt.setGeometry(1, geomWKT); + pstmt.setGeography(2, geogWKT); + pstmt.setString(3, s); + pstmt.setDouble(4, d); + pstmt.setInt(5, i2); + + pstmt.executeUpdate(); + + rs = (SQLServerResultSet) stmt.executeQuery("select * from " + spatialDatatypeTableName); + for (int i = 0; i < geoWKTList.size(); i++) { + rs.next(); + assertEquals(rs.getGeometry(1).asTextZM(), geoWKTListExpected.get(i)); + assertEquals(rs.getGeography(2).asTextZM(), geoWKTListExpected.get(i)); + assertEquals(rs.getString(3), s); + assertEquals((Double) rs.getDouble(4), d); + assertEquals(rs.getInt(5), i2); + } + } + } + } + private void beforeEachSetup() throws SQLException { Utils.dropTableIfExists(geomTableName, stmt); Utils.dropTableIfExists(geogTableName, stmt); stmt.executeUpdate("Create table " + geomTableName + " (c1 geometry)"); stmt.executeUpdate("Create table " + geogTableName + " (c1 geography)"); } - + private void beforeEachSetupSpatialDatatype() throws SQLException { Utils.dropTableIfExists(spatialDatatypeTableName, stmt); - stmt.executeUpdate("Create table " + spatialDatatypeTableName + - " (c1 geometry," - + "c2 geography," - + "c3 nvarchar(512)," - + "c4 decimal(28,4)," - + "c5 int)"); - } - + stmt.executeUpdate("Create table " + spatialDatatypeTableName + " (c1 geometry," + "c2 geography," + + "c3 nvarchar(512)," + "c4 decimal(28,4)," + "c5 int)"); + } + private void testWkt(String geoWKT) throws SQLException { testWkt(geoWKT, geoWKT); } - + private void testWkt(String geoWKT, String geoWKTSS) throws SQLException { Geometry geomWKT = Geometry.STGeomFromText(geoWKT, 0); Geography geogWKT = Geography.STGeomFromText(geoWKT, 4326); - - pstmt = (SQLServerPreparedStatement) con.prepareStatement("insert into "+ geomTableName + " values (?)"); - pstmt.setGeometry(1, geomWKT); - pstmt.execute(); - - rs = (SQLServerResultSet) stmt.executeQuery("select c1 from " + geomTableName); - rs.next(); - assertEquals(rs.getGeometry(1).asTextZM(), geoWKTSS); - - pstmt = (SQLServerPreparedStatement) con.prepareStatement("insert into "+ geogTableName + " values (?)"); - pstmt.setGeography(1, geogWKT); - pstmt.execute(); - - rs = (SQLServerResultSet) stmt.executeQuery("select c1 from " + geogTableName); - rs.next(); - assertEquals(rs.getGeography(1).asTextZM(), geoWKTSS); + + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con + .prepareStatement("insert into " + geomTableName + " values (?)");) { + pstmt.setGeometry(1, geomWKT); + pstmt.execute(); + + rs = (SQLServerResultSet) stmt.executeQuery("select c1 from " + geomTableName); + rs.next(); + assertEquals(rs.getGeometry(1).asTextZM(), geoWKTSS); + } + + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con + .prepareStatement("insert into " + geogTableName + " values (?)");) { + pstmt.setGeography(1, geogWKT); + pstmt.execute(); + + rs = (SQLServerResultSet) stmt.executeQuery("select c1 from " + geogTableName); + rs.next(); + assertEquals(rs.getGeography(1).asTextZM(), geoWKTSS); + } } - + private static byte[] hexStringToByteArray(String s) { int len = s.length(); byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { - data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) - + Character.digit(s.charAt(i+1), 16)); + data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16)); } - + return data; } - + /** * Prepare test * @@ -939,14 +1047,14 @@ private static byte[] hexStringToByteArray(String s) { public static void setupHere() throws SQLException, SecurityException, IOException { con = (SQLServerConnection) DriverManager.getConnection(connectionString); stmt = con.createStatement(); - + rs = (SQLServerResultSet) stmt.executeQuery("select SERVERPROPERTY ( 'ProductVersion' )"); - + rs.next(); - + try { int version = Integer.parseInt(rs.getString(1).substring(0, 2)); - + // if major version is greater than or equal to 11, it's SQL Server 2012 or above. if (version >= 11) { isDenaliOrLater = true; diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/SQLVariantResultSetTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/SQLVariantResultSetTest.java index 76701bba2..3d5a3937d 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/SQLVariantResultSetTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/SQLVariantResultSetTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.datatypes; @@ -35,6 +32,7 @@ import com.microsoft.sqlserver.testframework.Utils; import com.microsoft.sqlserver.testframework.util.RandomData; + /** * Tests for supporting sqlVariant * @@ -391,7 +389,8 @@ public void readSQLVariantProperty() throws SQLException, SecurityException, IOE "SELECT SQL_VARIANT_PROPERTY(col1,'BaseType') AS 'Base Type', SQL_VARIANT_PROPERTY(col1,'Precision') AS 'Precision' from " + tableName); rs.next(); - assertTrue(rs.getString(1).equalsIgnoreCase("binary"), "unexpected baseType, expected: binary, retrieved:" + rs.getString(1)); + assertTrue(rs.getString(1).equalsIgnoreCase("binary"), + "unexpected baseType, expected: binary, retrieved:" + rs.getString(1)); } /** @@ -407,12 +406,12 @@ public void insertVarChar8001() throws SQLException { } Utils.dropTableIfExists(tableName, stmt); stmt.executeUpdate("create table " + tableName + " (col1 sql_variant)"); - SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con.prepareStatement("insert into " + tableName + " values (?)"); + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con + .prepareStatement("insert into " + tableName + " values (?)"); pstmt.setObject(1, buffer.toString()); try { pstmt.execute(); - } - catch (SQLServerException e) { + } catch (SQLServerException e) { assertTrue(e.toString().contains("com.microsoft.sqlserver.jdbc.SQLServerException: Operand type clash")); } } @@ -523,7 +522,8 @@ public void updateBinary20() throws SQLException, SecurityException, IOException public void insertTest() throws SQLException { Utils.dropTableIfExists(tableName, stmt); stmt.executeUpdate("create table " + tableName + " (col1 sql_variant, col2 int)"); - SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con.prepareStatement("insert into " + tableName + " values (?, ?)"); + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con + .prepareStatement("insert into " + tableName + " values (?, ?)"); String[] col1Value = {"Hello", null}; int[] col2Value = {1, 2}; @@ -541,8 +541,7 @@ public void insertTest() throws SQLException { assertEquals(rs.getObject(1), col1Value[i]); assertEquals(rs.getObject(2), col2Value[i]); i++; - } - while (rs.next()); + } while (rs.next()); } /** @@ -597,7 +596,8 @@ public void callableStatementOutputIntTest() throws SQLException { stmt.executeUpdate("INSERT into " + tableName + " values (CAST (" + value + " AS " + "int" + "))"); Utils.dropProcedureIfExists(inputProc, stmt); - String sql = "CREATE PROCEDURE " + inputProc + " @p0 sql_variant OUTPUT AS SELECT TOP 1 @p0=col1 FROM " + tableName; + String sql = "CREATE PROCEDURE " + inputProc + " @p0 sql_variant OUTPUT AS SELECT TOP 1 @p0=col1 FROM " + + tableName; stmt.execute(sql); CallableStatement cs = con.prepareCall(" {call " + inputProc + " (?) }"); @@ -623,7 +623,8 @@ public void callableStatementOutputDateTest() throws SQLException { stmt.executeUpdate("INSERT into " + tableName + " values (CAST ('" + value + "' AS " + "date" + "))"); Utils.dropProcedureIfExists(inputProc, stmt); - String sql = "CREATE PROCEDURE " + inputProc + " @p0 sql_variant OUTPUT AS SELECT TOP 1 @p0=col1 FROM " + tableName; + String sql = "CREATE PROCEDURE " + inputProc + " @p0 sql_variant OUTPUT AS SELECT TOP 1 @p0=col1 FROM " + + tableName; stmt.execute(sql); CallableStatement cs = con.prepareCall(" {call " + inputProc + " (?) }"); @@ -649,7 +650,8 @@ public void callableStatementOutputTimeTest() throws SQLException { stmt.executeUpdate("INSERT into " + tableName + " values (CAST ('" + value + "' AS " + "time(3)" + "))"); Utils.dropProcedureIfExists(inputProc, stmt); - String sql = "CREATE PROCEDURE " + inputProc + " @p0 sql_variant OUTPUT AS SELECT TOP 1 @p0=col1 FROM " + tableName; + String sql = "CREATE PROCEDURE " + inputProc + " @p0 sql_variant OUTPUT AS SELECT TOP 1 @p0=col1 FROM " + + tableName; stmt.execute(sql); CallableStatement cs = con.prepareCall(" {call " + inputProc + " (?) }"); @@ -677,8 +679,8 @@ public void callableStatementOutputBinaryTest() throws SQLException { pstmt.setObject(2, secondBinary20); pstmt.execute(); Utils.dropProcedureIfExists(inputProc, stmt); - String sql = "CREATE PROCEDURE " + inputProc + " @p0 sql_variant OUTPUT, @p1 sql_variant" + " AS" + " SELECT top 1 @p0=col1 FROM " + tableName - + " where col2=@p1 "; + String sql = "CREATE PROCEDURE " + inputProc + " @p0 sql_variant OUTPUT, @p1 sql_variant" + " AS" + + " SELECT top 1 @p0=col1 FROM " + tableName + " where col2=@p1 "; stmt.execute(sql); CallableStatement cs = con.prepareCall(" {call " + inputProc + " (?,?) }"); @@ -703,10 +705,11 @@ public void callableStatementInputOutputIntTest() throws SQLException { int col2Value = 2; Utils.dropTableIfExists(tableName, stmt); stmt.executeUpdate("create table " + tableName + " (col1 sql_variant, col2 int)"); - stmt.executeUpdate("INSERT into " + tableName + "(col1, col2) values (CAST (" + col1Value + " AS " + "int" + "), " + col2Value + ")"); + stmt.executeUpdate("INSERT into " + tableName + "(col1, col2) values (CAST (" + col1Value + " AS " + "int" + + "), " + col2Value + ")"); Utils.dropProcedureIfExists(inputProc, stmt); - String sql = "CREATE PROCEDURE " + inputProc + " @p0 sql_variant OUTPUT, @p1 sql_variant" + " AS" + " SELECT top 1 @p0=col1 FROM " + tableName - + " where col2=@p1"; + String sql = "CREATE PROCEDURE " + inputProc + " @p0 sql_variant OUTPUT, @p1 sql_variant" + " AS" + + " SELECT top 1 @p0=col1 FROM " + tableName + " where col2=@p1"; stmt.execute(sql); CallableStatement cs = con.prepareCall(" {call " + inputProc + " (?,?) }"); @@ -731,10 +734,11 @@ public void callableStatementInputOutputReturnIntTest() throws SQLException { int returnValue = 12; Utils.dropTableIfExists(tableName, stmt); stmt.executeUpdate("create table " + tableName + " (col1 sql_variant, col2 int)"); - stmt.executeUpdate("INSERT into " + tableName + "(col1, col2) values (CAST (" + col1Value + " AS " + "int" + "), " + col2Value + ")"); + stmt.executeUpdate("INSERT into " + tableName + "(col1, col2) values (CAST (" + col1Value + " AS " + "int" + + "), " + col2Value + ")"); Utils.dropProcedureIfExists(inputProc, stmt); - String sql = "CREATE PROCEDURE " + inputProc + " @p0 sql_variant OUTPUT, @p1 sql_variant" + " AS" + " SELECT top 1 @p0=col1 FROM " + tableName - + " where col2=@p1" + " return " + returnValue; + String sql = "CREATE PROCEDURE " + inputProc + " @p0 sql_variant OUTPUT, @p1 sql_variant" + " AS" + + " SELECT top 1 @p0=col1 FROM " + tableName + " where col2=@p1" + " return " + returnValue; stmt.execute(sql); CallableStatement cs = con.prepareCall(" {? = call " + inputProc + " (?,?) }"); @@ -762,11 +766,11 @@ public void callableStatementInputOutputReturnStringTest() throws SQLException { Utils.dropTableIfExists(tableName, stmt); stmt.executeUpdate("create table " + tableName + " (col1 sql_variant, col2 sql_variant)"); - stmt.executeUpdate("INSERT into " + tableName + "(col1,col2) values" + " (CAST ('" + col1Value + "' AS " + "varchar(5)" + ")" + " ,CAST ('" - + col2Value + "' AS " + "varchar(5)" + ")" + ")"); + stmt.executeUpdate("INSERT into " + tableName + "(col1,col2) values" + " (CAST ('" + col1Value + "' AS " + + "varchar(5)" + ")" + " ,CAST ('" + col2Value + "' AS " + "varchar(5)" + ")" + ")"); Utils.dropProcedureIfExists(inputProc, stmt); - String sql = "CREATE PROCEDURE " + inputProc + " @p0 sql_variant OUTPUT, @p1 sql_variant" + " AS" + " SELECT top 1 @p0=col1 FROM " + tableName - + " where col2=@p1 " + " return " + returnValue; + String sql = "CREATE PROCEDURE " + inputProc + " @p0 sql_variant OUTPUT, @p1 sql_variant" + " AS" + + " SELECT top 1 @p0=col1 FROM " + tableName + " where col2=@p1 " + " return " + returnValue; stmt.execute(sql); CallableStatement cs = con.prepareCall(" {? = call " + inputProc + " (?,?) }"); cs.registerOutParameter(1, java.sql.Types.INTEGER); @@ -793,8 +797,8 @@ public void readSeveralRows() throws SQLException { String value3 = "hi"; Utils.dropTableIfExists(tableName, stmt); stmt.executeUpdate("create table " + tableName + " (col1 sql_variant, col2 sql_variant, col3 sql_variant)"); - stmt.executeUpdate("INSERT into " + tableName + " values (CAST (" + value1 + " AS " + "tinyint" + ")" + ",CAST (" + value2 + " AS " + "int" - + ")" + ",CAST ('" + value3 + "' AS " + "char(2)" + ")" + ")"); + stmt.executeUpdate("INSERT into " + tableName + " values (CAST (" + value1 + " AS " + "tinyint" + ")" + + ",CAST (" + value2 + " AS " + "int" + ")" + ",CAST ('" + value3 + "' AS " + "char(2)" + ")" + ")"); rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + tableName); rs.next(); @@ -806,16 +810,18 @@ public void readSeveralRows() throws SQLException { } } - + /** * Test retrieving values with varchar and integer as basetype + * * @throws SQLException */ @Test public void readVarcharInteger() throws SQLException { Object expected[] = {"abc", 42}; int index = 0; - rs = (SQLServerResultSet) stmt.executeQuery("SELECT cast('abc' as sql_variant) UNION ALL SELECT cast(42 as sql_variant)"); + rs = (SQLServerResultSet) stmt + .executeQuery("SELECT cast('abc' as sql_variant) UNION ALL SELECT cast(42 as sql_variant)"); while (rs.next()) { assertEquals(rs.getObject(1), expected[index++]); } @@ -828,13 +834,13 @@ public void readVarcharInteger() throws SQLException { */ @Test public void testUnsupportedDatatype() throws SQLException { - rs = (SQLServerResultSet) stmt.executeQuery("select cast(cast('2017-08-16 17:31:09.995 +07:00' as datetimeoffset) as sql_variant)"); + rs = (SQLServerResultSet) stmt + .executeQuery("select cast(cast('2017-08-16 17:31:09.995 +07:00' as datetimeoffset) as sql_variant)"); rs.next(); try { rs.getObject(1); fail(TestResource.getResource("R_expectedExceptionNotThrown")); - } - catch (Exception e) { + } catch (Exception e) { assertTrue(e.getMessage().equalsIgnoreCase("Unexpected TDS type DATETIMEOFFSETN in SQL_VARIANT.")); } if (null != rs) { @@ -853,13 +859,12 @@ public void testTimeClassAsSqlVariant() throws SQLException { rs = (SQLServerResultSet) stmt.executeQuery("select cast(cast('17:31:09.995' as time(3)) as sql_variant)"); rs.next(); Object object = rs.getObject(1); - assertEquals(object.getClass(), java.sql.Time.class); - ; + assertEquals(object.getClass(), java.sql.Time.class);; } - private boolean parseByte(byte[] expectedData, - byte[] retrieved) { - assertTrue(Arrays.equals(expectedData, Arrays.copyOf(retrieved, expectedData.length)), " unexpected BINARY value, expected"); + private boolean parseByte(byte[] expectedData, byte[] retrieved) { + assertTrue(Arrays.equals(expectedData, Arrays.copyOf(retrieved, expectedData.length)), + " unexpected BINARY value, expected"); for (int i = expectedData.length; i < retrieved.length; i++) { assertTrue(0 == retrieved[i], "unexpected data BINARY"); } @@ -873,8 +878,7 @@ private boolean parseByte(byte[] expectedData, * @param value * @throws SQLException */ - private void createAndPopulateTable(String columnType, - Object value) throws SQLException { + private void createAndPopulateTable(String columnType, Object value) throws SQLException { Utils.dropTableIfExists(tableName, stmt); stmt.executeUpdate("create table " + tableName + " (col1 sql_variant)"); stmt.executeUpdate("INSERT into " + tableName + " values (CAST (" + value + " AS " + columnType + "))"); diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/TVPWithSqlVariantTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/TVPWithSqlVariantTest.java index e62a18dce..6e4bf7f97 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/TVPWithSqlVariantTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/datatypes/TVPWithSqlVariantTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.datatypes; @@ -37,6 +34,7 @@ import com.microsoft.sqlserver.testframework.sqlType.SqlDate; import com.microsoft.sqlserver.testframework.util.RandomData; + @RunWith(JUnitPlatform.class) public class TVPWithSqlVariantTest extends AbstractTest { @@ -53,14 +51,15 @@ public class TVPWithSqlVariantTest extends AbstractTest { * Test a previous failure regarding to numeric precision. Issue #211 * * @throws SQLException - * @throws SQLTimeoutException + * @throws SQLTimeoutException */ @Test public void testInt() throws SQLException { tvp = new SQLServerDataTable(); tvp.addColumnMetadata("c1", microsoft.sql.Types.SQL_VARIANT); tvp.addRow(12); - pstmt = (SQLServerPreparedStatement) connection.prepareStatement("INSERT INTO " + destTable + " select * from ? ;"); + pstmt = (SQLServerPreparedStatement) connection + .prepareStatement("INSERT INTO " + destTable + " select * from ? ;"); pstmt.setStructured(1, tvpName, tvp); pstmt.execute(); if (null != pstmt) { @@ -79,7 +78,7 @@ public void testInt() throws SQLException { * Test with date value * * @throws SQLException - * @throws SQLTimeoutException + * @throws SQLTimeoutException */ @Test public void testDate() throws SQLException { @@ -88,7 +87,8 @@ public void testDate() throws SQLException { tvp = new SQLServerDataTable(); tvp.addColumnMetadata("c1", microsoft.sql.Types.SQL_VARIANT); tvp.addRow(date); - pstmt = (SQLServerPreparedStatement) connection.prepareStatement("INSERT INTO " + destTable + " select * from ? ;"); + pstmt = (SQLServerPreparedStatement) connection + .prepareStatement("INSERT INTO " + destTable + " select * from ? ;"); pstmt.setStructured(1, tvpName, tvp); pstmt.execute(); if (null != pstmt) { @@ -104,7 +104,7 @@ public void testDate() throws SQLException { * Test with money value * * @throws SQLException - * @throws SQLTimeoutException + * @throws SQLTimeoutException */ @Test public void testMoney() throws SQLException { @@ -112,7 +112,8 @@ public void testMoney() throws SQLException { tvp.addColumnMetadata("c1", microsoft.sql.Types.SQL_VARIANT); String[] numeric = createNumericValues(); tvp.addRow(new BigDecimal(numeric[14])); - pstmt = (SQLServerPreparedStatement) connection.prepareStatement("INSERT INTO " + destTable + " select * from ? ;"); + pstmt = (SQLServerPreparedStatement) connection + .prepareStatement("INSERT INTO " + destTable + " select * from ? ;"); pstmt.setStructured(1, tvpName, tvp); pstmt.execute(); if (null != pstmt) { @@ -128,7 +129,7 @@ public void testMoney() throws SQLException { * Test with small int value * * @throws SQLException - * @throws SQLTimeoutException + * @throws SQLTimeoutException */ @Test public void testSmallInt() throws SQLException { @@ -136,7 +137,8 @@ public void testSmallInt() throws SQLException { tvp.addColumnMetadata("c1", microsoft.sql.Types.SQL_VARIANT); String[] numeric = createNumericValues(); tvp.addRow(Short.valueOf(numeric[2])); - pstmt = (SQLServerPreparedStatement) connection.prepareStatement("INSERT INTO " + destTable + " select * from ? ;"); + pstmt = (SQLServerPreparedStatement) connection + .prepareStatement("INSERT INTO " + destTable + " select * from ? ;"); pstmt.setStructured(1, tvpName, tvp); pstmt.execute(); @@ -146,7 +148,8 @@ public void testSmallInt() throws SQLException { rs = (SQLServerResultSet) stmt.executeQuery("SELECT * FROM " + destTable); while (rs.next()) { assertEquals("" + rs.getInt(1), numeric[2]); - // System.out.println(rs.getShort(1)); //does not work says cannot cast integer to short cause it is written as int + // System.out.println(rs.getShort(1)); //does not work says cannot cast integer to short cause it is written + // as int } } @@ -154,7 +157,7 @@ public void testSmallInt() throws SQLException { * Test with bigint value * * @throws SQLException - * @throws SQLTimeoutException + * @throws SQLTimeoutException */ @Test public void testBigInt() throws SQLException { @@ -164,7 +167,8 @@ public void testBigInt() throws SQLException { String[] numeric = createNumericValues(); tvp.addRow(Long.parseLong(numeric[4])); - pstmt = (SQLServerPreparedStatement) connection.prepareStatement("INSERT INTO " + destTable + " select * from ? ;"); + pstmt = (SQLServerPreparedStatement) connection + .prepareStatement("INSERT INTO " + destTable + " select * from ? ;"); pstmt.setStructured(1, tvpName, tvp); pstmt.execute(); if (null != pstmt) { @@ -180,7 +184,7 @@ public void testBigInt() throws SQLException { * Test with boolean value * * @throws SQLException - * @throws SQLTimeoutException + * @throws SQLTimeoutException */ @Test public void testBoolean() throws SQLException { @@ -188,7 +192,8 @@ public void testBoolean() throws SQLException { tvp.addColumnMetadata("c1", microsoft.sql.Types.SQL_VARIANT); String[] numeric = createNumericValues(); tvp.addRow(Boolean.parseBoolean(numeric[0])); - pstmt = (SQLServerPreparedStatement) connection.prepareStatement("INSERT INTO " + destTable + " select * from ? ;"); + pstmt = (SQLServerPreparedStatement) connection + .prepareStatement("INSERT INTO " + destTable + " select * from ? ;"); pstmt.setStructured(1, tvpName, tvp); pstmt.execute(); if (null != pstmt) { @@ -204,7 +209,7 @@ public void testBoolean() throws SQLException { * Test with float value * * @throws SQLException - * @throws SQLTimeoutException + * @throws SQLTimeoutException */ @Test public void testFloat() throws SQLException { @@ -212,7 +217,8 @@ public void testFloat() throws SQLException { tvp.addColumnMetadata("c1", microsoft.sql.Types.SQL_VARIANT); String[] numeric = createNumericValues(); tvp.addRow(Float.parseFloat(numeric[1])); - pstmt = (SQLServerPreparedStatement) connection.prepareStatement("INSERT INTO " + destTable + " select * from ? ;"); + pstmt = (SQLServerPreparedStatement) connection + .prepareStatement("INSERT INTO " + destTable + " select * from ? ;"); pstmt.setStructured(1, tvpName, tvp); pstmt.execute(); if (null != pstmt) { @@ -228,7 +234,7 @@ public void testFloat() throws SQLException { * Test with nvarchar * * @throws SQLException - * @throws SQLTimeoutException + * @throws SQLTimeoutException */ @Test public void testNvarChar() throws SQLException { @@ -236,7 +242,8 @@ public void testNvarChar() throws SQLException { tvp.addColumnMetadata("c1", microsoft.sql.Types.SQL_VARIANT); String colValue = "س"; tvp.addRow(colValue); - pstmt = (SQLServerPreparedStatement) connection.prepareStatement("INSERT INTO " + destTable + " select * from ? ;"); + pstmt = (SQLServerPreparedStatement) connection + .prepareStatement("INSERT INTO " + destTable + " select * from ? ;"); pstmt.setStructured(1, tvpName, tvp); pstmt.execute(); if (null != pstmt) { @@ -252,7 +259,7 @@ public void testNvarChar() throws SQLException { * Test with varchar8000 * * @throws SQLException - * @throws SQLTimeoutException + * @throws SQLTimeoutException */ @Test public void testVarChar8000() throws SQLException { @@ -265,7 +272,8 @@ public void testVarChar8000() throws SQLException { String value = buffer.toString(); tvp.addRow(value); - pstmt = (SQLServerPreparedStatement) connection.prepareStatement("INSERT INTO " + destTable + " select * from ? ;"); + pstmt = (SQLServerPreparedStatement) connection + .prepareStatement("INSERT INTO " + destTable + " select * from ? ;"); pstmt.setStructured(1, tvpName, tvp); pstmt.execute(); if (null != pstmt) { @@ -294,19 +302,18 @@ public void testLongVarChar() throws SQLException { String value = buffer.toString(); tvp.addRow(value); - pstmt = (SQLServerPreparedStatement) connection.prepareStatement("INSERT INTO " + destTable + " select * from ? ;"); + pstmt = (SQLServerPreparedStatement) connection + .prepareStatement("INSERT INTO " + destTable + " select * from ? ;"); pstmt.setStructured(1, tvpName, tvp); try { pstmt.execute(); - } - catch (SQLException e) { - assertTrue(e.getMessage().contains("SQL_VARIANT does not support string values of length greater than 8000.")); - } - catch (Exception e) { + } catch (SQLException e) { + assertTrue( + e.getMessage().contains("SQL_VARIANT does not support string values of length greater than 8000.")); + } catch (Exception e) { // Test should have failed! mistakenly inserted string value of more than 8000 in sql-variant fail(TestResource.getResource("R_unexpectedException")); - } - finally { + } finally { if (null != pstmt) { pstmt.close(); } @@ -317,7 +324,7 @@ public void testLongVarChar() throws SQLException { * Test ith datetime * * @throws SQLException - * @throws SQLTimeoutException + * @throws SQLTimeoutException */ @Test public void testDateTime() throws SQLException { @@ -326,7 +333,8 @@ public void testDateTime() throws SQLException { tvp.addColumnMetadata("c1", microsoft.sql.Types.SQL_VARIANT); tvp.addRow(timestamp); - pstmt = (SQLServerPreparedStatement) connection.prepareStatement("INSERT INTO " + destTable + " select * from ? ;"); + pstmt = (SQLServerPreparedStatement) connection + .prepareStatement("INSERT INTO " + destTable + " select * from ? ;"); pstmt.setStructured(1, tvpName, tvp); pstmt.execute(); if (null != pstmt) { @@ -343,7 +351,7 @@ public void testDateTime() throws SQLException { * Test with null value * * @throws SQLException - * @throws SQLTimeoutException + * @throws SQLTimeoutException */ @Test // TODO We need to check this later. Right now sending null with TVP is not supported public void testNull() throws SQLException { @@ -351,12 +359,12 @@ public void testNull() throws SQLException { tvp.addColumnMetadata("c1", microsoft.sql.Types.SQL_VARIANT); try { tvp.addRow((Date) null); - } - catch (Exception e) { + } catch (Exception e) { assertTrue(e.getMessage().startsWith("Use of TVPs containing null sql_variant columns is not supported.")); } - pstmt = (SQLServerPreparedStatement) connection.prepareStatement("INSERT INTO " + destTable + " select * from ? ;"); + pstmt = (SQLServerPreparedStatement) connection + .prepareStatement("INSERT INTO " + destTable + " select * from ? ;"); pstmt.setStructured(1, tvpName, tvp); pstmt.execute(); if (null != pstmt) { @@ -372,7 +380,7 @@ public void testNull() throws SQLException { * Test with stored procedure * * @throws SQLException - * @throws SQLTimeoutException + * @throws SQLTimeoutException */ @Test public void testIntStoredProcedure() throws SQLException { @@ -392,7 +400,7 @@ public void testIntStoredProcedure() throws SQLException { Cstatement.close(); } } - + /** * Test for allowing duplicate columns * @@ -442,9 +450,9 @@ private static String[] createNumericValues() { BigDecimal C15_decimal = RandomData.generateDecimalNumeric(28, 4, nullable); BigDecimal C16_numeric = RandomData.generateDecimalNumeric(28, 4, nullable); - String[] numericValues = {"" + C1_BIT, "" + C2_TINYINT, "" + C3_SMALLINT, "" + C4_INT, "" + C5_BIGINT, "" + C6_FLOAT, "" + C7_FLOAT, - "" + C8_REAL, "" + C9_DECIMAL, "" + C10_DECIMAL, "" + C11_NUMERIC, "" + C12_NUMERIC, "" + C13_smallMoney, "" + C14_money, - "" + C15_decimal, "" + C16_numeric}; + String[] numericValues = {"" + C1_BIT, "" + C2_TINYINT, "" + C3_SMALLINT, "" + C4_INT, "" + C5_BIGINT, + "" + C6_FLOAT, "" + C7_FLOAT, "" + C8_REAL, "" + C9_DECIMAL, "" + C10_DECIMAL, "" + C11_NUMERIC, + "" + C12_NUMERIC, "" + C13_smallMoney, "" + C14_money, "" + C15_decimal, "" + C16_numeric}; if (RandomData.returnZero && !RandomData.returnNull) { C10_DECIMAL = new BigDecimal(0); @@ -458,8 +466,9 @@ private static String[] createNumericValues() { } @BeforeEach - private void testSetup() throws SQLException { - conn = (SQLServerConnection) DriverManager.getConnection(connectionString + ";sendStringParametersAsUnicode=true;"); + public void testSetup() throws SQLException { + conn = (SQLServerConnection) DriverManager + .getConnection(connectionString + ";sendStringParametersAsUnicode=true;"); stmt = (SQLServerStatement) conn.createStatement(); Utils.dropProcedureIfExists(procedureName, stmt); @@ -472,12 +481,13 @@ private void testSetup() throws SQLException { } private static void dropTVPS() throws SQLException { - stmt.executeUpdate("IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvpName + "') " + " drop type " + tvpName); + stmt.executeUpdate("IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvpName + "') " + + " drop type " + tvpName); } private static void createPreocedure() throws SQLException { - String sql = "CREATE PROCEDURE " + procedureName + " @InputData " + tvpName + " READONLY " + " AS " + " BEGIN " + " INSERT INTO " + destTable - + " SELECT * FROM @InputData" + " END"; + String sql = "CREATE PROCEDURE " + procedureName + " @InputData " + tvpName + " READONLY " + " AS " + " BEGIN " + + " INSERT INTO " + destTable + " SELECT * FROM @InputData" + " END"; stmt.execute(sql); } @@ -493,7 +503,7 @@ private void createTVPS() throws SQLException { } @AfterEach - private void terminateVariation() throws SQLException { + public void terminateVariation() throws SQLException { Utils.dropProcedureIfExists(procedureName, stmt); Utils.dropTableIfExists(destTable, stmt); dropTVPS(); diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/dns/DNSRealmsTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/dns/DNSRealmsTest.java index 8a16cffc9..02d795381 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/dns/DNSRealmsTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/dns/DNSRealmsTest.java @@ -1,28 +1,26 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ -package com.microsoft.sqlserver.jdbc.dns; - -import javax.naming.NamingException; - -public class DNSRealmsTest { - - public static void main(String... args) { - if (args.length < 1) { - System.err.println("USAGE: list of domains to test for kerberos realms"); - } - for (String realmName : args) { - try { - System.out.print(DNSKerberosLocator.isRealmValid(realmName) ? "[ VALID ] " : "[INVALID] "); - } catch (NamingException err) { - System.err.print("[ FAILED] : " + err.getClass().getName() + ":" + err.getMessage()); - } - System.out.println(realmName); - } - } - -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package com.microsoft.sqlserver.jdbc.dns; + +import javax.naming.NamingException; + + +public class DNSRealmsTest { + + public static void main(String... args) { + if (args.length < 1) { + System.err.println("USAGE: list of domains to test for kerberos realms"); + } + for (String realmName : args) { + try { + System.out.print(DNSKerberosLocator.isRealmValid(realmName) ? "[ VALID ] " : "[INVALID] "); + } catch (NamingException err) { + System.err.print("[ FAILED] : " + err.getClass().getName() + ":" + err.getMessage()); + } + System.out.println(realmName); + } + } + +} diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/exception/ExceptionTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/exception/ExceptionTest.java index b21430515..d7cc3c310 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/exception/ExceptionTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/exception/ExceptionTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.exception; @@ -25,6 +22,7 @@ import com.microsoft.sqlserver.testframework.AbstractTest; import com.microsoft.sqlserver.testframework.Utils; + @RunWith(JUnitPlatform.class) public class ExceptionTest extends AbstractTest { static String inputFile = "BulkCopyCSVTestInput.csv"; @@ -39,9 +37,9 @@ public void testBulkCSVFileRecordExceptionCause() throws Exception { String filePath = Utils.getCurrentClassPath(); try { - SQLServerBulkCSVFileRecord scvFileRecord = new SQLServerBulkCSVFileRecord(filePath + inputFile, "invalid_encoding", true); - } - catch (Exception e) { + SQLServerBulkCSVFileRecord scvFileRecord = new SQLServerBulkCSVFileRecord(filePath + inputFile, + "invalid_encoding", true); + } catch (Exception e) { if (!(e instanceof SQLException)) { throw e; } @@ -67,17 +65,17 @@ public void testSocketTimeoutExceptionCause() throws Exception { SQLServerConnection conn = null; try { conn = (SQLServerConnection) DriverManager.getConnection(connectionString); - + Utils.dropProcedureIfExists(waitForDelaySPName, conn.createStatement()); createWaitForDelayPreocedure(conn); - conn = (SQLServerConnection) DriverManager.getConnection(connectionString + ";socketTimeout=" + (waitForDelaySeconds * 1000 / 2) + ";"); + conn = (SQLServerConnection) DriverManager + .getConnection(connectionString + ";socketTimeout=" + (waitForDelaySeconds * 1000 / 2) + ";"); try { conn.createStatement().execute("exec " + waitForDelaySPName); throw new Exception(TestResource.getResource("R_expectedExceptionNotThrown")); - } - catch (Exception e) { + } catch (Exception e) { if (!(e instanceof SQLException)) { throw e; } @@ -87,8 +85,7 @@ public void testSocketTimeoutExceptionCause() throws Exception { Object[] msgArgs = {"SocketTimeoutException"}; assertTrue(e.getCause() instanceof SocketTimeoutException, form.format(msgArgs)); } - } - finally { + } finally { if (null != conn) { conn.close(); } @@ -96,7 +93,8 @@ public void testSocketTimeoutExceptionCause() throws Exception { } private void createWaitForDelayPreocedure(SQLServerConnection conn) throws SQLException { - String sql = "CREATE PROCEDURE " + waitForDelaySPName + " AS" + " BEGIN" + " WAITFOR DELAY '00:00:" + waitForDelaySeconds + "';" + " END"; + String sql = "CREATE PROCEDURE " + waitForDelaySPName + " AS" + " BEGIN" + " WAITFOR DELAY '00:00:" + + waitForDelaySeconds + "';" + " END"; conn.createStatement().execute(sql); } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/fips/FipsEnvTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/fips/FipsEnvTest.java index 0b9c25b3d..8539439cd 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/fips/FipsEnvTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/fips/FipsEnvTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.fips; @@ -23,9 +20,9 @@ import org.junit.platform.runner.JUnitPlatform; import org.junit.runner.RunWith; -import com.microsoft.sqlserver.testframework.Utils; +import com.microsoft.sqlserver.jdbc.TestResource; +import com.microsoft.sqlserver.testframework.Utils;; -import com.microsoft.sqlserver.jdbc.TestResource;; /** * Class which will useful for checking if FIPS env. set or not. @@ -75,19 +72,21 @@ public static void populateProperties() { public void testFIPSOnOracle() throws Exception { assumeTrue(ORACLE_JVM.equals(currentJVM), TestResource.getResource("R_wrongEnv") + ORACLE_JVM); - assumeTrue("FIPS".equals(Utils.getConfiguredProperty("FIPS_ENV")), TestResource.getResource("R_fipsPropertyNotSet")); + assumeTrue("FIPS".equals(Utils.getConfiguredProperty("FIPS_ENV")), + TestResource.getResource("R_fipsPropertyNotSet")); assertTrue(isFIPS("SunJSSE"), "FIPS " + TestResource.getResource("R_shouldBeEnabled")); // As JDK 1.7 is not supporting lambda for time being commenting. /* - * assumingThat("NSSFIPS".equals(Utils.getConfiguredProperty("FIPS_ENV")), () -> assertAll("All FIPS", () -> assertTrue(isFIPS("SunJSSE"), - * TestResource.getResource("R_shouldBeEnabled")), () -> assertTrue(isFIPS("SunPKCS11-NSS"), "Testing"))); - * - * assumingThat("BCFIPS".equals(Utils.getConfiguredProperty("FIPS_ENV")), () -> assertAll("All FIPS", () -> assertTrue(isFIPS("SunJSSE"), - * TestResource.getResource("R_shouldBeEnabled")), () -> assertTrue(isFIPS("BCFIPS"), "Testing"))); - * - * assumingThat("FIPS".equals(Utils.getConfiguredProperty("FIPS_ENV")), ()-> assertTrue(isFIPS("SunJSSE"), TestResource.getResource("R_shouldBeEnabled"))); + * assumingThat("NSSFIPS".equals(Utils.getConfiguredProperty("FIPS_ENV")), () -> assertAll("All FIPS", () -> + * assertTrue(isFIPS("SunJSSE"), TestResource.getResource("R_shouldBeEnabled")), () -> + * assertTrue(isFIPS("SunPKCS11-NSS"), "Testing"))); + * assumingThat("BCFIPS".equals(Utils.getConfiguredProperty("FIPS_ENV")), () -> assertAll("All FIPS", () -> + * assertTrue(isFIPS("SunJSSE"), TestResource.getResource("R_shouldBeEnabled")), () -> + * assertTrue(isFIPS("BCFIPS"), "Testing"))); + * assumingThat("FIPS".equals(Utils.getConfiguredProperty("FIPS_ENV")), ()-> assertTrue(isFIPS("SunJSSE"), + * TestResource.getResource("R_shouldBeEnabled"))); */ } @@ -100,44 +99,47 @@ public void testFIPSOnOracle() throws Exception { public void testFIPSOnIBM() throws Exception { assumeTrue(IBM_JVM.equals(currentJVM), TestResource.getResource("R_wrongEnv") + IBM_JVM); - assumeTrue("FIPS".equals(Utils.getConfiguredProperty("FIPS_ENV")), TestResource.getResource("R_fipsPropertyNotSet")); + assumeTrue("FIPS".equals(Utils.getConfiguredProperty("FIPS_ENV")), + TestResource.getResource("R_fipsPropertyNotSet")); assertTrue(isFIPS("IBMJCEFIP"), "FIPS " + TestResource.getResource("R_shouldBeEnabled")); // As JDK 1.7 is not supporting lambda for time being commenting. /* - * assumingThat("NSSFIPS".equals(Utils.getConfiguredProperty("FIPS_ENV")), () -> assertAll("All FIPS", () -> assertTrue(isFIPS("IBMJCEFIP"), - * "FIPS should be Enabled."), () -> assertTrue(isFIPS("SunPKCS11-NSS"), "Testing"))); - * - * assumingThat("BCFIPS".equals(Utils.getConfiguredProperty("FIPS_ENV")), () -> assertAll("All FIPS", () -> assertTrue(isFIPS("IBMJCEFIPS"), - * "FIPS should be Enabled."), () -> assertTrue(isFIPS("BCFIPS"), "Testing"))); - * - * assumingThat("FIPS".equals(Utils.getConfiguredProperty("FIPS_ENV")), ()-> assertTrue(isFIPS("IBMJCEFIPS"), "FIPS Should be enabled")); + * assumingThat("NSSFIPS".equals(Utils.getConfiguredProperty("FIPS_ENV")), () -> assertAll("All FIPS", () -> + * assertTrue(isFIPS("IBMJCEFIP"), "FIPS should be Enabled."), () -> assertTrue(isFIPS("SunPKCS11-NSS"), + * "Testing"))); assumingThat("BCFIPS".equals(Utils.getConfiguredProperty("FIPS_ENV")), () -> + * assertAll("All FIPS", () -> assertTrue(isFIPS("IBMJCEFIPS"), "FIPS should be Enabled."), () -> + * assertTrue(isFIPS("BCFIPS"), "Testing"))); + * assumingThat("FIPS".equals(Utils.getConfiguredProperty("FIPS_ENV")), ()-> assertTrue(isFIPS("IBMJCEFIPS"), + * "FIPS Should be enabled")); */ } /** - * In case of FIPs enabled this test method will call {@link #isFIPS(String)} with appropriate FIPS provider. May be useful only for JDK 1.8 + * In case of FIPs enabled this test method will call {@link #isFIPS(String)} with appropriate FIPS provider. May be + * useful only for JDK 1.8 */ @Test @Disabled public void testFIPSEnv() { - assumeTrue("FIPS".equals(Utils.getConfiguredProperty("FIPS_ENV")), TestResource.getResource("R_fipsPropertyNotSet")); + assumeTrue("FIPS".equals(Utils.getConfiguredProperty("FIPS_ENV")), + TestResource.getResource("R_fipsPropertyNotSet")); // As JDK 1.7 is not supporting lambda for time being commenting. /* - * assumingThat(System.getProperty("java.vendor").startsWith("IBM"), () -> assertTrue(isFIPS("IBMJCEFIP"), "FIPS should be Enabled.")); - * - * assumingThat(System.getProperty("java.vendor").startsWith("Oracle"), () -> assertTrue(isFIPS("SunJSSE"), "FIPS should be Enabled.")); + * assumingThat(System.getProperty("java.vendor").startsWith("IBM"), () -> assertTrue(isFIPS("IBMJCEFIP"), + * "FIPS should be Enabled.")); assumingThat(System.getProperty("java.vendor").startsWith("Oracle"), () -> + * assertTrue(isFIPS("SunJSSE"), "FIPS should be Enabled.")); */ } /** - * Just simple method to check if JVM is configured for FIPS or not. CAUTION: We observed that SSLContext.getDefault().getProvider - * fails because it could not find any algorithm. + * Just simple method to check if JVM is configured for FIPS or not. CAUTION: We observed that + * SSLContext.getDefault().getProvider fails because it could not find any algorithm. * * @param provider - * FIPS Provider + * FIPS Provider * @return boolean * @throws Exception */ diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/fips/FipsTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/fips/FipsTest.java index 67378152c..81a0980d0 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/fips/FipsTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/fips/FipsTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.fips; @@ -19,10 +16,10 @@ import com.microsoft.sqlserver.jdbc.SQLServerDataSource; import com.microsoft.sqlserver.jdbc.StringUtils; +import com.microsoft.sqlserver.jdbc.TestResource; import com.microsoft.sqlserver.testframework.PrepUtil; -import com.microsoft.sqlserver.testframework.Utils; +import com.microsoft.sqlserver.testframework.Utils;; -import com.microsoft.sqlserver.jdbc.TestResource;; /** * Test class for testing FIPS property settings. @@ -51,10 +48,8 @@ public void fipsTrustServerCertificateTest() throws Exception { props.setProperty("TrustServerCertificate", "true"); Connection con = PrepUtil.getConnection(connectionString, props); Assertions.fail(TestResource.getResource("R_expectedExceptionNotThrown")); - } - catch (SQLException e) { - Assertions.assertTrue( - e.getMessage().contains(TestResource.getResource("R_invalidFipsConfig")), + } catch (SQLException e) { + Assertions.assertTrue(e.getMessage().contains(TestResource.getResource("R_invalidFipsConfig")), TestResource.getResource("R_invalidTrustCert")); } } @@ -71,10 +66,8 @@ public void fipsEncryptTest() throws Exception { props.setProperty("encrypt", "false"); Connection con = PrepUtil.getConnection(connectionString, props); Assertions.fail(TestResource.getResource("R_expectedExceptionNotThrown")); - } - catch (SQLException e) { - Assertions.assertTrue( - e.getMessage().contains(TestResource.getResource("R_invalidFipsConfig")), + } catch (SQLException e) { + Assertions.assertTrue(e.getMessage().contains(TestResource.getResource("R_invalidFipsConfig")), TestResource.getResource("R_invalidEncrypt")); } } @@ -126,10 +119,8 @@ public void fipsDatSourceEncrypt() { Connection con = ds.getConnection(); Assertions.fail(TestResource.getResource("R_expectedExceptionNotThrown")); - } - catch (SQLException e) { - Assertions.assertTrue( - e.getMessage().contains(TestResource.getResource("R_invalidFipsConfig")), + } catch (SQLException e) { + Assertions.assertTrue(e.getMessage().contains(TestResource.getResource("R_invalidFipsConfig")), TestResource.getResource("R_invalidEncrypt")); } } @@ -147,16 +138,15 @@ public void fipsDataSourceTrustServerCertificateTest() throws Exception { ds.setTrustServerCertificate(true); Connection con = ds.getConnection(); Assertions.fail(TestResource.getResource("R_expectedExceptionNotThrown")); - } - catch (SQLException e) { - Assertions.assertTrue( - e.getMessage().contains(TestResource.getResource("R_invalidFipsConfig")), + } catch (SQLException e) { + Assertions.assertTrue(e.getMessage().contains(TestResource.getResource("R_invalidFipsConfig")), TestResource.getResource("R_invalidTrustCert")); } } /** * Setting appropriate data source properties including FIPS + * * @param ds */ private void setDataSourceProperties(SQLServerDataSource ds) { @@ -202,7 +192,8 @@ private Properties buildConnectionProperties() { /** * It will return String array. [dbServer,username,password,dbname/database] * - * -ea -Dmssql_jdbc_test_connection_properties=jdbc:sqlserver://SQL-2K16-01.galaxy.ad;userName=sa;password=Moonshine4me;database=test; + * -ea + * -Dmssql_jdbc_test_connection_properties=jdbc:sqlserver://SQL-2K16-01.galaxy.ad;userName=sa;password=Moonshine4me;database=test; * -Djava.library.path=C:\Downloads\sqljdbc_6.0.7728.100_enu.tar\sqljdbc_6.0\enu\auth\x64 * * @param connectionProperty @@ -222,33 +213,29 @@ private static String[] getDataSourceProperties() { } } // Actually this is specifically did for Travis. - else if(strParam.startsWith("port")) { + else if (strParam.startsWith("port")) { strParam = strParam.toLowerCase(); - if(strParam.startsWith("portnumber")) { + if (strParam.startsWith("portnumber")) { dataSoureParam[1] = strParam.replace("portnumber=", ""); } else { dataSoureParam[1] = strParam.replace("port=", ""); } } - + else if (strParam.startsWith("user")) { strParam = strParam.toLowerCase(); if (strParam.startsWith("username")) { dataSoureParam[2] = strParam.replace("username=", ""); - } - else { + } else { dataSoureParam[2] = strParam.replace("user=", ""); } - } - else if (strParam.startsWith("password")) { + } else if (strParam.startsWith("password")) { dataSoureParam[3] = strParam.replace("password=", ""); - } - else if (strParam.startsWith("database")) { + } else if (strParam.startsWith("database")) { strParam = strParam.toLowerCase(); if (strParam.startsWith("databasename")) { dataSoureParam[4] = strParam.replace("databasename=", ""); - } - else { + } else { dataSoureParam[4] = strParam.replace("database=", ""); } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/parametermetadata/ParameterMetaDataTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/parametermetadata/ParameterMetaDataTest.java index 7a59ba809..81bf36465 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/parametermetadata/ParameterMetaDataTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/parametermetadata/ParameterMetaDataTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.parametermetadata; @@ -25,6 +22,7 @@ import com.microsoft.sqlserver.testframework.Utils; import com.microsoft.sqlserver.testframework.util.RandomUtil; + @RunWith(JUnitPlatform.class) public class ParameterMetaDataTest extends AbstractTest { private static final String tableName = "[" + RandomUtil.getIdentifier("StatementParam") + "]"; @@ -47,8 +45,7 @@ public void testParameterMetaDataWrapper() throws SQLException { assertTrue(parameterMetaData.isWrapperFor(ParameterMetaData.class)); assertSame(parameterMetaData, parameterMetaData.unwrap(ParameterMetaData.class)); } - } - finally { + } finally { Utils.dropTableIfExists(tableName, stmt); } } @@ -65,13 +62,12 @@ public void testSQLServerExceptionNotWrapped() throws SQLException { PreparedStatement pstmt = connection.prepareStatement("invalid query :)");) { pstmt.getParameterMetaData(); - } - catch (SQLException e) { + } catch (SQLException e) { assertTrue(!e.getMessage().contains("com.microsoft.sqlserver.jdbc.SQLException"), "SQLException should not be wrapped by another SQLException."); } } - + /** * Test ParameterMetaData when parameter name contains braces * @@ -88,8 +84,7 @@ public void testNameWithBraces() throws SQLException { try (PreparedStatement pstmt = con.prepareStatement(query)) { pstmt.getParameterMetaData(); } - } - finally { + } finally { Utils.dropTableIfExists(tableName, stmt); } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/parametermetadata/ParameterMetaDataWhiteSpaceTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/parametermetadata/ParameterMetaDataWhiteSpaceTest.java index 6911066b0..7f23ff551 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/parametermetadata/ParameterMetaDataWhiteSpaceTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/parametermetadata/ParameterMetaDataWhiteSpaceTest.java @@ -1,145 +1,144 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ -package com.microsoft.sqlserver.jdbc.parametermetadata; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.sql.DriverManager; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.platform.runner.JUnitPlatform; -import org.junit.runner.RunWith; - -import com.microsoft.sqlserver.jdbc.SQLServerConnection; -import com.microsoft.sqlserver.testframework.AbstractTest; -import com.microsoft.sqlserver.testframework.Utils; -import com.microsoft.sqlserver.testframework.util.RandomUtil; - -@RunWith(JUnitPlatform.class) -public class ParameterMetaDataWhiteSpaceTest extends AbstractTest { - private static final String tableName = "[" + RandomUtil.getIdentifier("ParameterMetaDataWhiteSpaceTest") + "]"; - - private static Statement stmt = null; - - @BeforeAll - public static void BeforeTests() throws SQLException { - connection = (SQLServerConnection) DriverManager.getConnection(connectionString); - stmt = connection.createStatement(); - createCharTable(); - } - - @AfterAll - public static void dropTables() throws SQLException { - Utils.dropTableIfExists(tableName, stmt); - - if (null != stmt) { - stmt.close(); - } - - if (null != connection) { - connection.close(); - } - } - - private static void createCharTable() throws SQLException { - stmt.execute("Create table " + tableName + " (c1 int)"); - } - - /** - * Test regular simple query - * - * @throws SQLException - */ - @Test - public void NormalTest() throws SQLException { - testUpdateWithTwoParameters("update " + tableName + " set c1 = ? where c1 = ?"); - testInsertWithOneParameter("insert into " + tableName + " (c1) values (?)"); - } - - /** - * Test query with new line character - * - * @throws SQLException - */ - @Test - public void NewLineTest() throws SQLException { - testQueriesWithWhiteSpaces("\n"); - } - - /** - * Test query with tab character - * - * @throws SQLException - */ - @Test - public void TabTest() throws SQLException { - testQueriesWithWhiteSpaces("\t"); - } - - /** - * Test query with form feed character - * - * @throws SQLException - */ - @Test - public void FormFeedTest() throws SQLException { - testQueriesWithWhiteSpaces("\f"); - } - - private void testQueriesWithWhiteSpaces(String whiteSpace) throws SQLException { - testUpdateWithTwoParameters("update" + whiteSpace + tableName + " set c1 = ? where c1 = ?"); - testUpdateWithTwoParameters("update " + tableName + " set" + whiteSpace + "c1 = ? where c1 = ?"); - testUpdateWithTwoParameters("update " + tableName + " set c1 = ? where" + whiteSpace + "c1 = ?"); - - testInsertWithOneParameter("insert into " + tableName + "(c1) values (?)"); // no space between table name and column name - testInsertWithOneParameter("insert into" + whiteSpace + tableName + " (c1) values (?)"); - } - - private void testUpdateWithTwoParameters(String sql) throws SQLException { - insertTestRow(1); - try (PreparedStatement ps = connection.prepareStatement(sql)) { - ps.setInt(1, 2); - ps.setInt(2, 1); - ps.executeUpdate(); - assertTrue(isIdPresentInTable(2), "Expected ID is not present"); - assertEquals(2, ps.getParameterMetaData().getParameterCount(), "Parameter count mismatch"); - } - } - - private void testInsertWithOneParameter(String sql) throws SQLException { - try (PreparedStatement ps = connection.prepareStatement(sql)) { - ps.setInt(1, 1); - ps.executeUpdate(); - assertTrue(isIdPresentInTable(1), "Insert statement did not work"); - assertEquals(1, ps.getParameterMetaData().getParameterCount(), "Parameter count mismatch"); - } - } - - private void insertTestRow(int id) throws SQLException { - try (PreparedStatement ps = connection.prepareStatement("insert into " + tableName + " (c1) values (?)")) { - ps.setInt(1, id); - ps.executeUpdate(); - } - } - - private boolean isIdPresentInTable(int id) throws SQLException { - try (PreparedStatement ps = connection.prepareStatement("select c1 from " + tableName + " where c1 = ?")) { - ps.setInt(1, id); - try (ResultSet rs = ps.executeQuery()) { - return rs.next(); - } - } - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package com.microsoft.sqlserver.jdbc.parametermetadata; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.platform.runner.JUnitPlatform; +import org.junit.runner.RunWith; + +import com.microsoft.sqlserver.jdbc.SQLServerConnection; +import com.microsoft.sqlserver.testframework.AbstractTest; +import com.microsoft.sqlserver.testframework.Utils; +import com.microsoft.sqlserver.testframework.util.RandomUtil; + + +@RunWith(JUnitPlatform.class) +public class ParameterMetaDataWhiteSpaceTest extends AbstractTest { + private static final String tableName = "[" + RandomUtil.getIdentifier("ParameterMetaDataWhiteSpaceTest") + "]"; + + private static Statement stmt = null; + + @BeforeAll + public static void BeforeTests() throws SQLException { + connection = (SQLServerConnection) DriverManager.getConnection(connectionString); + stmt = connection.createStatement(); + createCharTable(); + } + + @AfterAll + public static void dropTables() throws SQLException { + Utils.dropTableIfExists(tableName, stmt); + + if (null != stmt) { + stmt.close(); + } + + if (null != connection) { + connection.close(); + } + } + + private static void createCharTable() throws SQLException { + stmt.execute("Create table " + tableName + " (c1 int)"); + } + + /** + * Test regular simple query + * + * @throws SQLException + */ + @Test + public void NormalTest() throws SQLException { + testUpdateWithTwoParameters("update " + tableName + " set c1 = ? where c1 = ?"); + testInsertWithOneParameter("insert into " + tableName + " (c1) values (?)"); + } + + /** + * Test query with new line character + * + * @throws SQLException + */ + @Test + public void NewLineTest() throws SQLException { + testQueriesWithWhiteSpaces("\n"); + } + + /** + * Test query with tab character + * + * @throws SQLException + */ + @Test + public void TabTest() throws SQLException { + testQueriesWithWhiteSpaces("\t"); + } + + /** + * Test query with form feed character + * + * @throws SQLException + */ + @Test + public void FormFeedTest() throws SQLException { + testQueriesWithWhiteSpaces("\f"); + } + + private void testQueriesWithWhiteSpaces(String whiteSpace) throws SQLException { + testUpdateWithTwoParameters("update" + whiteSpace + tableName + " set c1 = ? where c1 = ?"); + testUpdateWithTwoParameters("update " + tableName + " set" + whiteSpace + "c1 = ? where c1 = ?"); + testUpdateWithTwoParameters("update " + tableName + " set c1 = ? where" + whiteSpace + "c1 = ?"); + + testInsertWithOneParameter("insert into " + tableName + "(c1) values (?)"); // no space between table name and + // column name + testInsertWithOneParameter("insert into" + whiteSpace + tableName + " (c1) values (?)"); + } + + private void testUpdateWithTwoParameters(String sql) throws SQLException { + insertTestRow(1); + try (PreparedStatement ps = connection.prepareStatement(sql)) { + ps.setInt(1, 2); + ps.setInt(2, 1); + ps.executeUpdate(); + assertTrue(isIdPresentInTable(2), "Expected ID is not present"); + assertEquals(2, ps.getParameterMetaData().getParameterCount(), "Parameter count mismatch"); + } + } + + private void testInsertWithOneParameter(String sql) throws SQLException { + try (PreparedStatement ps = connection.prepareStatement(sql)) { + ps.setInt(1, 1); + ps.executeUpdate(); + assertTrue(isIdPresentInTable(1), "Insert statement did not work"); + assertEquals(1, ps.getParameterMetaData().getParameterCount(), "Parameter count mismatch"); + } + } + + private void insertTestRow(int id) throws SQLException { + try (PreparedStatement ps = connection.prepareStatement("insert into " + tableName + " (c1) values (?)")) { + ps.setInt(1, id); + ps.executeUpdate(); + } + } + + private boolean isIdPresentInTable(int id) throws SQLException { + try (PreparedStatement ps = connection.prepareStatement("select c1 from " + tableName + " where c1 = ?")) { + ps.setInt(1, id); + try (ResultSet rs = ps.executeQuery()) { + return rs.next(); + } + } + } +} diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/preparedStatement/BatchExecutionWithBulkCopyTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/preparedStatement/BatchExecutionWithBulkCopyTest.java index d98dc4ebb..207a1fd4c 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/preparedStatement/BatchExecutionWithBulkCopyTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/preparedStatement/BatchExecutionWithBulkCopyTest.java @@ -6,6 +6,7 @@ import java.lang.reflect.Field; import java.lang.reflect.Method; +import java.sql.BatchUpdateException; import java.sql.Connection; import java.sql.Date; import java.sql.DriverManager; @@ -23,17 +24,21 @@ import org.junit.runner.RunWith; import org.opentest4j.TestAbortedException; +import com.microsoft.sqlserver.jdbc.Geography; +import com.microsoft.sqlserver.jdbc.Geometry; import com.microsoft.sqlserver.jdbc.SQLServerConnection; import com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement; import com.microsoft.sqlserver.jdbc.SQLServerStatement; import com.microsoft.sqlserver.testframework.AbstractTest; import com.microsoft.sqlserver.testframework.Utils; + @RunWith(JUnitPlatform.class) public class BatchExecutionWithBulkCopyTest extends AbstractTest { static long UUID = System.currentTimeMillis();; static String tableName = "BulkCopyParseTest" + UUID; + static String unsupportedTableName = "BulkCopyUnsupportedTable" + UUID; static String squareBracketTableName = "[peter]]]]test" + UUID + "]"; static String doubleQuoteTableName = "\"peter\"\"\"\"test" + UUID + "\""; @@ -66,10 +71,11 @@ public void testComments() throws Exception { f1.setAccessible(true); f1.set(pstmt, valid); - Method method = pstmt.getClass().getDeclaredMethod("parseUserSQLForTableNameDW", boolean.class, boolean.class, boolean.class, boolean.class); + Method method = pstmt.getClass().getDeclaredMethod("parseUserSQLForTableNameDW", boolean.class, + boolean.class, boolean.class, boolean.class); method.setAccessible(true); - assertEquals((String) method.invoke(pstmt, false, false, false, false), "PeterTable"); + assertEquals("PeterTable", (String) method.invoke(pstmt, false, false, false, false)); } } @@ -84,10 +90,11 @@ public void testBrackets() throws Exception { f1.setAccessible(true); f1.set(pstmt, valid); - Method method = pstmt.getClass().getDeclaredMethod("parseUserSQLForTableNameDW", boolean.class, boolean.class, boolean.class, boolean.class); + Method method = pstmt.getClass().getDeclaredMethod("parseUserSQLForTableNameDW", boolean.class, + boolean.class, boolean.class, boolean.class); method.setAccessible(true); - assertEquals((String) method.invoke(pstmt, false, false, false, false), "[Peter[]]Table]"); + assertEquals("[Peter[]]Table]", (String) method.invoke(pstmt, false, false, false, false)); } } @@ -102,10 +109,11 @@ public void testDoubleQuotes() throws Exception { f1.setAccessible(true); f1.set(pstmt, valid); - Method method = pstmt.getClass().getDeclaredMethod("parseUserSQLForTableNameDW", boolean.class, boolean.class, boolean.class, boolean.class); + Method method = pstmt.getClass().getDeclaredMethod("parseUserSQLForTableNameDW", boolean.class, + boolean.class, boolean.class, boolean.class); method.setAccessible(true); - assertEquals((String) method.invoke(pstmt, false, false, false, false), "\"Peter\"\"\"\"Table\""); + assertEquals("\"Peter\"\"\"\"Table\"", (String) method.invoke(pstmt, false, false, false, false)); } } @@ -122,7 +130,8 @@ public void testAll() throws Exception { f1.setAccessible(true); f1.set(pstmt, valid); - Method method = pstmt.getClass().getDeclaredMethod("parseUserSQLForTableNameDW", boolean.class, boolean.class, boolean.class, boolean.class); + Method method = pstmt.getClass().getDeclaredMethod("parseUserSQLForTableNameDW", boolean.class, + boolean.class, boolean.class, boolean.class); method.setAccessible(true); assertEquals((String) method.invoke(pstmt, false, false, false, false), "\"Peter\"\"\"\"Table\""); @@ -138,51 +147,27 @@ public void testAll() throws Exception { columnListExpected.add("c4"); for (int i = 0; i < columnListExpected.size(); i++) { - assertEquals(columnList.get(i), columnListExpected.get(i)); - } - - method = pstmt.getClass().getDeclaredMethod("parseUserSQLForValueListDW", boolean.class); - method.setAccessible(true); - - ArrayList valueList = (ArrayList) method.invoke(pstmt, false); - ArrayList valueListExpected = new ArrayList(); - valueListExpected.add("1"); - valueListExpected.add("2"); - valueListExpected.add("'?'"); - valueListExpected.add("?"); - - for (int i = 0; i < valueListExpected.size(); i++) { - assertEquals(valueList.get(i), valueListExpected.get(i)); + assertEquals(columnListExpected.get(i), columnList.get(i)); } } } - + @Test public void testAllcolumns() throws Exception { - String valid = "INSERT INTO " + tableName + " values " - + "(" - + "?, " - + "?, " - + "?, " - + "?, " - + "?, " - + "?, " - + "?, " - + "?, " - + "?, " - + ")"; - + String valid = "INSERT INTO " + tableName + " values " + "(" + "?, " + "?, " + "?, " + "?, " + "?, " + "?, " + + "?, " + "?, " + "? " + ")"; + try (Connection connection = DriverManager.getConnection(connectionString + ";useBulkCopyForBatchInsert=true;"); SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection.prepareStatement(valid); Statement stmt = (SQLServerStatement) connection.createStatement();) { Field f1 = SQLServerConnection.class.getDeclaredField("isAzureDW"); f1.setAccessible(true); f1.set(connection, true); - + Timestamp myTimestamp = new Timestamp(114550L); - + Date d = new Date(114550L); - + pstmt.setInt(1, 1234); pstmt.setBoolean(2, false); pstmt.setString(3, "a"); @@ -193,13 +178,13 @@ public void testAllcolumns() throws Exception { pstmt.setString(8, "varc"); pstmt.setString(9, "''"); pstmt.addBatch(); - + pstmt.executeBatch(); - + ResultSet rs = stmt.executeQuery("SELECT * FROM " + tableName); - + Object[] expected = new Object[9]; - + expected[0] = 1234; expected[1] = false; expected[2] = "a"; @@ -209,47 +194,42 @@ public void testAllcolumns() throws Exception { expected[6] = "b"; expected[7] = "varc"; expected[8] = "''"; - + rs.next(); - for (int i=0; i < expected.length; i++) { - assertEquals(rs.getObject(i + 1).toString(), expected[i].toString()); + for (int i = 0; i < expected.length; i++) { + assertEquals(expected[i].toString(), rs.getObject(i + 1).toString()); } } } @Test public void testMixColumns() throws Exception { - String valid = "INSERT INTO " + tableName + " (c1, c3, c5, c8) values " - + "(" - + "?, " - + "?, " - + "?, " - + "?, " + String valid = "INSERT INTO " + tableName + " (c1, c3, c5, c8) values " + "(" + "?, " + "?, " + "?, " + "? " + ")"; - + try (Connection connection = DriverManager.getConnection(connectionString + ";useBulkCopyForBatchInsert=true;"); SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection.prepareStatement(valid); Statement stmt = (SQLServerStatement) connection.createStatement();) { Field f1 = SQLServerConnection.class.getDeclaredField("isAzureDW"); f1.setAccessible(true); f1.set(connection, true); - + Timestamp myTimestamp = new Timestamp(114550L); - + Date d = new Date(114550L); - + pstmt.setInt(1, 1234); pstmt.setString(2, "a"); pstmt.setDateTime(3, myTimestamp); pstmt.setString(4, "varc"); pstmt.addBatch(); - + pstmt.executeBatch(); - + ResultSet rs = stmt.executeQuery("SELECT * FROM " + tableName); - + Object[] expected = new Object[9]; - + expected[0] = 1234; expected[1] = false; expected[2] = "a"; @@ -259,29 +239,21 @@ public void testMixColumns() throws Exception { expected[6] = "b"; expected[7] = "varc"; expected[8] = "varcmax"; - + rs.next(); - for (int i=0; i < expected.length; i++) { + for (int i = 0; i < expected.length; i++) { if (null != rs.getObject(i + 1)) { - assertEquals(rs.getObject(i + 1).toString(), expected[i].toString()); + assertEquals(expected[i].toString(), rs.getObject(i + 1).toString()); } } } } - + @Test public void testNullOrEmptyColumns() throws Exception { - String valid = "INSERT INTO " + tableName + " (c1, c2, c3, c4, c5, c6, c7) values " - + "(" - + "?, " - + "?, " - + "?, " - + "?, " - + "?, " - + "?, " - + "?, " - + ")"; - + String valid = "INSERT INTO " + tableName + " (c1, c2, c3, c4, c5, c6, c7) values " + "(" + "?, " + "?, " + + "?, " + "?, " + "?, " + "?, " + "? " + ")"; + try (Connection connection = DriverManager.getConnection(connectionString + ";useBulkCopyForBatchInsert=true;"); SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection.prepareStatement(valid); Statement stmt = (SQLServerStatement) connection.createStatement();) { @@ -297,13 +269,13 @@ public void testNullOrEmptyColumns() throws Exception { pstmt.setFloat(6, (float) 123.45); pstmt.setString(7, ""); pstmt.addBatch(); - + pstmt.executeBatch(); - + ResultSet rs = stmt.executeQuery("SELECT * FROM " + tableName); - + Object[] expected = new Object[9]; - + expected[0] = 1234; expected[1] = false; expected[2] = null; @@ -311,31 +283,22 @@ public void testNullOrEmptyColumns() throws Exception { expected[4] = null; expected[5] = 123.45; expected[6] = " "; - + rs.next(); - for (int i=0; i < expected.length; i++) { + for (int i = 0; i < expected.length; i++) { if (null != rs.getObject(i + 1)) { - assertEquals(rs.getObject(i + 1), expected[i]); + assertEquals(expected[i], rs.getObject(i + 1)); } } } } - - @Test + + // Non-parameterized queries are not supported anymore. + // @Test public void testAllFilledColumns() throws Exception { - String valid = "INSERT INTO " + tableName + " values " - + "(" - + "1234, " - + "false, " - + "a, " - + "null, " - + "null, " - + "123.45, " - + "b, " - + "varc, " - + "sadf, " - + ")"; - + String valid = "INSERT INTO " + tableName + " values " + "(" + "1234, " + "false, " + "a, " + "null, " + + "null, " + "123.45, " + "b, " + "varc, " + "sadf, " + ")"; + try (Connection connection = DriverManager.getConnection(connectionString + ";useBulkCopyForBatchInsert=true;"); SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection.prepareStatement(valid); Statement stmt = (SQLServerStatement) connection.createStatement();) { @@ -344,13 +307,13 @@ public void testAllFilledColumns() throws Exception { f1.set(connection, true); pstmt.addBatch(); - + pstmt.executeBatch(); - + ResultSet rs = stmt.executeQuery("SELECT * FROM " + tableName); - + Object[] expected = new Object[9]; - + expected[0] = 1234; expected[1] = false; expected[2] = "a"; @@ -360,18 +323,18 @@ public void testAllFilledColumns() throws Exception { expected[6] = "b"; expected[7] = "varc"; expected[8] = "sadf"; - + rs.next(); - for (int i=0; i < expected.length; i++) { - assertEquals(rs.getObject(i + 1), expected[i]); + for (int i = 0; i < expected.length; i++) { + assertEquals(expected[i], rs.getObject(i + 1)); } } } - + @Test public void testSquareBracketAgainstDB() throws Exception { String valid = "insert into " + squareBracketTableName + " values (?)"; - + try (Connection connection = DriverManager.getConnection(connectionString + ";useBulkCopyForBatchInsert=true;"); SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection.prepareStatement(valid); Statement stmt = (SQLServerStatement) connection.createStatement();) { @@ -382,19 +345,19 @@ public void testSquareBracketAgainstDB() throws Exception { Utils.dropTableIfExists(squareBracketTableName, stmt); String createTable = "create table " + squareBracketTableName + " (c1 int)"; stmt.execute(createTable); - + pstmt.setInt(1, 1); pstmt.addBatch(); - + pstmt.executeBatch(); - + ResultSet rs = stmt.executeQuery("SELECT * FROM " + squareBracketTableName); rs.next(); - - assertEquals(rs.getObject(1), 1); + + assertEquals(1, rs.getObject(1)); } } - + @Test public void testDoubleQuoteAgainstDB() throws Exception { String valid = "insert into " + doubleQuoteTableName + " values (?)"; @@ -405,23 +368,23 @@ public void testDoubleQuoteAgainstDB() throws Exception { Field f1 = SQLServerConnection.class.getDeclaredField("isAzureDW"); f1.setAccessible(true); f1.set(connection, true); - + Utils.dropTableIfExists(doubleQuoteTableName, stmt); String createTable = "create table " + doubleQuoteTableName + " (c1 int)"; stmt.execute(createTable); - + pstmt.setInt(1, 1); pstmt.addBatch(); - + pstmt.executeBatch(); - + ResultSet rs = stmt.executeQuery("SELECT * FROM " + doubleQuoteTableName); rs.next(); - - assertEquals(rs.getObject(1), 1); + + assertEquals(1, rs.getObject(1)); } } - + @Test public void testSchemaAgainstDB() throws Exception { String schemaTableName = "\"dbo\" . /*some comment */ " + squareBracketTableName; @@ -433,24 +396,24 @@ public void testSchemaAgainstDB() throws Exception { Field f1 = SQLServerConnection.class.getDeclaredField("isAzureDW"); f1.setAccessible(true); f1.set(connection, true); - + Utils.dropTableIfExists("[dbo]." + squareBracketTableName, stmt); - + String createTable = "create table " + schemaTableName + " (c1 int)"; stmt.execute(createTable); - + pstmt.setInt(1, 1); pstmt.addBatch(); - + pstmt.executeBatch(); - + ResultSet rs = stmt.executeQuery("SELECT * FROM " + schemaTableName); rs.next(); - - assertEquals(rs.getObject(1), 1); + + assertEquals(1, rs.getObject(1)); } } - + @Test public void testColumnNameMixAgainstDB() throws Exception { String valid = "insert into " + squareBracketTableName + " ([c]]]]1], [c]]]]2]) values (?, 1)"; @@ -461,38 +424,28 @@ public void testColumnNameMixAgainstDB() throws Exception { Field f1 = SQLServerConnection.class.getDeclaredField("isAzureDW"); f1.setAccessible(true); f1.set(connection, true); - + Utils.dropTableIfExists(squareBracketTableName, stmt); String createTable = "create table " + squareBracketTableName + " ([c]]]]1] int, [c]]]]2] int)"; stmt.execute(createTable); - + pstmt.setInt(1, 1); pstmt.addBatch(); - + pstmt.executeBatch(); - + ResultSet rs = stmt.executeQuery("SELECT * FROM " + squareBracketTableName); rs.next(); - - assertEquals(rs.getObject(1), 1); + + assertEquals(1, rs.getObject(1)); } } - + @Test - public void testAlColumnsLargeBatch() throws Exception { - String valid = "INSERT INTO " + tableName + " values " - + "(" - + "?, " - + "?, " - + "?, " - + "?, " - + "?, " - + "?, " - + "?, " - + "?, " - + "?, " - + ")"; - + public void testAllColumnsLargeBatch() throws Exception { + String valid = "INSERT INTO " + tableName + " values " + "(" + "?, " + "?, " + "?, " + "?, " + "?, " + "?, " + + "?, " + "?, " + "? " + ")"; + try (Connection connection = DriverManager.getConnection(connectionString + ";useBulkCopyForBatchInsert=true;"); SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection.prepareStatement(valid); Statement stmt = (SQLServerStatement) connection.createStatement();) { @@ -501,9 +454,9 @@ public void testAlColumnsLargeBatch() throws Exception { f1.set(connection, true); Timestamp myTimestamp = new Timestamp(114550L); - + Date d = new Date(114550L); - + pstmt.setInt(1, 1234); pstmt.setBoolean(2, false); pstmt.setString(3, "a"); @@ -514,13 +467,13 @@ public void testAlColumnsLargeBatch() throws Exception { pstmt.setString(8, "varc"); pstmt.setString(9, "''"); pstmt.addBatch(); - + pstmt.executeLargeBatch(); - + ResultSet rs = stmt.executeQuery("SELECT * FROM " + tableName); - + Object[] expected = new Object[9]; - + expected[0] = 1234; expected[1] = false; expected[2] = "a"; @@ -530,37 +483,158 @@ public void testAlColumnsLargeBatch() throws Exception { expected[6] = "b"; expected[7] = "varc"; expected[8] = "''"; - + rs.next(); - for (int i=0; i < expected.length; i++) { - assertEquals(rs.getObject(i + 1).toString(), expected[i].toString()); + for (int i = 0; i < expected.length; i++) { + assertEquals(expected[i].toString(), rs.getObject(i + 1).toString()); } } } - + + @Test + public void testIllegalNumberOfArgNoColumnList() throws Exception { + String invalid = "insert into " + tableName + " values (?, ?,? ,?) "; + + try (Connection connection = DriverManager.getConnection(connectionString + ";useBulkCopyForBatchInsert=true;"); + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection.prepareStatement(invalid); + Statement stmt = (SQLServerStatement) connection.createStatement();) { + Field f1 = SQLServerConnection.class.getDeclaredField("isAzureDW"); + f1.setAccessible(true); + f1.set(connection, true); + + pstmt.setInt(1, 1); + pstmt.setInt(2, 1); + pstmt.setInt(3, 1); + pstmt.setInt(4, 1); + pstmt.addBatch(); + + pstmt.executeBatch(); + throw new Exception("Test did not throw an exception when it was expected."); + } catch (BatchUpdateException e) { + assertEquals("Column name or number of supplied values does not match table definition.", e.getMessage()); + } + + invalid = "insert into " + tableName + " (c1, c2, c3) values (?, ?,? ,?) "; + + try (Connection connection = DriverManager.getConnection(connectionString + ";useBulkCopyForBatchInsert=true;"); + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection.prepareStatement(invalid); + Statement stmt = (SQLServerStatement) connection.createStatement();) { + Field f1 = SQLServerConnection.class.getDeclaredField("isAzureDW"); + f1.setAccessible(true); + f1.set(connection, true); + + pstmt.setInt(1, 1); + pstmt.setInt(2, 1); + pstmt.setInt(3, 1); + pstmt.setInt(4, 1); + pstmt.addBatch(); + + pstmt.executeBatch(); + throw new Exception("Test did not throw an exception when it was expected."); + } catch (BatchUpdateException e) { + assertEquals( + "There are fewer columns in the INSERT statement than values specified in the VALUES clause. The number of values in the VALUES clause must match the number of columns specified in the INSERT statement.", + e.getMessage()); + } + } + + @Test + public void testNonParameterizedQuery() throws Exception { + String invalid = "insert into " + tableName + " values ((SELECT * from table where c1=?), ?,? ,?) "; + + try (Connection connection = DriverManager.getConnection(connectionString + ";useBulkCopyForBatchInsert=true;"); + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection.prepareStatement(invalid); + Statement stmt = (SQLServerStatement) connection.createStatement();) { + Field f1 = SQLServerConnection.class.getDeclaredField("isAzureDW"); + f1.setAccessible(true); + f1.set(connection, true); + + pstmt.setInt(1, 1); + pstmt.setInt(2, 1); + pstmt.setInt(3, 1); + pstmt.setInt(4, 1); + pstmt.addBatch(); + + pstmt.executeBatch(); + throw new Exception("Test did not throw an exception when it was expected."); + } catch (BatchUpdateException e) { + assertEquals("Incorrect syntax near the keyword 'table'.", e.getMessage()); + } + + invalid = "insert into " + tableName + " values ('?', ?,? ,?) "; + + try (Connection connection = DriverManager.getConnection(connectionString + ";useBulkCopyForBatchInsert=true;"); + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection.prepareStatement(invalid); + Statement stmt = (SQLServerStatement) connection.createStatement();) { + Field f1 = SQLServerConnection.class.getDeclaredField("isAzureDW"); + f1.setAccessible(true); + f1.set(connection, true); + + pstmt.setInt(1, 1); + pstmt.setInt(2, 1); + pstmt.setInt(3, 1); + pstmt.addBatch(); + + pstmt.executeBatch(); + throw new Exception("Test did not throw an exception when it was expected."); + } catch (BatchUpdateException e) { + assertEquals("Column name or number of supplied values does not match table definition.", e.getMessage()); + } + } + + @Test + public void testNonSupportedColumns() throws Exception { + String valid = "insert into " + unsupportedTableName + " values (?, ?, ?, ?)"; + + try (Connection connection = DriverManager.getConnection(connectionString + ";useBulkCopyForBatchInsert=true;"); + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection.prepareStatement(valid); + Statement stmt = (SQLServerStatement) connection.createStatement();) { + Field f1 = SQLServerConnection.class.getDeclaredField("isAzureDW"); + f1.setAccessible(true); + f1.set(connection, true); + + Utils.dropTableIfExists(unsupportedTableName, stmt); + + String createTable = "create table " + unsupportedTableName + + " (c1 geometry, c2 geography, c3 datetime, c4 smalldatetime)"; + stmt.execute(createTable); + + Timestamp myTimestamp = new Timestamp(1200000L); + Geometry g1 = Geometry.STGeomFromText("POINT(1 2 3 4)", 0); + Geography g2 = Geography.STGeomFromText("POINT(1 2 3 4)", 4326); + + pstmt.setGeometry(1, g1); + pstmt.setGeography(2, g2); + pstmt.setDateTime(3, myTimestamp); + pstmt.setSmallDateTime(4, myTimestamp); + pstmt.addBatch(); + + pstmt.executeBatch(); + + ResultSet rs = stmt.executeQuery("SELECT * FROM " + unsupportedTableName); + rs.next(); + assertEquals(g1.toString(), Geometry.STGeomFromWKB((byte[]) rs.getObject(1)).toString()); + assertEquals(g2.toString(), Geography.STGeomFromWKB((byte[]) rs.getObject(2)).toString()); + assertEquals(myTimestamp, rs.getObject(3)); + assertEquals(myTimestamp, rs.getObject(4)); + } + } + @BeforeEach public void testSetup() throws TestAbortedException, Exception { - try (Connection connection = DriverManager.getConnection(connectionString + ";useBulkCopyForBatchInsert=true;")) { + try (Connection connection = DriverManager + .getConnection(connectionString + ";useBulkCopyForBatchInsert=true;")) { try (Statement stmt = (SQLServerStatement) connection.createStatement()) { Utils.dropTableIfExists(tableName, stmt); - String sql1 = "create table " + tableName + " " - + "(" - + "c1 int DEFAULT 1234, " - + "c2 bit, " - + "c3 char DEFAULT NULL, " - + "c4 date, " - + "c5 datetime2, " - + "c6 float, " - + "c7 nchar, " - + "c8 varchar(20), " - + "c9 varchar(max)" - + ")"; - + String sql1 = "create table " + tableName + " " + "(" + "c1 int DEFAULT 1234, " + "c2 bit, " + + "c3 char DEFAULT NULL, " + "c4 date, " + "c5 datetime2, " + "c6 float, " + "c7 nchar, " + + "c8 varchar(20), " + "c9 varchar(max)" + ")"; + stmt.execute(sql1); } } } - + @AfterAll public static void terminateVariation() throws SQLException { try (Connection connection = DriverManager.getConnection(connectionString)) { @@ -568,6 +642,7 @@ public static void terminateVariation() throws SQLException { Utils.dropTableIfExists(tableName, stmt); Utils.dropTableIfExists(squareBracketTableName, stmt); Utils.dropTableIfExists(doubleQuoteTableName, stmt); + Utils.dropTableIfExists(unsupportedTableName, stmt); } } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/preparedStatement/BatchExecutionWithNullTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/preparedStatement/BatchExecutionWithNullTest.java index 4db2eec83..d8194ef46 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/preparedStatement/BatchExecutionWithNullTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/preparedStatement/BatchExecutionWithNullTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.preparedStatement; @@ -31,6 +28,7 @@ import com.microsoft.sqlserver.testframework.DBConnection; import com.microsoft.sqlserver.testframework.Utils; + @RunWith(JUnitPlatform.class) public class BatchExecutionWithNullTest extends AbstractTest { @@ -41,8 +39,8 @@ public class BatchExecutionWithNullTest extends AbstractTest { static ResultSet rs = null; /** - * Test with combination of setString and setNull which cause the "Violation of PRIMARY KEY constraint and internally "Could not find prepared - * statement with handle X" error. + * Test with combination of setString and setNull which cause the "Violation of PRIMARY KEY constraint and + * internally "Could not find prepared statement with handle X" error. * * @throws SQLException */ @@ -120,7 +118,7 @@ public void testSetup() throws TestAbortedException, Exception { @AfterAll public static void terminateVariation() throws SQLException { connection = DriverManager.getConnection(connectionString); - + SQLServerStatement stmt = (SQLServerStatement) connection.createStatement(); Utils.dropTableIfExists("esimple", stmt); diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/preparedStatement/RegressionTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/preparedStatement/RegressionTest.java index 2596042f2..e8a7b7008 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/preparedStatement/RegressionTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/preparedStatement/RegressionTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.preparedStatement; @@ -26,9 +23,10 @@ import org.junit.runner.RunWith; import com.microsoft.sqlserver.jdbc.SQLServerConnection; +import com.microsoft.sqlserver.jdbc.TestResource; import com.microsoft.sqlserver.testframework.AbstractTest; import com.microsoft.sqlserver.testframework.Utils; -import com.microsoft.sqlserver.jdbc.TestResource; + /** * Tests with sql queries using preparedStatement without parameters @@ -70,9 +68,9 @@ public void createViewTest() throws SQLException { pstmt2 = con.prepareStatement("drop view x"); pstmt1.execute(); pstmt2.execute(); - } - catch (SQLException e) { - fail(TestResource.getResource("R_createDropViewFailed") + TestResource.getResource("R_errorMessage") + e.getMessage()); + } catch (SQLException e) { + fail(TestResource.getResource("R_createDropViewFailed") + TestResource.getResource("R_errorMessage") + + e.getMessage()); } finally { @@ -97,9 +95,9 @@ public void createSchemaTest() throws SQLException { pstmt2 = con.prepareStatement("drop schema x"); pstmt1.execute(); pstmt2.execute(); - } - catch (SQLException e) { - fail(TestResource.getResource("R_createDropSchemaFailed") + TestResource.getResource("R_errorMessage") + e.getMessage()); + } catch (SQLException e) { + fail(TestResource.getResource("R_createDropSchemaFailed") + TestResource.getResource("R_errorMessage") + + e.getMessage()); } finally { @@ -124,9 +122,9 @@ public void createTableTest() throws SQLException { pstmt2 = con.prepareStatement("drop table x"); pstmt1.execute(); pstmt2.execute(); - } - catch (SQLException e) { - fail(TestResource.getResource("R_createDropTableFailed") + TestResource.getResource("R_errorMessage") + e.getMessage()); + } catch (SQLException e) { + fail(TestResource.getResource("R_createDropTableFailed") + TestResource.getResource("R_errorMessage") + + e.getMessage()); } finally { @@ -153,9 +151,9 @@ public void alterTableTest() throws SQLException { pstmt1.execute(); pstmt2.execute(); pstmt3.execute(); - } - catch (SQLException e) { - fail(TestResource.getResource("R_createDropAlterTableFailed") + TestResource.getResource("R_errorMessage") + e.getMessage()); + } catch (SQLException e) { + fail(TestResource.getResource("R_createDropAlterTableFailed") + TestResource.getResource("R_errorMessage") + + e.getMessage()); } finally { @@ -187,9 +185,9 @@ public void grantTest() throws SQLException { pstmt2.execute(); pstmt3.execute(); pstmt4.execute(); - } - catch (SQLException e) { - fail(TestResource.getResource("R_grantFailed") + TestResource.getResource("R_errorMessage") + e.getMessage()); + } catch (SQLException e) { + fail(TestResource.getResource("R_grantFailed") + TestResource.getResource("R_errorMessage") + + e.getMessage()); } finally { @@ -217,12 +215,12 @@ public void grantTest() throws SQLException { public void batchWithLargeStringTest() throws Exception { batchWithLargeStringTestInternal("BatchInsert"); } - + @Test public void batchWithLargeStringTestUseBulkCopyAPI() throws Exception { batchWithLargeStringTestInternal("BulkCopy"); } - + private void batchWithLargeStringTestInternal(String mode) throws Exception { try (Connection con = DriverManager.getConnection(connectionString);) { if (mode.equalsIgnoreCase("bulkcopy")) { @@ -242,12 +240,10 @@ private void batchWithLargeStringTestInternal(String mode) throws Exception { stmt.execute("if object_id('TEST_TABLE', 'U') is not null\ndrop table TEST_TABLE;"); if (createPrimaryKey) { stmt.execute("create table TEST_TABLE ( ID int, DATA nvarchar(max), primary key (ID) );"); - } - else { + } else { stmt.execute("create table TEST_TABLE ( ID int, DATA nvarchar(max) );"); } - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } @@ -290,8 +286,7 @@ private void batchWithLargeStringTestInternal(String mode) throws Exception { pstmt.addBatch(); pstmt.executeBatch(); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } con.commit(); @@ -308,18 +303,17 @@ private void batchWithLargeStringTestInternal(String mode) throws Exception { id = rs.getInt(1); String data = rs.getNString(2); if (selectedValues.containsKey(id)) { - fail("Found duplicate id: " + id + " ,actual values is : " + values[i++] + " data is: " + data); + fail("Found duplicate id: " + id + " ,actual values is : " + values[i++] + " data is: " + + data); } selectedValues.put(id, data); } - } - finally { + } finally { if (null != rs) { rs.close(); } } - } - finally { + } finally { Utils.dropTableIfExists("TEST_TABLE", stmt); if (null != pstmt) { pstmt.close(); @@ -330,7 +324,7 @@ private void batchWithLargeStringTestInternal(String mode) throws Exception { } } } - + /** * Test with large string and tests with more batch queries * @@ -350,12 +344,10 @@ public void addBatchWithLargeStringTest() throws SQLException { stmt.execute("if object_id('testTable', 'U') is not null\ndrop table testTable;"); if (createPrimaryKey) { stmt.execute("create table testTable ( ID int, DATA nvarchar(max), primary key (ID) );"); - } - else { + } else { stmt.execute("create table testTable ( ID int, DATA nvarchar(max) );"); } - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } con.commit(); @@ -417,8 +409,7 @@ public void addBatchWithLargeStringTest() throws SQLException { catch (Exception e) { fail(e.toString()); - } - finally { + } finally { Utils.dropTableIfExists("testTable", stmt); if (null != stmt) { stmt.close(); @@ -455,7 +446,7 @@ private void modifyConnectionForBulkCopyAPI(SQLServerConnection con) throws Exce Field f1 = SQLServerConnection.class.getDeclaredField("isAzureDW"); f1.setAccessible(true); f1.set(con, true); - + con.setUseBulkCopyForBatchInsert(true); } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/resultset/DataClassificationTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/resultset/DataClassificationTest.java index 759eb167d..a59187826 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/resultset/DataClassificationTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/resultset/DataClassificationTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.resultset; @@ -12,6 +9,7 @@ import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Statement; + import org.junit.jupiter.api.Test; import org.junit.platform.runner.JUnitPlatform; import org.junit.runner.RunWith; @@ -23,6 +21,7 @@ import com.microsoft.sqlserver.testframework.util.RandomUtil; import com.microsoft.sqlserver.testframework.util.Util; + @RunWith(JUnitPlatform.class) public class DataClassificationTest extends AbstractTest { private static final String tableName = "[" + RandomUtil.getIdentifier("DataClassification") + "]"; @@ -35,7 +34,8 @@ public class DataClassificationTest extends AbstractTest { @Test public void testDataClassificationMetadata() throws Exception { // Run this test only with newer SQL Servers (version>=2018) that support Data Classification - try (Connection con = DriverManager.getConnection(connectionString); Statement stmt = connection.createStatement();) { + try (Connection con = DriverManager.getConnection(connectionString); + Statement stmt = connection.createStatement();) { if (Util.serverSupportsDataClassification(stmt)) { createTable(connection, stmt); runTestsForServer(stmt); @@ -51,11 +51,12 @@ public void testDataClassificationMetadata() throws Exception { * @param stmt * @throws SQLException */ - private void createTable(Connection connection, - Statement stmt) throws SQLException { - String createQuery = "CREATE TABLE " + tableName + " (" + "[Id] [int] IDENTITY(1,1) NOT NULL," + "[CompanyName] [nvarchar](40) NOT NULL," - + "[ContactName] [nvarchar](50) NULL," + "[ContactTitle] [nvarchar](40) NULL," + "[City] [nvarchar](40) NULL," - + "[Country] [nvarchar](40) NULL," + "[Phone] [nvarchar](30) MASKED WITH (FUNCTION = 'default()') NULL," + private void createTable(Connection connection, Statement stmt) throws SQLException { + String createQuery = "CREATE TABLE " + tableName + " (" + "[Id] [int] IDENTITY(1,1) NOT NULL," + + "[CompanyName] [nvarchar](40) NOT NULL," + "[ContactName] [nvarchar](50) NULL," + + "[ContactTitle] [nvarchar](40) NULL," + "[City] [nvarchar](40) NULL," + + "[CountryName] [nvarchar](40) NULL," + + "[Phone] [nvarchar](30) MASKED WITH (FUNCTION = 'default()') NULL," + "[Fax] [nvarchar](30) MASKED WITH (FUNCTION = 'default()') NULL)"; stmt.execute(createQuery); @@ -69,7 +70,8 @@ private void createTable(Connection connection, + ".Fax WITH (LABEL='PII', LABEL_ID='L1', INFORMATION_TYPE='Contact Information', INFORMATION_TYPE_ID='CONTACT')"); // INSERT ROWS OF DATA - try (PreparedStatement ps = connection.prepareStatement("INSERT INTO " + tableName + " VALUES (?,?,?,?,?,?,?)")) { + try (PreparedStatement ps = connection + .prepareStatement("INSERT INTO " + tableName + " VALUES (?,?,?,?,?,?,?)")) { ps.setString(1, "Exotic Liquids"); ps.setString(2, "Charlotte Cooper"); @@ -120,17 +122,21 @@ private void runTestsForServer(Statement stmt) throws Exception { */ private void verifySensitivityClassification(SQLServerResultSet rs) throws SQLException { if (null != rs.getSensitivityClassification()) { - for (int columnPos = 0; columnPos < rs.getSensitivityClassification().getColumnSensitivities().size(); columnPos++) { - for (SensitivityProperty sp : rs.getSensitivityClassification().getColumnSensitivities().get(columnPos).getSensitivityProperties()) { + for (int columnPos = 0; columnPos < rs.getSensitivityClassification().getColumnSensitivities().size(); + columnPos++) { + for (SensitivityProperty sp : rs.getSensitivityClassification().getColumnSensitivities().get(columnPos) + .getSensitivityProperties()) { if (columnPos == 1 || columnPos == 2 || columnPos == 6 || columnPos == 7) { assert (sp.getLabel() != null); assert (sp.getLabel().getId().equalsIgnoreCase("L1")); assert (sp.getLabel().getName().equalsIgnoreCase("PII")); assert (sp.getInformationType() != null); - assert (sp.getInformationType().getId().equalsIgnoreCase(columnPos == 1 ? "COMPANY" : (columnPos == 2 ? "NAME" : "CONTACT"))); - assert (sp.getInformationType().getName() - .equalsIgnoreCase(columnPos == 1 ? "Company name" : (columnPos == 2 ? "Person Name" : "Contact Information"))); + assert (sp.getInformationType().getId() + .equalsIgnoreCase(columnPos == 1 ? "COMPANY" : (columnPos == 2 ? "NAME" : "CONTACT"))); + assert (sp.getInformationType().getName().equalsIgnoreCase( + columnPos == 1 ? "Company name" + : (columnPos == 2 ? "Person Name" : "Contact Information"))); } } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/resultset/ResultSetTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/resultset/ResultSetTest.java index 51ad18c6e..8add5c13c 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/resultset/ResultSetTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/resultset/ResultSetTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.resultset; @@ -35,6 +32,7 @@ import com.microsoft.sqlserver.testframework.Utils; import com.microsoft.sqlserver.testframework.util.RandomUtil; + @RunWith(JUnitPlatform.class) public class ResultSetTest extends AbstractTest { private static final String tableName = "[" + RandomUtil.getIdentifier("StatementParam") + "]"; @@ -46,30 +44,16 @@ public class ResultSetTest extends AbstractTest { */ @Test public void testJdbc41ResultSetMethods() throws SQLException { - try (Connection con = DriverManager.getConnection(connectionString); - Statement stmt = con.createStatement()) { - stmt.executeUpdate("create table " + tableName + " ( " - + "col1 int, " - + "col2 varchar(512), " - + "col3 float, " - + "col4 decimal(10,5), " - + "col5 uniqueidentifier, " - + "col6 xml, " - + "col7 varbinary(max), " - + "col8 text, " - + "col9 ntext, " - + "col10 varbinary(max), " - + "col11 date, " - + "col12 time, " - + "col13 datetime2, " - + "col14 datetimeoffset, " - + "col15 decimal(10,9), " - + "col16 decimal(38,38), " + try (Connection con = DriverManager.getConnection(connectionString); Statement stmt = con.createStatement()) { + stmt.executeUpdate("create table " + tableName + " ( " + "col1 int, " + "col2 varchar(512), " + + "col3 float, " + "col4 decimal(10,5), " + "col5 uniqueidentifier, " + "col6 xml, " + + "col7 varbinary(max), " + "col8 text, " + "col9 ntext, " + "col10 varbinary(max), " + + "col11 date, " + "col12 time, " + "col13 datetime2, " + "col14 datetimeoffset, " + + "col15 decimal(10,9), " + "col16 decimal(38,38), " + "order_column int identity(1,1) primary key)"); try { - - stmt.executeUpdate("Insert into " + tableName + " values(" - + "1, " // col1 + + stmt.executeUpdate("Insert into " + tableName + " values(" + "1, " // col1 + "'hello', " // col2 + "2.0, " // col3 + "123.45, " // col4 @@ -86,25 +70,11 @@ public void testJdbc41ResultSetMethods() throws SQLException { + "0.123456789, " // col15 + "0.1234567890123456789012345678901234567" // col16 + ")"); - - stmt.executeUpdate("Insert into " + tableName + " values(" - + "null, " - + "null, " - + "null, " - + "null, " - + "null, " - + "null, " - + "null, " - + "null, " - + "null, " - + "null, " - + "null, " - + "null, " - + "null, " - + "null, " - + "null, " - + "null)"); - + + stmt.executeUpdate("Insert into " + tableName + " values(" + "null, " + "null, " + "null, " + "null, " + + "null, " + "null, " + "null, " + "null, " + "null, " + "null, " + "null, " + "null, " + + "null, " + "null, " + "null, " + "null)"); + try (ResultSet rs = stmt.executeQuery("select * from " + tableName + " order by order_column")) { // test non-null values assertTrue(rs.next()); @@ -132,7 +102,8 @@ public void testJdbc41ResultSetMethods() throws SQLException { assertEquals(0, rs.getObject("col4", BigDecimal.class).compareTo(new BigDecimal("123.45"))); assertEquals(UUID.fromString("6F9619FF-8B86-D011-B42D-00C04FC964FF"), rs.getObject(5, UUID.class)); - assertEquals(UUID.fromString("6F9619FF-8B86-D011-B42D-00C04FC964FF"), rs.getObject("col5", UUID.class)); + assertEquals(UUID.fromString("6F9619FF-8B86-D011-B42D-00C04FC964FF"), + rs.getObject("col5", UUID.class)); SQLXML sqlXml; sqlXml = rs.getObject(6, SQLXML.class); @@ -145,7 +116,9 @@ public void testJdbc41ResultSetMethods() throws SQLException { Blob blob; blob = rs.getObject(7, Blob.class); try { - assertArrayEquals(new byte[] {0x63, (byte) 0xC3, 0x4D, 0x6B, (byte) 0xCA, (byte) 0xD5, 0x55, (byte) 0xEB, 0x64, (byte) 0xBF, 0x7E, (byte) 0x84, (byte) 0x8D, 0x02, (byte) 0xC3, 0x76}, + assertArrayEquals( + new byte[] {0x63, (byte) 0xC3, 0x4D, 0x6B, (byte) 0xCA, (byte) 0xD5, 0x55, (byte) 0xEB, + 0x64, (byte) 0xBF, 0x7E, (byte) 0x84, (byte) 0x8D, 0x02, (byte) 0xC3, 0x76}, blob.getBytes(1, 16)); } finally { blob.free(); @@ -167,7 +140,9 @@ public void testJdbc41ResultSetMethods() throws SQLException { nclob.free(); } - assertArrayEquals(new byte[] {0x63, (byte) 0xC3, 0x4D, 0x6B, (byte) 0xCA, (byte) 0xD5, 0x55, (byte) 0xEB, 0x64, (byte) 0xBF, 0x7E, (byte) 0x84, (byte) 0x8D, 0x02, (byte) 0xC3, 0x76}, + assertArrayEquals( + new byte[] {0x63, (byte) 0xC3, 0x4D, 0x6B, (byte) 0xCA, (byte) 0xD5, 0x55, (byte) 0xEB, + 0x64, (byte) 0xBF, 0x7E, (byte) 0x84, (byte) 0x8D, 0x02, (byte) 0xC3, 0x76}, rs.getObject(10, byte[].class)); assertEquals(java.sql.Date.valueOf("2017-05-19"), rs.getObject(11, java.sql.Date.class)); @@ -177,18 +152,25 @@ public void testJdbc41ResultSetMethods() throws SQLException { assertEquals(expectedTime, rs.getObject(12, java.sql.Time.class)); assertEquals(expectedTime, rs.getObject("col12", java.sql.Time.class)); - assertEquals(java.sql.Timestamp.valueOf("2017-05-19 10:47:15.1234567"), rs.getObject(13, java.sql.Timestamp.class)); - assertEquals(java.sql.Timestamp.valueOf("2017-05-19 10:47:15.1234567"), rs.getObject("col13", java.sql.Timestamp.class)); + assertEquals(java.sql.Timestamp.valueOf("2017-05-19 10:47:15.1234567"), + rs.getObject(13, java.sql.Timestamp.class)); + assertEquals(java.sql.Timestamp.valueOf("2017-05-19 10:47:15.1234567"), + rs.getObject("col13", java.sql.Timestamp.class)); - assertEquals("2017-05-19 10:47:15.1234567 +02:00", rs.getObject(14, microsoft.sql.DateTimeOffset.class).toString()); - assertEquals("2017-05-19 10:47:15.1234567 +02:00", rs.getObject("col14", microsoft.sql.DateTimeOffset.class).toString()); - - // BigDecimal#equals considers the number of decimal places (ResultSet returns all digits after decimal unlike CallableStatement outparams) + assertEquals("2017-05-19 10:47:15.1234567 +02:00", + rs.getObject(14, microsoft.sql.DateTimeOffset.class).toString()); + assertEquals("2017-05-19 10:47:15.1234567 +02:00", + rs.getObject("col14", microsoft.sql.DateTimeOffset.class).toString()); + + // BigDecimal#equals considers the number of decimal places (ResultSet returns all digits after + // decimal unlike CallableStatement outparams) assertEquals(0, rs.getObject(15, BigDecimal.class).compareTo(new BigDecimal("0.123456789"))); assertEquals(0, rs.getObject("col15", BigDecimal.class).compareTo(new BigDecimal("0.123456789"))); - - assertEquals(0, rs.getObject(16, BigDecimal.class).compareTo(new BigDecimal("0.12345678901234567890123456789012345670"))); - assertEquals(0, rs.getObject("col16", BigDecimal.class).compareTo(new BigDecimal("0.12345678901234567890123456789012345670"))); + + assertEquals(0, rs.getObject(16, BigDecimal.class) + .compareTo(new BigDecimal("0.12345678901234567890123456789012345670"))); + assertEquals(0, rs.getObject("col16", BigDecimal.class) + .compareTo(new BigDecimal("0.12345678901234567890123456789012345670"))); // test null values, mostly to verify primitive wrappers do not return default values assertTrue(rs.next()); @@ -231,13 +213,13 @@ public void testJdbc41ResultSetMethods() throws SQLException { assertNull(rs.getObject(10, byte[].class)); assertNull(rs.getObject("col10", byte[].class)); - + assertNull(rs.getObject(11, java.sql.Date.class)); assertNull(rs.getObject("col11", java.sql.Date.class)); - + assertNull(rs.getObject(12, java.sql.Time.class)); assertNull(rs.getObject("col12", java.sql.Time.class)); - + assertNull(rs.getObject(13, java.sql.Timestamp.class)); assertNull(rs.getObject("col14", java.sql.Timestamp.class)); @@ -246,10 +228,10 @@ public void testJdbc41ResultSetMethods() throws SQLException { assertNull(rs.getObject(15, BigDecimal.class)); assertNull(rs.getObject("col15", BigDecimal.class)); - + assertNull(rs.getObject(16, BigDecimal.class)); assertNull(rs.getObject("col16", BigDecimal.class)); - + assertFalse(rs.next()); } } finally { @@ -265,11 +247,11 @@ public void testJdbc41ResultSetMethods() throws SQLException { */ @Test public void testResultSetWrapper() throws SQLException { - try (Connection con = DriverManager.getConnection(connectionString); - Statement stmt = con.createStatement()) { - - stmt.executeUpdate("create table " + tableName + " (col1 int, col2 text, col3 int identity(1,1) primary key)"); - + try (Connection con = DriverManager.getConnection(connectionString); Statement stmt = con.createStatement()) { + + stmt.executeUpdate( + "create table " + tableName + " (col1 int, col2 text, col3 int identity(1,1) primary key)"); + try (ResultSet rs = stmt.executeQuery("select * from " + tableName)) { assertTrue(rs.isWrapperFor(ResultSet.class)); assertTrue(rs.isWrapperFor(ISQLServerResultSet.class)); @@ -281,7 +263,7 @@ public void testResultSetWrapper() throws SQLException { } } } - + /** * Tests calling any getter on a null column should work regardless of their type. * @@ -298,8 +280,7 @@ public void testGetterOnNull() throws SQLException { rs = stmt.executeQuery("select null"); rs.next(); assertEquals(null, rs.getTime(1)); - } - finally { + } finally { if (con != null) { con.close(); } @@ -311,5 +292,5 @@ public void testGetterOnNull() throws SQLException { } } } - + } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/ssl/trustmanager/CustomTrustManagerTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/ssl/trustmanager/CustomTrustManagerTest.java index deec89c8f..b60ff3b1d 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/ssl/trustmanager/CustomTrustManagerTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/ssl/trustmanager/CustomTrustManagerTest.java @@ -1,17 +1,16 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.ssl.trustmanager; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + import java.sql.DriverManager; import java.sql.SQLException; -import static org.junit.Assert.*; import org.junit.jupiter.api.Test; import org.junit.platform.runner.JUnitPlatform; import org.junit.runner.RunWith; @@ -19,6 +18,7 @@ import com.microsoft.sqlserver.jdbc.SQLServerConnection; import com.microsoft.sqlserver.testframework.AbstractTest; + @RunWith(JUnitPlatform.class) public class CustomTrustManagerTest extends AbstractTest { @@ -29,7 +29,8 @@ public class CustomTrustManagerTest extends AbstractTest { */ @Test public void testWithPermissiveX509TrustManager() throws Exception { - String url = connectionString + ";trustManagerClass=" + PermissiveTrustManager.class.getName() + ";encrypt=true;"; + String url = connectionString + ";trustManagerClass=" + PermissiveTrustManager.class.getName() + + ";encrypt=true;"; try (SQLServerConnection con = (SQLServerConnection) DriverManager.getConnection(url)) { assertTrue(con != null); } @@ -59,9 +60,9 @@ public void testWithInvalidTrustManager() throws Exception { String url = connectionString + ";trustManagerClass=" + InvalidTrustManager.class.getName() + ";encrypt=true;"; try (SQLServerConnection con = (SQLServerConnection) DriverManager.getConnection(url)) { fail(); - } - catch (SQLException e) { - assertTrue(e.getMessage().contains("The class specified by the trustManagerClass property must implement javax.net.ssl.TrustManager")); + } catch (SQLException e) { + assertTrue(e.getMessage().contains( + "The class specified by the trustManagerClass property must implement javax.net.ssl.TrustManager")); } } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/ssl/trustmanager/InvalidTrustManager.java b/src/test/java/com/microsoft/sqlserver/jdbc/ssl/trustmanager/InvalidTrustManager.java index c657b967e..83cbf3894 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/ssl/trustmanager/InvalidTrustManager.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/ssl/trustmanager/InvalidTrustManager.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.ssl.trustmanager; @@ -11,22 +8,20 @@ import java.security.cert.CertificateException; import java.security.cert.X509Certificate; + /** - * This class does not implement X509TrustManager and the connection must fail when it is specified by the trustManagerClass property + * This class does not implement X509TrustManager and the connection must fail when it is specified by the + * trustManagerClass property * */ public final class InvalidTrustManager { - public InvalidTrustManager() { - } + public InvalidTrustManager() {} - public void checkClientTrusted(X509Certificate[] chain, - String authType) throws CertificateException { + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } - public void checkServerTrusted(X509Certificate[] chain, - String authType) throws CertificateException { - } + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {} public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/ssl/trustmanager/PermissiveTrustManager.java b/src/test/java/com/microsoft/sqlserver/jdbc/ssl/trustmanager/PermissiveTrustManager.java index 12186ee7e..0f2e0a5a3 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/ssl/trustmanager/PermissiveTrustManager.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/ssl/trustmanager/PermissiveTrustManager.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.ssl.trustmanager; @@ -13,18 +10,15 @@ import javax.net.ssl.X509TrustManager; + /** * This class implements an X509TrustManager that always accepts the X509Certificate chain offered to it. */ public final class PermissiveTrustManager implements X509TrustManager { - public void checkClientTrusted(X509Certificate[] chain, - String authType) throws CertificateException { - } + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {} - public void checkServerTrusted(X509Certificate[] chain, - String authType) throws CertificateException { - } + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {} public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/ssl/trustmanager/TrustManagerWithConstructorArg.java b/src/test/java/com/microsoft/sqlserver/jdbc/ssl/trustmanager/TrustManagerWithConstructorArg.java index 09b5a3a80..d360c4c66 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/ssl/trustmanager/TrustManagerWithConstructorArg.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/ssl/trustmanager/TrustManagerWithConstructorArg.java @@ -1,20 +1,18 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.ssl.trustmanager; import java.io.IOException; - +import java.security.GeneralSecurityException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; -import java.security.GeneralSecurityException; + import javax.net.ssl.X509TrustManager; + /** * This class implements an X509TrustManager that always accepts the X509Certificate chain offered to it. * @@ -34,26 +32,18 @@ public X509Certificate[] getAcceptedIssuers() { } @Override - public void checkServerTrusted(X509Certificate[] chain, - String authType) throws CertificateException { - } + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {} @Override - public void checkClientTrusted(X509Certificate[] chain, - String authType) throws CertificateException { - } + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {} }; } @Override - public void checkClientTrusted(X509Certificate[] chain, - String authType) throws CertificateException { - } + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {} @Override - public void checkServerTrusted(X509Certificate[] chain, - String authType) throws CertificateException { - } + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {} @Override public X509Certificate[] getAcceptedIssuers() { diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPAllTypes.java b/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPAllTypes.java index 4b33f124e..210d73e87 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPAllTypes.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPAllTypes.java @@ -1,217 +1,210 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ -package com.microsoft.sqlserver.jdbc.tvp; - -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -import org.junit.jupiter.api.Test; -import org.junit.platform.runner.JUnitPlatform; -import org.junit.runner.RunWith; - -import com.microsoft.sqlserver.jdbc.SQLServerCallableStatement; -import com.microsoft.sqlserver.jdbc.SQLServerDataTable; -import com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement; -import com.microsoft.sqlserver.testframework.AbstractTest; -import com.microsoft.sqlserver.testframework.DBConnection; -import com.microsoft.sqlserver.testframework.DBStatement; -import com.microsoft.sqlserver.testframework.DBTable; -import com.microsoft.sqlserver.testframework.Utils; -import com.microsoft.sqlserver.testframework.sqlType.SqlType; -import com.microsoft.sqlserver.testframework.util.ComparisonUtil; - -@RunWith(JUnitPlatform.class) -public class TVPAllTypes extends AbstractTest { - private static Connection conn = null; - static Statement stmt = null; - - private static String tvpName = "TVPAllTypesTable_char_TVP"; - private static String procedureName = "TVPAllTypesTable_char_SP"; - - private static DBTable tableSrc = null; - private static DBTable tableDest = null; - - /** - * Test TVP with result set - * - * @throws SQLException - */ - @Test - public void testTVPResultSet() throws SQLException { - testTVPResultSet(false, null, null); - testTVPResultSet(true, null, null); - testTVPResultSet(false, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); - testTVPResultSet(false, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); - testTVPResultSet(false, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); - testTVPResultSet(false, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); - } - - private void testTVPResultSet(boolean setSelectMethod, - Integer resultSetType, - Integer resultSetConcurrency) throws SQLException { - setupVariation(); - - Connection connnection = null; - if (setSelectMethod) { - connnection = DriverManager.getConnection(connectionString + ";selectMethod=cursor;"); - } - else { - connnection = DriverManager.getConnection(connectionString); - } - - Statement stmtement = null; - if (null != resultSetType || null != resultSetConcurrency) { - stmtement = connnection.createStatement(resultSetType, resultSetConcurrency); - } - else { - stmtement = connnection.createStatement(); - } - - ResultSet rs = stmtement.executeQuery("select * from " + tableSrc.getEscapedTableName()); - - SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connnection - .prepareStatement("INSERT INTO " + tableDest.getEscapedTableName() + " select * from ? ;"); - pstmt.setStructured(1, tvpName, rs); - pstmt.execute(); - - ComparisonUtil.compareSrcTableAndDestTableIgnoreRowOrder(new DBConnection(connectionString), tableSrc, tableDest); - - terminateVariation(); - } - - /** - * Test TVP with stored procedure and result set - * - * @throws SQLException - */ - @Test - public void testTVPStoredProcedureResultSet() throws SQLException { - testTVPStoredProcedureResultSet(false, null, null); - testTVPStoredProcedureResultSet(true, null, null); - testTVPStoredProcedureResultSet(false, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); - testTVPStoredProcedureResultSet(false, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); - testTVPStoredProcedureResultSet(false, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); - testTVPStoredProcedureResultSet(false, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); - } - - private void testTVPStoredProcedureResultSet(boolean setSelectMethod, - Integer resultSetType, - Integer resultSetConcurrency) throws SQLException { - setupVariation(); - - Connection connnection = null; - if (setSelectMethod) { - connnection = DriverManager.getConnection(connectionString + ";selectMethod=cursor;"); - } - else { - connnection = DriverManager.getConnection(connectionString); - } - - Statement stmtement = null; - if (null != resultSetType || null != resultSetConcurrency) { - stmtement = connnection.createStatement(resultSetType, resultSetConcurrency); - } - else { - stmtement = connnection.createStatement(); - } - - ResultSet rs = stmtement.executeQuery("select * from " + tableSrc.getEscapedTableName()); - - String sql = "{call " + procedureName + "(?)}"; - SQLServerCallableStatement Cstmt = (SQLServerCallableStatement) connnection.prepareCall(sql); - Cstmt.setStructured(1, tvpName, rs); - Cstmt.execute(); - - ComparisonUtil.compareSrcTableAndDestTableIgnoreRowOrder(new DBConnection(connectionString), tableSrc, tableDest); - - terminateVariation(); - } - - /** - * Test TVP with DataTable - * - * @throws SQLException - */ - @Test - public void testTVPDataTable() throws SQLException { - setupVariation(); - - SQLServerDataTable dt = new SQLServerDataTable(); - - int numberOfColumns = tableDest.getColumns().size(); - Object[] values = new Object[numberOfColumns]; - for (int i = 0; i < numberOfColumns; i++) { - SqlType sqlType = tableDest.getColumns().get(i).getSqlType(); - dt.addColumnMetadata(tableDest.getColumnName(i), sqlType.getJdbctype().getVendorTypeNumber()); - values[i] = sqlType.createdata(); - } - - int numberOfRows = 10; - for (int i = 0; i < numberOfRows; i++) { - dt.addRow(values); - } - - SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection - .prepareStatement("INSERT INTO " + tableDest.getEscapedTableName() + " select * from ? ;"); - pstmt.setStructured(1, tvpName, dt); - pstmt.execute(); - } - - private static void createPreocedure(String procedureName, - String destTable) throws SQLException { - String sql = "CREATE PROCEDURE " + procedureName + " @InputData " + tvpName + " READONLY " + " AS " + " BEGIN " + " INSERT INTO " + destTable - + " SELECT * FROM @InputData" + " END"; - - stmt.execute(sql); - } - - private static void dropTVPS(String tvpName) throws SQLException { - stmt.executeUpdate("IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvpName + "') " + " drop type " + tvpName); - } - - private static void createTVPS(String TVPName, - String TVPDefinition) throws SQLException { - String TVPCreateCmd = "CREATE TYPE " + TVPName + " as table (" + TVPDefinition + ");"; - stmt.executeUpdate(TVPCreateCmd); - } - - private void setupVariation() throws SQLException { - conn = DriverManager.getConnection(connectionString); - stmt = conn.createStatement(); - - Utils.dropProcedureIfExists(procedureName, stmt); - dropTVPS(tvpName); - - DBConnection dbConnection = new DBConnection(connectionString); - DBStatement dbStmt = dbConnection.createStatement(); - - tableSrc = new DBTable(true); - tableDest = tableSrc.cloneSchema(); - - dbStmt.createTable(tableSrc); - dbStmt.createTable(tableDest); - - createTVPS(tvpName, tableSrc.getDefinitionOfColumns()); - createPreocedure(procedureName, tableDest.getEscapedTableName()); - - dbStmt.populateTable(tableSrc); - } - - private void terminateVariation() throws SQLException { - conn = DriverManager.getConnection(connectionString); - stmt = conn.createStatement(); - - Utils.dropProcedureIfExists(procedureName, stmt); - Utils.dropTableIfExists(tableSrc.getEscapedTableName(), stmt); - Utils.dropTableIfExists(tableDest.getEscapedTableName(), stmt); - dropTVPS(tvpName); - } -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package com.microsoft.sqlserver.jdbc.tvp; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +import org.junit.jupiter.api.Test; +import org.junit.platform.runner.JUnitPlatform; +import org.junit.runner.RunWith; + +import com.microsoft.sqlserver.jdbc.SQLServerCallableStatement; +import com.microsoft.sqlserver.jdbc.SQLServerDataTable; +import com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement; +import com.microsoft.sqlserver.testframework.AbstractTest; +import com.microsoft.sqlserver.testframework.DBConnection; +import com.microsoft.sqlserver.testframework.DBStatement; +import com.microsoft.sqlserver.testframework.DBTable; +import com.microsoft.sqlserver.testframework.Utils; +import com.microsoft.sqlserver.testframework.sqlType.SqlType; +import com.microsoft.sqlserver.testframework.util.ComparisonUtil; + + +@RunWith(JUnitPlatform.class) +public class TVPAllTypes extends AbstractTest { + private static Connection conn = null; + static Statement stmt = null; + + private static String tvpName = "TVPAllTypesTable_char_TVP"; + private static String procedureName = "TVPAllTypesTable_char_SP"; + + private static DBTable tableSrc = null; + private static DBTable tableDest = null; + + /** + * Test TVP with result set + * + * @throws SQLException + */ + @Test + public void testTVPResultSet() throws SQLException { + testTVPResultSet(false, null, null); + testTVPResultSet(true, null, null); + testTVPResultSet(false, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + testTVPResultSet(false, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); + testTVPResultSet(false, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); + testTVPResultSet(false, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); + } + + private void testTVPResultSet(boolean setSelectMethod, Integer resultSetType, + Integer resultSetConcurrency) throws SQLException { + setupVariation(); + + Connection connnection = null; + if (setSelectMethod) { + connnection = DriverManager.getConnection(connectionString + ";selectMethod=cursor;"); + } else { + connnection = DriverManager.getConnection(connectionString); + } + + Statement stmtement = null; + if (null != resultSetType || null != resultSetConcurrency) { + stmtement = connnection.createStatement(resultSetType, resultSetConcurrency); + } else { + stmtement = connnection.createStatement(); + } + + ResultSet rs = stmtement.executeQuery("select * from " + tableSrc.getEscapedTableName()); + + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connnection + .prepareStatement("INSERT INTO " + tableDest.getEscapedTableName() + " select * from ? ;"); + pstmt.setStructured(1, tvpName, rs); + pstmt.execute(); + + ComparisonUtil.compareSrcTableAndDestTableIgnoreRowOrder(new DBConnection(connectionString), tableSrc, + tableDest); + + terminateVariation(); + } + + /** + * Test TVP with stored procedure and result set + * + * @throws SQLException + */ + @Test + public void testTVPStoredProcedureResultSet() throws SQLException { + testTVPStoredProcedureResultSet(false, null, null); + testTVPStoredProcedureResultSet(true, null, null); + testTVPStoredProcedureResultSet(false, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + testTVPStoredProcedureResultSet(false, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); + testTVPStoredProcedureResultSet(false, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); + testTVPStoredProcedureResultSet(false, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); + } + + private void testTVPStoredProcedureResultSet(boolean setSelectMethod, Integer resultSetType, + Integer resultSetConcurrency) throws SQLException { + setupVariation(); + + Connection connnection = null; + if (setSelectMethod) { + connnection = DriverManager.getConnection(connectionString + ";selectMethod=cursor;"); + } else { + connnection = DriverManager.getConnection(connectionString); + } + + Statement stmtement = null; + if (null != resultSetType || null != resultSetConcurrency) { + stmtement = connnection.createStatement(resultSetType, resultSetConcurrency); + } else { + stmtement = connnection.createStatement(); + } + + ResultSet rs = stmtement.executeQuery("select * from " + tableSrc.getEscapedTableName()); + + String sql = "{call " + procedureName + "(?)}"; + SQLServerCallableStatement Cstmt = (SQLServerCallableStatement) connnection.prepareCall(sql); + Cstmt.setStructured(1, tvpName, rs); + Cstmt.execute(); + + ComparisonUtil.compareSrcTableAndDestTableIgnoreRowOrder(new DBConnection(connectionString), tableSrc, + tableDest); + + terminateVariation(); + } + + /** + * Test TVP with DataTable + * + * @throws SQLException + */ + @Test + public void testTVPDataTable() throws SQLException { + setupVariation(); + + SQLServerDataTable dt = new SQLServerDataTable(); + + int numberOfColumns = tableDest.getColumns().size(); + Object[] values = new Object[numberOfColumns]; + for (int i = 0; i < numberOfColumns; i++) { + SqlType sqlType = tableDest.getColumns().get(i).getSqlType(); + dt.addColumnMetadata(tableDest.getColumnName(i), sqlType.getJdbctype().getVendorTypeNumber()); + values[i] = sqlType.createdata(); + } + + int numberOfRows = 10; + for (int i = 0; i < numberOfRows; i++) { + dt.addRow(values); + } + + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection + .prepareStatement("INSERT INTO " + tableDest.getEscapedTableName() + " select * from ? ;"); + pstmt.setStructured(1, tvpName, dt); + pstmt.execute(); + } + + private static void createPreocedure(String procedureName, String destTable) throws SQLException { + String sql = "CREATE PROCEDURE " + procedureName + " @InputData " + tvpName + " READONLY " + " AS " + " BEGIN " + + " INSERT INTO " + destTable + " SELECT * FROM @InputData" + " END"; + + stmt.execute(sql); + } + + private static void dropTVPS(String tvpName) throws SQLException { + stmt.executeUpdate("IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvpName + "') " + + " drop type " + tvpName); + } + + private static void createTVPS(String TVPName, String TVPDefinition) throws SQLException { + String TVPCreateCmd = "CREATE TYPE " + TVPName + " as table (" + TVPDefinition + ");"; + stmt.executeUpdate(TVPCreateCmd); + } + + private void setupVariation() throws SQLException { + conn = DriverManager.getConnection(connectionString); + stmt = conn.createStatement(); + + Utils.dropProcedureIfExists(procedureName, stmt); + dropTVPS(tvpName); + + DBConnection dbConnection = new DBConnection(connectionString); + DBStatement dbStmt = dbConnection.createStatement(); + + tableSrc = new DBTable(true); + tableDest = tableSrc.cloneSchema(); + + dbStmt.createTable(tableSrc); + dbStmt.createTable(tableDest); + + createTVPS(tvpName, tableSrc.getDefinitionOfColumns()); + createPreocedure(procedureName, tableDest.getEscapedTableName()); + + dbStmt.populateTable(tableSrc); + } + + private void terminateVariation() throws SQLException { + conn = DriverManager.getConnection(connectionString); + stmt = conn.createStatement(); + + Utils.dropProcedureIfExists(procedureName, stmt); + Utils.dropTableIfExists(tableSrc.getEscapedTableName(), stmt); + Utils.dropTableIfExists(tableDest.getEscapedTableName(), stmt); + dropTVPS(tvpName); + } +} diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPIssuesTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPIssuesTest.java index dfe8a5cd2..87ed449a3 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPIssuesTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPIssuesTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.tvp; @@ -26,10 +23,10 @@ import com.microsoft.sqlserver.jdbc.SQLServerCallableStatement; import com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement; import com.microsoft.sqlserver.jdbc.SQLServerStatement; +import com.microsoft.sqlserver.jdbc.TestResource; import com.microsoft.sqlserver.testframework.AbstractTest; -import com.microsoft.sqlserver.testframework.Utils; +import com.microsoft.sqlserver.testframework.Utils;; -import com.microsoft.sqlserver.jdbc.TestResource;; @RunWith(JUnitPlatform.class) public class TVPIssuesTest extends AbstractTest { @@ -81,20 +78,19 @@ public void testExceptionWithInvalidStoredProcedureName() throws Exception { try { Cstmt.setObject(1, rs); throw new Exception(TestResource.getResource("R_expectedExceptionNotThrown")); - } - catch (Exception e) { + } catch (Exception e) { if (e instanceof SQLException) { - assertTrue(e.getMessage().contains(TestResource.getResource("R_StoredProcedureNotFound")), TestResource.getResource("R_invalidErrorMessage") + e.toString()); - } - else { + assertTrue(e.getMessage().contains(TestResource.getResource("R_StoredProcedureNotFound")), + TestResource.getResource("R_invalidErrorMessage") + e.toString()); + } else { throw e; } } } /** - * Fix an issue: If column is time(x) and TVP is used (with either ResultSet, Stored Procedure or SQLServerDataTable). The milliseconds or - * nanoseconds are not copied into the destination table. + * Fix an issue: If column is time(x) and TVP is used (with either ResultSet, Stored Procedure or + * SQLServerDataTable). The milliseconds or nanoseconds are not copied into the destination table. * * @throws Exception */ @@ -141,13 +137,13 @@ public static void beforeAll() throws SQLException { dropProcedure(); - stmt.executeUpdate( - "IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvp_varcharMax + "') " + " drop type " + tvp_varcharMax); + stmt.executeUpdate("IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvp_varcharMax + + "') " + " drop type " + tvp_varcharMax); Utils.dropTableIfExists(srcTable_varcharMax, stmt); Utils.dropTableIfExists(desTable_varcharMax, stmt); - stmt.executeUpdate( - "IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvp_time_6 + "') " + " drop type " + tvp_time_6); + stmt.executeUpdate("IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvp_time_6 + + "') " + " drop type " + tvp_time_6); Utils.dropTableIfExists(srcTable_time_6, stmt); Utils.dropTableIfExists(desTable_time_6, stmt); @@ -198,8 +194,8 @@ private static void dropProcedure() throws SQLException { } private static void createPreocedure() throws SQLException { - String sql = "CREATE PROCEDURE " + spName_varcharMax + " @InputData " + tvp_varcharMax + " READONLY " + " AS " + " BEGIN " + " INSERT INTO " - + desTable_varcharMax + " SELECT * FROM @InputData" + " END"; + String sql = "CREATE PROCEDURE " + spName_varcharMax + " @InputData " + tvp_varcharMax + " READONLY " + " AS " + + " BEGIN " + " INSERT INTO " + desTable_varcharMax + " SELECT * FROM @InputData" + " END"; stmt.execute(sql); } @@ -207,13 +203,13 @@ private static void createPreocedure() throws SQLException { @AfterAll public static void terminateVariation() throws SQLException { dropProcedure(); - stmt.executeUpdate( - "IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvp_varcharMax + "') " + " drop type " + tvp_varcharMax); + stmt.executeUpdate("IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvp_varcharMax + + "') " + " drop type " + tvp_varcharMax); Utils.dropTableIfExists(srcTable_varcharMax, stmt); Utils.dropTableIfExists(desTable_varcharMax, stmt); - stmt.executeUpdate( - "IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvp_time_6 + "') " + " drop type " + tvp_time_6); + stmt.executeUpdate("IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvp_time_6 + + "') " + " drop type " + tvp_time_6); Utils.dropTableIfExists(srcTable_time_6, stmt); Utils.dropTableIfExists(desTable_time_6, stmt); diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPNumericTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPNumericTest.java index e96496e84..98a989cc9 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPNumericTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPNumericTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.tvp; @@ -23,6 +20,7 @@ import com.microsoft.sqlserver.testframework.DBResultSet; import com.microsoft.sqlserver.testframework.DBStatement; + @RunWith(JUnitPlatform.class) public class TVPNumericTest extends AbstractTest { @@ -41,7 +39,7 @@ public class TVPNumericTest extends AbstractTest { * Test a previous failure regarding to numeric precision. Issue #211 * * @throws SQLException - * @throws SQLTimeoutException + * @throws SQLTimeoutException */ @Test public void testNumericPresicionIssue211() throws SQLException { @@ -63,7 +61,7 @@ public void testNumericPresicionIssue211() throws SQLException { } @BeforeEach - private void testSetup() throws SQLException { + public void testSetup() throws SQLException { conn = new DBConnection(connectionString); stmt = conn.createStatement(); @@ -77,8 +75,8 @@ private void testSetup() throws SQLException { } private void dropProcedure() throws SQLException { - String sql = " IF EXISTS (select * from sysobjects where id = object_id(N'" + procedureName + "') and OBJECTPROPERTY(id, N'IsProcedure') = 1)" - + " DROP PROCEDURE " + procedureName; + String sql = " IF EXISTS (select * from sysobjects where id = object_id(N'" + procedureName + + "') and OBJECTPROPERTY(id, N'IsProcedure') = 1)" + " DROP PROCEDURE " + procedureName; stmt.execute(sql); } @@ -87,12 +85,13 @@ private static void dropTables() throws SQLException { } private static void dropTVPS() throws SQLException { - stmt.executeUpdate("IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvpName + "') " + " drop type " + tvpName); + stmt.executeUpdate("IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvpName + "') " + + " drop type " + tvpName); } private static void createPreocedure() throws SQLException { - String sql = "CREATE PROCEDURE " + procedureName + " @InputData " + tvpName + " READONLY " + " AS " + " BEGIN " + " INSERT INTO " + charTable - + " SELECT * FROM @InputData" + " END"; + String sql = "CREATE PROCEDURE " + procedureName + " @InputData " + tvpName + " READONLY " + " AS " + " BEGIN " + + " INSERT INTO " + charTable + " SELECT * FROM @InputData" + " END"; stmt.execute(sql); } @@ -108,7 +107,7 @@ private void createTVPS() throws SQLException { } @AfterEach - private void terminateVariation() throws SQLException { + public void terminateVariation() throws SQLException { if (null != conn) { conn.close(); } @@ -123,4 +122,4 @@ private void terminateVariation() throws SQLException { } } -} \ No newline at end of file +} diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPResultSetCursorTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPResultSetCursorTest.java index 2557031fb..88ce22dcc 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPResultSetCursorTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPResultSetCursorTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.tvp; @@ -31,19 +28,23 @@ import com.microsoft.sqlserver.testframework.AbstractTest; import com.microsoft.sqlserver.testframework.Utils; + @RunWith(JUnitPlatform.class) public class TVPResultSetCursorTest extends AbstractTest { private static Connection conn = null; static Statement stmt = null; - static BigDecimal[] expectedBigDecimals = {new BigDecimal("12345.12345"), new BigDecimal("125.123"), new BigDecimal("45.12345")}; + static BigDecimal[] expectedBigDecimals = {new BigDecimal("12345.12345"), new BigDecimal("125.123"), + new BigDecimal("45.12345")}; static String[] expectedBigDecimalStrings = {"12345.12345", "125.12300", "45.12345"}; static String[] expectedStrings = {"hello", "world", "!!!"}; - static Timestamp[] expectedTimestamps = {new Timestamp(1433338533461L), new Timestamp(14917485583999L), new Timestamp(1491123533000L)}; - static String[] expectedTimestampStrings = {"2015-06-03 13:35:33.4610000", "2442-09-19 01:59:43.9990000", "2017-04-02 08:58:53.0000000"}; + static Timestamp[] expectedTimestamps = {new Timestamp(1433338533461L), new Timestamp(14917485583999L), + new Timestamp(1491123533000L)}; + static String[] expectedTimestampStrings = {"2015-06-03 13:35:33.4610000", "2442-09-19 01:59:43.9990000", + "2017-04-02 08:58:53.0000000"}; private static String tvpName = "TVPResultSetCursorTest_TVP"; private static String procedureName = "TVPResultSetCursorTest_SP"; @@ -63,8 +64,7 @@ public void testServerCursors() throws SQLException { serverCursorsTest(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); } - private void serverCursorsTest(int resultSetType, - int resultSetConcurrency) throws SQLException { + private void serverCursorsTest(int resultSetType, int resultSetConcurrency) throws SQLException { conn = DriverManager.getConnection(connectionString); stmt = conn.createStatement(); @@ -76,9 +76,11 @@ private void serverCursorsTest(int resultSetType, populateSourceTable(); - ResultSet rs = conn.createStatement(resultSetType, resultSetConcurrency).executeQuery("select * from " + srcTable); + ResultSet rs = conn.createStatement(resultSetType, resultSetConcurrency) + .executeQuery("select * from " + srcTable); - SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) conn.prepareStatement("INSERT INTO " + desTable + " select * from ? ;"); + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) conn + .prepareStatement("INSERT INTO " + desTable + " select * from ? ;"); pstmt.setStructured(1, tvpName, rs); pstmt.execute(); @@ -93,7 +95,8 @@ private void serverCursorsTest(int resultSetType, } /** - * Test a previous failure when setting SelectMethod to cursor and using the same connection to create TVP and result set. + * Test a previous failure when setting SelectMethod to cursor and using the same connection to create TVP and + * result set. * * @throws SQLException */ @@ -115,7 +118,8 @@ public void testSelectMethodSetToCursor() throws SQLException { ResultSet rs = conn.createStatement().executeQuery("select * from " + srcTable); - SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) conn.prepareStatement("INSERT INTO " + desTable + " select * from ? ;"); + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) conn + .prepareStatement("INSERT INTO " + desTable + " select * from ? ;"); pstmt.setStructured(1, tvpName, rs); pstmt.execute(); @@ -130,7 +134,8 @@ public void testSelectMethodSetToCursor() throws SQLException { } /** - * Test a previous failure when setting SelectMethod to cursor and using the same connection to create TVP, SP and result set. + * Test a previous failure when setting SelectMethod to cursor and using the same connection to create TVP, SP and + * result set. * * @throws SQLException */ @@ -162,8 +167,7 @@ public void testSelectMethodSetToCursorWithSP() throws SQLException { pstmt.execute(); verifyDestinationTableData(expectedBigDecimals.length); - } - finally { + } finally { if (null != pstmt) { pstmt.close(); } @@ -198,18 +202,17 @@ public void testInvalidTVPName() throws SQLException { ResultSet rs = conn.createStatement().executeQuery("select * from " + srcTable); - SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) conn.prepareStatement("INSERT INTO " + desTable + " select * from ? ;"); + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) conn + .prepareStatement("INSERT INTO " + desTable + " select * from ? ;"); pstmt.setStructured(1, "invalid" + tvpName, rs); try { pstmt.execute(); - } - catch (SQLException e) { + } catch (SQLException e) { if (!e.getMessage().contains(TestResource.getResource("R_dataTypeNotFound"))) { throw e; } - } - finally { + } finally { if (null != pstmt) { pstmt.close(); } @@ -250,13 +253,11 @@ public void testInvalidStoredProcedureName() throws SQLException { try { pstmt.execute(); - } - catch (SQLException e) { + } catch (SQLException e) { if (!e.getMessage().contains(TestResource.getResource("R_StoredProcedureNotFound"))) { throw e; } - } - finally { + } finally { if (null != pstmt) { pstmt.close(); @@ -288,9 +289,11 @@ public void testMultiplePreparedStatementAndResultSet() throws SQLException { populateSourceTable(); - ResultSet rs = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE).executeQuery("select * from " + srcTable); + ResultSet rs = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE) + .executeQuery("select * from " + srcTable); - SQLServerPreparedStatement pstmt1 = (SQLServerPreparedStatement) conn.prepareStatement("INSERT INTO " + desTable + " select * from ? ;"); + SQLServerPreparedStatement pstmt1 = (SQLServerPreparedStatement) conn + .prepareStatement("INSERT INTO " + desTable + " select * from ? ;"); pstmt1.setStructured(1, tvpName, rs); pstmt1.execute(); verifyDestinationTableData(expectedBigDecimals.length); @@ -302,7 +305,8 @@ public void testMultiplePreparedStatementAndResultSet() throws SQLException { verifyDestinationTableData(expectedBigDecimals.length * 2); rs.beforeFirst(); - SQLServerPreparedStatement pstmt2 = (SQLServerPreparedStatement) conn.prepareStatement("INSERT INTO " + desTable + " select * from ? ;"); + SQLServerPreparedStatement pstmt2 = (SQLServerPreparedStatement) conn + .prepareStatement("INSERT INTO " + desTable + " select * from ? ;"); pstmt2.setStructured(1, tvpName, rs); pstmt2.execute(); verifyDestinationTableData(expectedBigDecimals.length * 3); @@ -319,7 +323,8 @@ public void testMultiplePreparedStatementAndResultSet() throws SQLException { } verifyDestinationTableData(expectedBigDecimals.length * 4); - ResultSet rs2 = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE).executeQuery("select * from " + srcTable); + ResultSet rs2 = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE) + .executeQuery("select * from " + srcTable); pstmt1 = (SQLServerPreparedStatement) conn.prepareStatement("INSERT INTO " + desTable + " select * from ? ;"); pstmt1.setStructured(1, tvpName, rs2); @@ -347,14 +352,14 @@ private static void verifyDestinationTableData(int expectedNumberOfRows) throws int i = 0; while (rs.next()) { - assertTrue(rs.getString(1).equals(expectedBigDecimalStrings[i % expectedArrayLength]), - "Expected Value:" + expectedBigDecimalStrings[i % expectedArrayLength] + ", Actual Value: " + rs.getString(1)); - assertTrue(rs.getString(2).trim().equals(expectedStrings[i % expectedArrayLength]), - "Expected Value:" + expectedStrings[i % expectedArrayLength] + ", Actual Value: " + rs.getString(2)); - assertTrue(rs.getString(3).equals(expectedTimestampStrings[i % expectedArrayLength]), - "Expected Value:" + expectedTimestampStrings[i % expectedArrayLength] + ", Actual Value: " + rs.getString(3)); - assertTrue(rs.getString(4).trim().equals(expectedStrings[i % expectedArrayLength]), - "Expected Value:" + expectedStrings[i % expectedArrayLength] + ", Actual Value: " + rs.getString(4)); + assertTrue(rs.getString(1).equals(expectedBigDecimalStrings[i % expectedArrayLength]), "Expected Value:" + + expectedBigDecimalStrings[i % expectedArrayLength] + ", Actual Value: " + rs.getString(1)); + assertTrue(rs.getString(2).trim().equals(expectedStrings[i % expectedArrayLength]), "Expected Value:" + + expectedStrings[i % expectedArrayLength] + ", Actual Value: " + rs.getString(2)); + assertTrue(rs.getString(3).equals(expectedTimestampStrings[i % expectedArrayLength]), "Expected Value:" + + expectedTimestampStrings[i % expectedArrayLength] + ", Actual Value: " + rs.getString(3)); + assertTrue(rs.getString(4).trim().equals(expectedStrings[i % expectedArrayLength]), "Expected Value:" + + expectedStrings[i % expectedArrayLength] + ", Actual Value: " + rs.getString(4)); i++; } @@ -383,10 +388,12 @@ private static void dropTables() throws SQLException { } private static void createTables() throws SQLException { - String sql = "create table " + srcTable + " (c1 decimal(10,5) null, c2 nchar(50) null, c3 datetime2(7) null, c4 char(7000));"; + String sql = "create table " + srcTable + + " (c1 decimal(10,5) null, c2 nchar(50) null, c3 datetime2(7) null, c4 char(7000));"; stmt.execute(sql); - sql = "create table " + desTable + " (c1 decimal(10,5) null, c2 nchar(50) null, c3 datetime2(7) null, c4 char(7000));"; + sql = "create table " + desTable + + " (c1 decimal(10,5) null, c2 nchar(50) null, c3 datetime2(7) null, c4 char(7000));"; stmt.execute(sql); } @@ -397,7 +404,8 @@ private static void createTVPS() throws SQLException { } private static void dropTVPS() throws SQLException { - stmt.execute("IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvpName + "') " + " drop type " + tvpName); + stmt.execute("IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvpName + "') " + + " drop type " + tvpName); } private static void dropProcedure() throws SQLException { @@ -405,14 +413,14 @@ private static void dropProcedure() throws SQLException { } private static void createPreocedure() throws SQLException { - String sql = "CREATE PROCEDURE " + procedureName + " @InputData " + tvpName + " READONLY " + " AS " + " BEGIN " + " INSERT INTO " + desTable - + " SELECT * FROM @InputData" + " END"; + String sql = "CREATE PROCEDURE " + procedureName + " @InputData " + tvpName + " READONLY " + " AS " + " BEGIN " + + " INSERT INTO " + desTable + " SELECT * FROM @InputData" + " END"; stmt.execute(sql); } @AfterEach - private void terminateVariation() throws SQLException { + public void terminateVariation() throws SQLException { if (null != conn) { conn.close(); } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPSchemaTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPSchemaTest.java index dd029ee1b..7ec4a7776 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPSchemaTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPSchemaTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.tvp; @@ -27,6 +24,7 @@ import com.microsoft.sqlserver.testframework.DBResultSet; import com.microsoft.sqlserver.testframework.DBStatement; + @RunWith(JUnitPlatform.class) public class TVPSchemaTest extends AbstractTest { @@ -122,7 +120,8 @@ public void testTVPSchemaPreparedInsertCommand() throws SQLException, IOExceptio @DisplayName("TVPSchemaCallableInsertCommand()") public void testTVPSchemaCallableInsertCommand() throws SQLException, IOException { - SQLServerCallableStatement P_C_stmt = (SQLServerCallableStatement) connection.prepareCall("INSERT INTO " + charTable + " select * from ? ;"); + SQLServerCallableStatement P_C_stmt = (SQLServerCallableStatement) connection + .prepareCall("INSERT INTO " + charTable + " select * from ? ;"); P_C_stmt.setStructured(1, tvpNameWithSchema, tvp); P_C_stmt.executeUpdate(); @@ -135,7 +134,7 @@ public void testTVPSchemaCallableInsertCommand() throws SQLException, IOExceptio } @BeforeEach - private void testSetup() throws SQLException { + public void testSetup() throws SQLException { conn = new DBConnection(connectionString); stmt = conn.createStatement(); @@ -174,8 +173,8 @@ private void verify(DBResultSet rs) throws SQLException { } private void dropProcedure() throws SQLException { - String sql = " IF EXISTS (select * from sysobjects where id = object_id(N'" + procedureName + "') and OBJECTPROPERTY(id, N'IsProcedure') = 1)" - + " DROP PROCEDURE " + procedureName; + String sql = " IF EXISTS (select * from sysobjects where id = object_id(N'" + procedureName + + "') and OBJECTPROPERTY(id, N'IsProcedure') = 1)" + " DROP PROCEDURE " + procedureName; stmt.execute(sql); } @@ -184,8 +183,8 @@ private static void dropTables() throws SQLException { } private static void dropTVPS() throws SQLException { - stmt.executeUpdate("IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvpNameWithouSchema + "') " + " drop type " - + tvpNameWithSchema); + stmt.executeUpdate("IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + + tvpNameWithouSchema + "') " + " drop type " + tvpNameWithSchema); } private static void dropAndCreateSchema() throws SQLException { @@ -194,8 +193,8 @@ private static void dropAndCreateSchema() throws SQLException { } private static void createPreocedure() throws SQLException { - String sql = "CREATE PROCEDURE " + procedureName + " @InputData " + tvpNameWithSchema + " READONLY " + " AS " + " BEGIN " + " INSERT INTO " - + charTable + " SELECT * FROM @InputData" + " END"; + String sql = "CREATE PROCEDURE " + procedureName + " @InputData " + tvpNameWithSchema + " READONLY " + " AS " + + " BEGIN " + " INSERT INTO " + charTable + " SELECT * FROM @InputData" + " END"; stmt.execute(sql); } @@ -207,13 +206,13 @@ private void createTables() throws SQLException { } private void createTVPS() throws SQLException { - String TVPCreateCmd = "CREATE TYPE " + tvpNameWithSchema + " as table ( " + "PlainChar char(50) null," + "PlainVarchar varchar(50) null," - + "PlainVarcharMax varchar(max) null" + ")"; + String TVPCreateCmd = "CREATE TYPE " + tvpNameWithSchema + " as table ( " + "PlainChar char(50) null," + + "PlainVarchar varchar(50) null," + "PlainVarcharMax varchar(max) null" + ")"; stmt.executeUpdate(TVPCreateCmd); } @AfterEach - private void terminateVariation() throws SQLException { + public void terminateVariation() throws SQLException { if (null != conn) { conn.close(); } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPTypesTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPTypesTest.java index 5d4ec875c..4ec14f92a 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPTypesTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/tvp/TVPTypesTest.java @@ -1,589 +1,587 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ -package com.microsoft.sqlserver.jdbc.tvp; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.Arrays; - -import org.junit.jupiter.api.AfterAll; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.platform.runner.JUnitPlatform; -import org.junit.runner.RunWith; - -import com.microsoft.sqlserver.jdbc.SQLServerCallableStatement; -import com.microsoft.sqlserver.jdbc.SQLServerDataTable; -import com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement; -import com.microsoft.sqlserver.jdbc.SQLServerResultSet; -import com.microsoft.sqlserver.testframework.AbstractTest; - -@RunWith(JUnitPlatform.class) -public class TVPTypesTest extends AbstractTest { - - private static Connection conn = null; - static Statement stmt = null; - static ResultSet rs = null; - static SQLServerDataTable tvp = null; - private static String tvpName = "TVP"; - private static String table = "TVPTable"; - private static String procedureName = "procedureThatCallsTVP"; - private String value = null; - - /** - * Test a longvarchar support - * - * @throws SQLException - */ - @Test - public void testLongVarchar() throws SQLException { - createTables("varchar(max)"); - createTVPS("varchar(max)"); - - StringBuffer buffer = new StringBuffer(); - for (int i = 0; i < 9000; i++) - buffer.append("a"); - - value = buffer.toString(); - tvp = new SQLServerDataTable(); - tvp.addColumnMetadata("c1", java.sql.Types.LONGVARCHAR); - tvp.addRow(value); - - SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection - .prepareStatement("INSERT INTO " + table + " select * from ? ;"); - pstmt.setStructured(1, tvpName, tvp); - - pstmt.execute(); - - rs = conn.createStatement().executeQuery("select * from " + table); - while (rs.next()) { - assertEquals(rs.getString(1), value); - } - if (null != pstmt) { - pstmt.close(); - } - } - - /** - * Test longnvarchar - * - * @throws SQLException - */ - @Test - public void testLongNVarchar() throws SQLException { - createTables("nvarchar(max)"); - createTVPS("nvarchar(max)"); - - StringBuffer buffer = new StringBuffer(); - for (int i = 0; i < 8001; i++) - buffer.append("سس"); - - value = buffer.toString(); - tvp = new SQLServerDataTable(); - tvp.addColumnMetadata("c1", java.sql.Types.LONGNVARCHAR); - tvp.addRow(value); - - SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection - .prepareStatement("INSERT INTO " + table + " select * from ? ;"); - pstmt.setStructured(1, tvpName, tvp); - - pstmt.execute(); - - rs = conn.createStatement().executeQuery("select * from " + table); - while (rs.next()) { - assertEquals(rs.getString(1), value); - } - - if (null != pstmt) { - pstmt.close(); - } - } - - /** - * Test xml support - * - * @throws SQLException - */ - @Test - public void testXML() throws SQLException { - createTables("xml"); - createTVPS("xml"); - value = "Variable E" + "Variable F" + "API" - + "The following are Japanese chars." - + " Some UTF-8 encoded characters: �������"; - - tvp = new SQLServerDataTable(); - tvp.addColumnMetadata("c1", java.sql.Types.SQLXML); - tvp.addRow(value); - - SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection - .prepareStatement("INSERT INTO " + table + " select * from ? ;"); - pstmt.setStructured(1, tvpName, tvp); - - pstmt.execute(); - - Connection con = DriverManager.getConnection(connectionString); - ResultSet rs = con.createStatement().executeQuery("select * from " + table); - while (rs.next()) - assertEquals(rs.getString(1), value); - - if (null != pstmt) { - pstmt.close(); - } - } - - /** - * Test ntext support - * - * @throws SQLException - */ - @Test - public void testnText() throws SQLException { - createTables("ntext"); - createTVPS("ntext"); - StringBuffer buffer = new StringBuffer(); - for (int i = 0; i < 9000; i++) - buffer.append("س"); - value = buffer.toString(); - tvp = new SQLServerDataTable(); - tvp.addColumnMetadata("c1", java.sql.Types.LONGNVARCHAR); - tvp.addRow(value); - - SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection - .prepareStatement("INSERT INTO " + table + " select * from ? ;"); - pstmt.setStructured(1, tvpName, tvp); - - pstmt.execute(); - - Connection con = DriverManager.getConnection(connectionString); - ResultSet rs = con.createStatement().executeQuery("select * from " + table); - while (rs.next()) - assertEquals(rs.getString(1), value); - - if (null != pstmt) { - pstmt.close(); - } - } - - /** - * Test text support - * - * @throws SQLException - */ - @Test - public void testText() throws SQLException { - createTables("text"); - createTVPS("text"); - StringBuffer buffer = new StringBuffer(); - for (int i = 0; i < 9000; i++) - buffer.append("a"); - value = buffer.toString(); - tvp = new SQLServerDataTable(); - tvp.addColumnMetadata("c1", java.sql.Types.LONGVARCHAR); - tvp.addRow(value); - - SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection - .prepareStatement("INSERT INTO " + table + " select * from ? ;"); - pstmt.setStructured(1, tvpName, tvp); - - pstmt.execute(); - - Connection con = DriverManager.getConnection(connectionString); - ResultSet rs = con.createStatement().executeQuery("select * from " + table); - while (rs.next()) - assertEquals(rs.getString(1), value); - - if (null != pstmt) { - pstmt.close(); - } - } - - /** - * Test text support - * - * @throws SQLException - */ - @Test - public void testImage() throws SQLException { - createTables("varbinary(max)"); - createTVPS("varbinary(max)"); - StringBuffer buffer = new StringBuffer(); - for (int i = 0; i < 10000; i++) - buffer.append("a"); - value = buffer.toString(); - tvp = new SQLServerDataTable(); - tvp.addColumnMetadata("c1", java.sql.Types.LONGVARBINARY); - tvp.addRow(value.getBytes()); - - SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection - .prepareStatement("INSERT INTO " + table + " select * from ? ;"); - pstmt.setStructured(1, tvpName, tvp); - - pstmt.execute(); - - Connection con = DriverManager.getConnection(connectionString); - ResultSet rs = con.createStatement().executeQuery("select * from " + table); - - while (rs.next()) - assertTrue(parseByte(rs.getBytes(1), value.getBytes())); - - if (null != pstmt) { - pstmt.close(); - } - } - - /** - * LongVarchar with StoredProcedure - * - * @throws SQLException - */ - @Test - public void testTVPLongVarcharStoredProcedure() throws SQLException { - createTables("varchar(max)"); - createTVPS("varchar(max)"); - createPreocedure(); - - StringBuffer buffer = new StringBuffer(); - for (int i = 0; i < 8001; i++) - buffer.append("a"); - - value = buffer.toString(); - tvp = new SQLServerDataTable(); - tvp.addColumnMetadata("c1", java.sql.Types.LONGVARCHAR); - tvp.addRow(value); - - final String sql = "{call " + procedureName + "(?)}"; - - SQLServerCallableStatement P_C_statement = (SQLServerCallableStatement) connection.prepareCall(sql); - P_C_statement.setStructured(1, tvpName, tvp); - P_C_statement.execute(); - - rs = stmt.executeQuery("select * from " + table); - while (rs.next()) - assertEquals(rs.getString(1), value); - - if (null != P_C_statement) { - P_C_statement.close(); - } - } - - /** - * LongNVarchar with StoredProcedure - * - * @throws SQLException - */ - @Test - public void testTVPLongNVarcharStoredProcedure() throws SQLException { - createTables("nvarchar(max)"); - createTVPS("nvarchar(max)"); - createPreocedure(); - - StringBuffer buffer = new StringBuffer(); - for (int i = 0; i < 8001; i++) - buffer.append("سس"); - value = buffer.toString(); - tvp = new SQLServerDataTable(); - tvp.addColumnMetadata("c1", java.sql.Types.LONGNVARCHAR); - tvp.addRow(buffer.toString()); - - final String sql = "{call " + procedureName + "(?)}"; - - SQLServerCallableStatement P_C_statement = (SQLServerCallableStatement) connection.prepareCall(sql); - P_C_statement.setStructured(1, tvpName, tvp); - P_C_statement.execute(); - - rs = stmt.executeQuery("select * from " + table); - while (rs.next()) - assertEquals(rs.getString(1), value); - - if (null != P_C_statement) { - P_C_statement.close(); - } - } - - /** - * XML with StoredProcedure - * - * @throws SQLException - */ - @Test - public void testTVPXMLStoredProcedure() throws SQLException { - createTables("xml"); - createTVPS("xml"); - createPreocedure(); - - value = "Variable E" + "Variable F" + "API" - + "The following are Japanese chars." - + " Some UTF-8 encoded characters: �������"; - - tvp = new SQLServerDataTable(); - tvp.addColumnMetadata("c1", java.sql.Types.SQLXML); - tvp.addRow(value); - - final String sql = "{call " + procedureName + "(?)}"; - - SQLServerCallableStatement P_C_statement = (SQLServerCallableStatement) connection.prepareCall(sql); - P_C_statement.setStructured(1, tvpName, tvp); - P_C_statement.execute(); - - rs = stmt.executeQuery("select * from " + table); - while (rs.next()) - assertEquals(rs.getString(1), value); - if (null != P_C_statement) { - P_C_statement.close(); - } - } - - /** - * Text with StoredProcedure - * - * @throws SQLException - */ - @Test - public void testTVPTextStoredProcedure() throws SQLException { - createTables("text"); - createTVPS("text"); - createPreocedure(); - - StringBuffer buffer = new StringBuffer(); - for (int i = 0; i < 9000; i++) - buffer.append("a"); - value = buffer.toString(); - - tvp = new SQLServerDataTable(); - tvp.addColumnMetadata("c1", java.sql.Types.LONGVARCHAR); - tvp.addRow(value); - - final String sql = "{call " + procedureName + "(?)}"; - - SQLServerCallableStatement P_C_statement = (SQLServerCallableStatement) connection.prepareCall(sql); - P_C_statement.setStructured(1, tvpName, tvp); - P_C_statement.execute(); - - rs = stmt.executeQuery("select * from " + table); - while (rs.next()) - assertEquals(rs.getString(1), value); - if (null != P_C_statement) { - P_C_statement.close(); - } - } - - /** - * Text with StoredProcedure - * - * @throws SQLException - */ - @Test - public void testTVPNTextStoredProcedure() throws SQLException { - createTables("ntext"); - createTVPS("ntext"); - createPreocedure(); - - StringBuffer buffer = new StringBuffer(); - for (int i = 0; i < 9000; i++) - buffer.append("س"); - value = buffer.toString(); - - tvp = new SQLServerDataTable(); - tvp.addColumnMetadata("c1", java.sql.Types.LONGNVARCHAR); - tvp.addRow(value); - - final String sql = "{call " + procedureName + "(?)}"; - - SQLServerCallableStatement P_C_statement = (SQLServerCallableStatement) connection.prepareCall(sql); - P_C_statement.setStructured(1, tvpName, tvp); - P_C_statement.execute(); - - rs = stmt.executeQuery("select * from " + table); - while (rs.next()) - assertEquals(rs.getString(1), value); - if (null != P_C_statement) { - P_C_statement.close(); - } - } - - /** - * Image with StoredProcedure acts the same as varbinary(max) - * - * @throws SQLException - */ - @Test - public void testTVPImageStoredProcedure() throws SQLException { - createTables("image"); - createTVPS("image"); - createPreocedure(); - - StringBuffer buffer = new StringBuffer(); - for (int i = 0; i < 9000; i++) - buffer.append("a"); - value = buffer.toString(); - - tvp = new SQLServerDataTable(); - tvp.addColumnMetadata("c1", java.sql.Types.LONGVARBINARY); - tvp.addRow(value.getBytes()); - - final String sql = "{call " + procedureName + "(?)}"; - - SQLServerCallableStatement P_C_statement = (SQLServerCallableStatement) connection.prepareCall(sql); - P_C_statement.setStructured(1, tvpName, tvp); - P_C_statement.execute(); - - rs = stmt.executeQuery("select * from " + table); - while (rs.next()) - assertTrue(parseByte(rs.getBytes(1), value.getBytes())); - if (null != P_C_statement) { - P_C_statement.close(); - } - } - - /** - * Test a datetime support - * - * @throws SQLException - */ - @Test - public void testDateTime() throws SQLException { - createTables("datetime"); - createTVPS("datetime"); - - java.sql.Timestamp value = java.sql.Timestamp.valueOf("2007-09-23 10:10:10.123"); - - tvp = new SQLServerDataTable(); - tvp.addColumnMetadata("c1", microsoft.sql.Types.DATETIME); - tvp.addRow(value); - - SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection - .prepareStatement("INSERT INTO " + table + " select * from ? ;"); - pstmt.setStructured(1, tvpName, tvp); - - pstmt.execute(); - - rs = conn.createStatement().executeQuery("select * from " + table); - while (rs.next()) { - assertEquals(((SQLServerResultSet) rs).getDateTime(1), value); - } - if (null != pstmt) { - pstmt.close(); - } - } - - /** - * Test a smalldatetime support - * - * @throws SQLException - */ - @Test - public void testSmallDateTime() throws SQLException { - createTables("smalldatetime"); - createTVPS("smalldatetime"); - - java.sql.Timestamp value = java.sql.Timestamp.valueOf("2007-09-23 10:10:10.123"); - java.sql.Timestamp returnValue = java.sql.Timestamp.valueOf("2007-09-23 10:10:00.0"); - - tvp = new SQLServerDataTable(); - tvp.addColumnMetadata("c1", microsoft.sql.Types.SMALLDATETIME); - tvp.addRow(value); - - SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection - .prepareStatement("INSERT INTO " + table + " select * from ? ;"); - pstmt.setStructured(1, tvpName, tvp); - - pstmt.execute(); - - rs = conn.createStatement().executeQuery("select * from " + table); - while (rs.next()) { - assertEquals(((SQLServerResultSet) rs).getSmallDateTime(1), returnValue); - } - if (null != pstmt) { - pstmt.close(); - } - } - - @BeforeEach - private void testSetup() throws SQLException { - conn = DriverManager.getConnection(connectionString); - stmt = conn.createStatement(); - - dropProcedure(); - dropTables(); - dropTVPS(); - } - - @AfterAll - public static void terminate() throws SQLException { - conn = DriverManager.getConnection(connectionString); - stmt = conn.createStatement(); - dropProcedure(); - dropTables(); - dropTVPS(); - } - - private static void dropProcedure() throws SQLException { - String sql = " IF EXISTS (select * from sysobjects where id = object_id(N'" + procedureName + "') and OBJECTPROPERTY(id, N'IsProcedure') = 1)" - + " DROP PROCEDURE " + procedureName; - stmt.execute(sql); - } - - private static void dropTables() throws SQLException { - stmt.executeUpdate("if object_id('" + table + "','U') is not null" + " drop table " + table); - } - - private static void dropTVPS() throws SQLException { - stmt.executeUpdate("IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvpName + "') " + " drop type " + tvpName); - } - - private static void createPreocedure() throws SQLException { - String sql = "CREATE PROCEDURE " + procedureName + " @InputData " + tvpName + " READONLY " + " AS " + " BEGIN " + " INSERT INTO " + table - + " SELECT * FROM @InputData" + " END"; - - stmt.execute(sql); - } - - private void createTables(String colType) throws SQLException { - String sql = "create table " + table + " (c1 " + colType + " null);"; - stmt.execute(sql); - } - - private void createTVPS(String colType) throws SQLException { - String TVPCreateCmd = "CREATE TYPE " + tvpName + " as table (c1 " + colType + " null)"; - stmt.executeUpdate(TVPCreateCmd); - } - - private boolean parseByte(byte[] expectedData, - byte[] retrieved) { - assertTrue(Arrays.equals(expectedData, Arrays.copyOf(retrieved, expectedData.length)), " unexpected BINARY value, expected"); - for (int i = expectedData.length; i < retrieved.length; i++) { - assertTrue(0 == retrieved[i], "unexpected data BINARY"); - } - return true; - } - - @AfterEach - private void terminateVariation() throws SQLException { - if (null != conn) { - conn.close(); - } - if (null != stmt) { - stmt.close(); - } - if (null != rs) { - rs.close(); - } - if (null != tvp) { - tvp.clear(); - } - } - -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package com.microsoft.sqlserver.jdbc.tvp; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Arrays; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.platform.runner.JUnitPlatform; +import org.junit.runner.RunWith; + +import com.microsoft.sqlserver.jdbc.SQLServerCallableStatement; +import com.microsoft.sqlserver.jdbc.SQLServerDataTable; +import com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement; +import com.microsoft.sqlserver.jdbc.SQLServerResultSet; +import com.microsoft.sqlserver.testframework.AbstractTest; + + +@RunWith(JUnitPlatform.class) +public class TVPTypesTest extends AbstractTest { + + private static Connection conn = null; + static Statement stmt = null; + static ResultSet rs = null; + static SQLServerDataTable tvp = null; + private static String tvpName = "TVP"; + private static String table = "TVPTable"; + private static String procedureName = "procedureThatCallsTVP"; + private String value = null; + + /** + * Test a longvarchar support + * + * @throws SQLException + */ + @Test + public void testLongVarchar() throws SQLException { + createTables("varchar(max)"); + createTVPS("varchar(max)"); + + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < 9000; i++) + buffer.append("a"); + + value = buffer.toString(); + tvp = new SQLServerDataTable(); + tvp.addColumnMetadata("c1", java.sql.Types.LONGVARCHAR); + tvp.addRow(value); + + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection + .prepareStatement("INSERT INTO " + table + " select * from ? ;"); + pstmt.setStructured(1, tvpName, tvp); + + pstmt.execute(); + + rs = conn.createStatement().executeQuery("select * from " + table); + while (rs.next()) { + assertEquals(rs.getString(1), value); + } + if (null != pstmt) { + pstmt.close(); + } + } + + /** + * Test longnvarchar + * + * @throws SQLException + */ + @Test + public void testLongNVarchar() throws SQLException { + createTables("nvarchar(max)"); + createTVPS("nvarchar(max)"); + + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < 8001; i++) + buffer.append("سس"); + + value = buffer.toString(); + tvp = new SQLServerDataTable(); + tvp.addColumnMetadata("c1", java.sql.Types.LONGNVARCHAR); + tvp.addRow(value); + + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection + .prepareStatement("INSERT INTO " + table + " select * from ? ;"); + pstmt.setStructured(1, tvpName, tvp); + + pstmt.execute(); + + rs = conn.createStatement().executeQuery("select * from " + table); + while (rs.next()) { + assertEquals(rs.getString(1), value); + } + + if (null != pstmt) { + pstmt.close(); + } + } + + /** + * Test xml support + * + * @throws SQLException + */ + @Test + public void testXML() throws SQLException { + createTables("xml"); + createTVPS("xml"); + value = "Variable E" + "Variable F" + "API" + + "The following are Japanese chars." + + " Some UTF-8 encoded characters: �������"; + + tvp = new SQLServerDataTable(); + tvp.addColumnMetadata("c1", java.sql.Types.SQLXML); + tvp.addRow(value); + + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection + .prepareStatement("INSERT INTO " + table + " select * from ? ;"); + pstmt.setStructured(1, tvpName, tvp); + + pstmt.execute(); + + Connection con = DriverManager.getConnection(connectionString); + ResultSet rs = con.createStatement().executeQuery("select * from " + table); + while (rs.next()) + assertEquals(rs.getString(1), value); + + if (null != pstmt) { + pstmt.close(); + } + } + + /** + * Test ntext support + * + * @throws SQLException + */ + @Test + public void testnText() throws SQLException { + createTables("ntext"); + createTVPS("ntext"); + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < 9000; i++) + buffer.append("س"); + value = buffer.toString(); + tvp = new SQLServerDataTable(); + tvp.addColumnMetadata("c1", java.sql.Types.LONGNVARCHAR); + tvp.addRow(value); + + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection + .prepareStatement("INSERT INTO " + table + " select * from ? ;"); + pstmt.setStructured(1, tvpName, tvp); + + pstmt.execute(); + + Connection con = DriverManager.getConnection(connectionString); + ResultSet rs = con.createStatement().executeQuery("select * from " + table); + while (rs.next()) + assertEquals(rs.getString(1), value); + + if (null != pstmt) { + pstmt.close(); + } + } + + /** + * Test text support + * + * @throws SQLException + */ + @Test + public void testText() throws SQLException { + createTables("text"); + createTVPS("text"); + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < 9000; i++) + buffer.append("a"); + value = buffer.toString(); + tvp = new SQLServerDataTable(); + tvp.addColumnMetadata("c1", java.sql.Types.LONGVARCHAR); + tvp.addRow(value); + + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection + .prepareStatement("INSERT INTO " + table + " select * from ? ;"); + pstmt.setStructured(1, tvpName, tvp); + + pstmt.execute(); + + Connection con = DriverManager.getConnection(connectionString); + ResultSet rs = con.createStatement().executeQuery("select * from " + table); + while (rs.next()) + assertEquals(rs.getString(1), value); + + if (null != pstmt) { + pstmt.close(); + } + } + + /** + * Test text support + * + * @throws SQLException + */ + @Test + public void testImage() throws SQLException { + createTables("varbinary(max)"); + createTVPS("varbinary(max)"); + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < 10000; i++) + buffer.append("a"); + value = buffer.toString(); + tvp = new SQLServerDataTable(); + tvp.addColumnMetadata("c1", java.sql.Types.LONGVARBINARY); + tvp.addRow(value.getBytes()); + + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection + .prepareStatement("INSERT INTO " + table + " select * from ? ;"); + pstmt.setStructured(1, tvpName, tvp); + + pstmt.execute(); + + Connection con = DriverManager.getConnection(connectionString); + ResultSet rs = con.createStatement().executeQuery("select * from " + table); + + while (rs.next()) + assertTrue(parseByte(rs.getBytes(1), value.getBytes())); + + if (null != pstmt) { + pstmt.close(); + } + } + + /** + * LongVarchar with StoredProcedure + * + * @throws SQLException + */ + @Test + public void testTVPLongVarcharStoredProcedure() throws SQLException { + createTables("varchar(max)"); + createTVPS("varchar(max)"); + createPreocedure(); + + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < 8001; i++) + buffer.append("a"); + + value = buffer.toString(); + tvp = new SQLServerDataTable(); + tvp.addColumnMetadata("c1", java.sql.Types.LONGVARCHAR); + tvp.addRow(value); + + final String sql = "{call " + procedureName + "(?)}"; + + SQLServerCallableStatement P_C_statement = (SQLServerCallableStatement) connection.prepareCall(sql); + P_C_statement.setStructured(1, tvpName, tvp); + P_C_statement.execute(); + + rs = stmt.executeQuery("select * from " + table); + while (rs.next()) + assertEquals(rs.getString(1), value); + + if (null != P_C_statement) { + P_C_statement.close(); + } + } + + /** + * LongNVarchar with StoredProcedure + * + * @throws SQLException + */ + @Test + public void testTVPLongNVarcharStoredProcedure() throws SQLException { + createTables("nvarchar(max)"); + createTVPS("nvarchar(max)"); + createPreocedure(); + + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < 8001; i++) + buffer.append("سس"); + value = buffer.toString(); + tvp = new SQLServerDataTable(); + tvp.addColumnMetadata("c1", java.sql.Types.LONGNVARCHAR); + tvp.addRow(buffer.toString()); + + final String sql = "{call " + procedureName + "(?)}"; + + SQLServerCallableStatement P_C_statement = (SQLServerCallableStatement) connection.prepareCall(sql); + P_C_statement.setStructured(1, tvpName, tvp); + P_C_statement.execute(); + + rs = stmt.executeQuery("select * from " + table); + while (rs.next()) + assertEquals(rs.getString(1), value); + + if (null != P_C_statement) { + P_C_statement.close(); + } + } + + /** + * XML with StoredProcedure + * + * @throws SQLException + */ + @Test + public void testTVPXMLStoredProcedure() throws SQLException { + createTables("xml"); + createTVPS("xml"); + createPreocedure(); + + value = "Variable E" + "Variable F" + "API" + + "The following are Japanese chars." + + " Some UTF-8 encoded characters: �������"; + + tvp = new SQLServerDataTable(); + tvp.addColumnMetadata("c1", java.sql.Types.SQLXML); + tvp.addRow(value); + + final String sql = "{call " + procedureName + "(?)}"; + + SQLServerCallableStatement P_C_statement = (SQLServerCallableStatement) connection.prepareCall(sql); + P_C_statement.setStructured(1, tvpName, tvp); + P_C_statement.execute(); + + rs = stmt.executeQuery("select * from " + table); + while (rs.next()) + assertEquals(rs.getString(1), value); + if (null != P_C_statement) { + P_C_statement.close(); + } + } + + /** + * Text with StoredProcedure + * + * @throws SQLException + */ + @Test + public void testTVPTextStoredProcedure() throws SQLException { + createTables("text"); + createTVPS("text"); + createPreocedure(); + + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < 9000; i++) + buffer.append("a"); + value = buffer.toString(); + + tvp = new SQLServerDataTable(); + tvp.addColumnMetadata("c1", java.sql.Types.LONGVARCHAR); + tvp.addRow(value); + + final String sql = "{call " + procedureName + "(?)}"; + + SQLServerCallableStatement P_C_statement = (SQLServerCallableStatement) connection.prepareCall(sql); + P_C_statement.setStructured(1, tvpName, tvp); + P_C_statement.execute(); + + rs = stmt.executeQuery("select * from " + table); + while (rs.next()) + assertEquals(rs.getString(1), value); + if (null != P_C_statement) { + P_C_statement.close(); + } + } + + /** + * Text with StoredProcedure + * + * @throws SQLException + */ + @Test + public void testTVPNTextStoredProcedure() throws SQLException { + createTables("ntext"); + createTVPS("ntext"); + createPreocedure(); + + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < 9000; i++) + buffer.append("س"); + value = buffer.toString(); + + tvp = new SQLServerDataTable(); + tvp.addColumnMetadata("c1", java.sql.Types.LONGNVARCHAR); + tvp.addRow(value); + + final String sql = "{call " + procedureName + "(?)}"; + + SQLServerCallableStatement P_C_statement = (SQLServerCallableStatement) connection.prepareCall(sql); + P_C_statement.setStructured(1, tvpName, tvp); + P_C_statement.execute(); + + rs = stmt.executeQuery("select * from " + table); + while (rs.next()) + assertEquals(rs.getString(1), value); + if (null != P_C_statement) { + P_C_statement.close(); + } + } + + /** + * Image with StoredProcedure acts the same as varbinary(max) + * + * @throws SQLException + */ + @Test + public void testTVPImageStoredProcedure() throws SQLException { + createTables("image"); + createTVPS("image"); + createPreocedure(); + + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < 9000; i++) + buffer.append("a"); + value = buffer.toString(); + + tvp = new SQLServerDataTable(); + tvp.addColumnMetadata("c1", java.sql.Types.LONGVARBINARY); + tvp.addRow(value.getBytes()); + + final String sql = "{call " + procedureName + "(?)}"; + + SQLServerCallableStatement P_C_statement = (SQLServerCallableStatement) connection.prepareCall(sql); + P_C_statement.setStructured(1, tvpName, tvp); + P_C_statement.execute(); + + rs = stmt.executeQuery("select * from " + table); + while (rs.next()) + assertTrue(parseByte(rs.getBytes(1), value.getBytes())); + if (null != P_C_statement) { + P_C_statement.close(); + } + } + + /** + * Test a datetime support + * + * @throws SQLException + */ + @Test + public void testDateTime() throws SQLException { + createTables("datetime"); + createTVPS("datetime"); + + java.sql.Timestamp value = java.sql.Timestamp.valueOf("2007-09-23 10:10:10.123"); + + tvp = new SQLServerDataTable(); + tvp.addColumnMetadata("c1", microsoft.sql.Types.DATETIME); + tvp.addRow(value); + + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection + .prepareStatement("INSERT INTO " + table + " select * from ? ;"); + pstmt.setStructured(1, tvpName, tvp); + + pstmt.execute(); + + rs = conn.createStatement().executeQuery("select * from " + table); + while (rs.next()) { + assertEquals(((SQLServerResultSet) rs).getDateTime(1), value); + } + if (null != pstmt) { + pstmt.close(); + } + } + + /** + * Test a smalldatetime support + * + * @throws SQLException + */ + @Test + public void testSmallDateTime() throws SQLException { + createTables("smalldatetime"); + createTVPS("smalldatetime"); + + java.sql.Timestamp value = java.sql.Timestamp.valueOf("2007-09-23 10:10:10.123"); + java.sql.Timestamp returnValue = java.sql.Timestamp.valueOf("2007-09-23 10:10:00.0"); + + tvp = new SQLServerDataTable(); + tvp.addColumnMetadata("c1", microsoft.sql.Types.SMALLDATETIME); + tvp.addRow(value); + + SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) connection + .prepareStatement("INSERT INTO " + table + " select * from ? ;"); + pstmt.setStructured(1, tvpName, tvp); + + pstmt.execute(); + + rs = conn.createStatement().executeQuery("select * from " + table); + while (rs.next()) { + assertEquals(((SQLServerResultSet) rs).getSmallDateTime(1), returnValue); + } + if (null != pstmt) { + pstmt.close(); + } + } + + @BeforeEach + public void testSetup() throws SQLException { + conn = DriverManager.getConnection(connectionString); + stmt = conn.createStatement(); + + dropProcedure(); + dropTables(); + dropTVPS(); + } + + @AfterAll + public static void terminate() throws SQLException { + conn = DriverManager.getConnection(connectionString); + stmt = conn.createStatement(); + dropProcedure(); + dropTables(); + dropTVPS(); + } + + private static void dropProcedure() throws SQLException { + String sql = " IF EXISTS (select * from sysobjects where id = object_id(N'" + procedureName + + "') and OBJECTPROPERTY(id, N'IsProcedure') = 1)" + " DROP PROCEDURE " + procedureName; + stmt.execute(sql); + } + + private static void dropTables() throws SQLException { + stmt.executeUpdate("if object_id('" + table + "','U') is not null" + " drop table " + table); + } + + private static void dropTVPS() throws SQLException { + stmt.executeUpdate("IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = '" + tvpName + "') " + + " drop type " + tvpName); + } + + private static void createPreocedure() throws SQLException { + String sql = "CREATE PROCEDURE " + procedureName + " @InputData " + tvpName + " READONLY " + " AS " + " BEGIN " + + " INSERT INTO " + table + " SELECT * FROM @InputData" + " END"; + + stmt.execute(sql); + } + + private void createTables(String colType) throws SQLException { + String sql = "create table " + table + " (c1 " + colType + " null);"; + stmt.execute(sql); + } + + private void createTVPS(String colType) throws SQLException { + String TVPCreateCmd = "CREATE TYPE " + tvpName + " as table (c1 " + colType + " null)"; + stmt.executeUpdate(TVPCreateCmd); + } + + private boolean parseByte(byte[] expectedData, byte[] retrieved) { + assertTrue(Arrays.equals(expectedData, Arrays.copyOf(retrieved, expectedData.length)), + " unexpected BINARY value, expected"); + for (int i = expectedData.length; i < retrieved.length; i++) { + assertTrue(0 == retrieved[i], "unexpected data BINARY"); + } + return true; + } + + @AfterEach + public void terminateVariation() throws SQLException { + if (null != conn) { + conn.close(); + } + if (null != stmt) { + stmt.close(); + } + if (null != rs) { + rs.close(); + } + if (null != tvp) { + tvp.clear(); + } + } +} diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/unit/TestSavepoint.java b/src/test/java/com/microsoft/sqlserver/jdbc/unit/TestSavepoint.java index 18e7d97bf..5dea7bf79 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/unit/TestSavepoint.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/unit/TestSavepoint.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.unit; @@ -26,6 +23,7 @@ import com.microsoft.sqlserver.testframework.AbstractTest; import com.microsoft.sqlserver.testframework.util.RandomUtil; + /** * Unit test case for Creating SavePoint. */ @@ -56,9 +54,7 @@ public void testSavePointName() throws SQLException { try { savePoint.getSavepointId(); assertTrue(false, TestResource.getResource("R_expectedExceptionNotThrown")); - } - catch (SQLException e) { - } + } catch (SQLException e) {} connection.rollback(); } @@ -85,9 +81,7 @@ public void testSavePointId() throws SQLException { savePoint.getSavepointName(); // Expecting Exception as trying to get SavePointname when we created savepoint without name assertTrue(false, TestResource.getResource("R_shouldThrowException")); - } - catch (SQLException e) { - } + } catch (SQLException e) {} assertTrue(savePoint.getSavepointId() != 0, form.format(msgArgs[1])); connection.rollback(); @@ -127,9 +121,7 @@ public void testSavePointWithAutoCommit() throws SQLException { connection.setSavepoint(null); // Expecting Exception as can not set SetPoint when AutoCommit mode is set to true assertTrue(false, TestResource.getResource("R_shouldThrowException")); - } - catch (SQLException e) { - } + } catch (SQLException e) {} } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/unit/UTF8SupportTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/unit/UTF8SupportTest.java index 68ee66dda..45be57ee6 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/unit/UTF8SupportTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/unit/UTF8SupportTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.unit; @@ -31,6 +28,7 @@ import com.microsoft.sqlserver.testframework.Utils; import com.microsoft.sqlserver.testframework.util.RandomUtil; + /** * A class for testing the UTF8 support changes. */ @@ -128,7 +126,8 @@ public static void cleanUp() throws SQLException { private static void createDatabaseWithUTF8Collation() throws SQLException { try (Statement stmt = connection.createStatement();) { - stmt.executeUpdate("CREATE DATABASE " + AbstractSQLGenerator.escapeIdentifier(databaseName) + " COLLATE Cyrillic_General_100_CS_AS_UTF8"); + stmt.executeUpdate("CREATE DATABASE " + AbstractSQLGenerator.escapeIdentifier(databaseName) + + " COLLATE Cyrillic_General_100_CS_AS_SC_UTF8"); } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/unit/lobs/lobsTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/unit/lobs/lobsTest.java index 2753a86a8..ee5009dee 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/unit/lobs/lobsTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/unit/lobs/lobsTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.unit.lobs; @@ -41,7 +38,6 @@ import org.junit.runner.RunWith; import com.microsoft.sqlserver.jdbc.TestResource; - import com.microsoft.sqlserver.testframework.AbstractSQLGenerator; import com.microsoft.sqlserver.testframework.AbstractTest; import com.microsoft.sqlserver.testframework.DBCoercion; @@ -57,6 +53,7 @@ import com.microsoft.sqlserver.testframework.sqlType.SqlType; import com.microsoft.sqlserver.testframework.util.RandomUtil; + /** * This class tests lobs (Blob, Clob and NClob) and their APIs * @@ -99,7 +96,8 @@ public static void terminate() throws SQLException { @TestFactory public Collection executeDynamicTests() { - List classes = new ArrayList(Arrays.asList(Blob.class, Clob.class, DBBinaryStream.class, DBCharacterStream.class)); + List classes = new ArrayList( + Arrays.asList(Blob.class, Clob.class, DBBinaryStream.class, DBCharacterStream.class)); List isResultSetTypes = new ArrayList<>(Arrays.asList(true, false)); Collection dynamicTests = new ArrayList<>(); @@ -132,8 +130,7 @@ public void execute() throws Throwable { * @param isResultSet * @throws SQLException */ - private void testInvalidLobs(Class lobClass, - boolean isResultSet) throws SQLException { + private void testInvalidLobs(Class lobClass, boolean isResultSet) throws SQLException { String clobTypes[] = {"varchar(max)", "nvarchar(max)"}; String blobTypes[] = {"varbinary(max)"}; int choose = ThreadLocalRandom.current().nextInt(3); @@ -152,8 +149,7 @@ private void testInvalidLobs(Class lobClass, try { if (clobType == classType(lobClass) || nClobType == classType(lobClass)) { table = this.createTable(table, clobTypes, true); - } - else { + } else { table = this.createTable(table, blobTypes, true); } Object updater; @@ -165,16 +161,15 @@ private void testInvalidLobs(Class lobClass, Object lob = this.createLob(lobClass); if (isResultSet) { Statement stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); - updater = stmt.executeQuery( - "Select " + table.getEscapedTableName() + ".[" + col.getColumnName() + "]" + " from " + table.getEscapedTableName()); + updater = stmt.executeQuery("Select " + table.getEscapedTableName() + ".[" + col.getColumnName() + + "]" + " from " + table.getEscapedTableName()); ((ResultSet) updater).next(); - } - else - updater = conn.prepareStatement("update " + table.getEscapedTableName() + " set " + ".[" + col.getColumnName() + "]" + "=?"); + } else + updater = conn.prepareStatement("update " + table.getEscapedTableName() + " set " + ".[" + + col.getColumnName() + "]" + "=?"); try { this.updateLob(lob, updater, 1); - } - catch (SQLException e) { + } catch (SQLException e) { boolean verified = false; if (lobClass == Clob.class) @@ -185,19 +180,23 @@ else if (lobClass == Blob.class) // Case 1: Invalid length value is passed as LOB length if (streamLength < 0 || streamLength == Long.MAX_VALUE) { // Applies to all LOB types ("The length {0} is not valid} - assertTrue(e.getMessage().startsWith("The length"), TestResource.getResource("R_unexpectedExceptionContent") + ": " + e.getMessage()); - assertTrue(e.getMessage().endsWith("is not valid."), TestResource.getResource("R_unexpectedExceptionContent") + ": " + e.getMessage()); + assertTrue(e.getMessage().startsWith("The length"), + TestResource.getResource("R_unexpectedExceptionContent") + ": " + e.getMessage()); + assertTrue(e.getMessage().endsWith("is not valid."), + TestResource.getResource("R_unexpectedExceptionContent") + ": " + e.getMessage()); verified = true; } // Case 2: CharacterStream or Clob.getCharacterStream threw IOException - if (lobClass == DBCharacterStream.class || (lobClass == Clob.class && ((DBInvalidUtil.InvalidClob) lob).stream != null)) { - DBInvalidUtil.InvalidCharacterStream stream = lobClass == DBCharacterStream.class - ? ((DBInvalidUtil.InvalidCharacterStream) lob) : ((DBInvalidUtil.InvalidClob) lob).stream; + if (lobClass == DBCharacterStream.class + || (lobClass == Clob.class && ((DBInvalidUtil.InvalidClob) lob).stream != null)) { + DBInvalidUtil.InvalidCharacterStream stream = lobClass == DBCharacterStream.class ? ((DBInvalidUtil.InvalidCharacterStream) lob) + : ((DBInvalidUtil.InvalidClob) lob).stream; if (stream.threwException) { // CharacterStream threw IOException - String[] args = {"java.io.IOException: " + DBInvalidUtil.InvalidCharacterStream.IOExceptionMsg}; + String[] args = { + "java.io.IOException: " + DBInvalidUtil.InvalidCharacterStream.IOExceptionMsg}; assertTrue(e.getMessage().contains(args[0])); verified = true; @@ -216,8 +215,7 @@ else if (lobClass == Blob.class) } } } - } - catch (Exception e) { + } catch (Exception e) { this.dropTables(table); e.printStackTrace(); } @@ -225,11 +223,10 @@ else if (lobClass == Blob.class) @Test @DisplayName("testFreedBlobs") - private void testFreedBlobs(Class lobClass, - boolean isResultSet) throws SQLException { + private void testFreedBlobs(Class lobClass, boolean isResultSet) throws SQLException { String types[] = {"varbinary(max)"}; try { - table = createTable(table, types, false); // create empty table + table = createTable(table, types, false); // create empty table int size = 10000; byte[] data = new byte[size]; @@ -237,9 +234,9 @@ private void testFreedBlobs(Class lobClass, Blob blob = null; InputStream stream = null; - for (int i = 0; i < 5; i++) - { - PreparedStatement ps = conn.prepareStatement("INSERT INTO " + table.getEscapedTableName() + " VALUES(?)"); + for (int i = 0; i < 5; i++) { + PreparedStatement ps = conn + .prepareStatement("INSERT INTO " + table.getEscapedTableName() + " VALUES(?)"); blob = conn.createBlob(); blob.setBytes(1, data); ps.setBlob(1, blob); @@ -248,29 +245,27 @@ private void testFreedBlobs(Class lobClass, byte[] chunk = new byte[size]; ResultSet rs = stmt.executeQuery("select * from " + table.getEscapedTableName()); - for (int i = 0; i < 5; i++) - { + for (int i = 0; i < 5; i++) { rs.next(); - + blob = rs.getBlob(1); stream = blob.getBinaryStream(); while (stream.available() > 0) - stream.read(); + stream.read(); blob.free(); try { - stream = blob.getBinaryStream(); + stream = blob.getBinaryStream(); } catch (SQLException e) { assertTrue(e.getMessage().contains(TestResource.getResource("R_blobFreed"))); } } rs.close(); try { - stream = blob.getBinaryStream(); + stream = blob.getBinaryStream(); } catch (SQLException e) { assertTrue(e.getMessage().contains(TestResource.getResource("R_blobFreed"))); } - } - catch (Exception e) { + } catch (Exception e) { this.dropTables(table); e.printStackTrace(); } @@ -311,22 +306,19 @@ private void testMultipleClose(Class streamClass) throws Exception { Object stream = rs.getXXX(i + 1, streamClass); if (stream == null) { assertEquals(stream, rs.getObject(i + 1), TestResource.getResource("R_streamNull")); - } - else { + } else { // close the stream twice if (streamClass == DBCharacterStream.class) { ((Reader) stream).close(); ((Reader) stream).close(); - } - else { + } else { ((InputStream) stream).close(); ((InputStream) stream).close(); } } } } - } - finally { + } finally { if (null != table) this.dropTables(table); if (null != null) @@ -370,9 +362,8 @@ public void testClob() throws Exception { testLobsInsertRetrive(types, Clob.class); } - private void testLobsInsertRetrive(String types[], - Class lobClass) throws Exception { - table = createTable(table, types, false); // create empty table + private void testLobsInsertRetrive(String types[], Class lobClass) throws Exception { + table = createTable(table, types, false); // create empty table int size = 10000; byte[] data = new byte[size]; @@ -389,8 +380,7 @@ private void testLobsInsertRetrive(String types[], clob = conn.createClob(); clob.setString(1, stringData); ps.setClob(1, clob); - } - else if (nClobType == classType(lobClass)) { + } else if (nClobType == classType(lobClass)) { String stringData = new String(data); size = stringData.length(); nclob = conn.createNClob(); @@ -417,16 +407,14 @@ else if (nClobType == classType(lobClass)) { stream = clob.getAsciiStream(); assertEquals(clob.length(), size); - } - else if (nClobType == classType(lobClass)) { + } else if (nClobType == classType(lobClass)) { nclob = rs.getNClob(1); assertEquals(nclob.length(), size); stream = nclob.getAsciiStream(); BufferedInputStream is = new BufferedInputStream(stream); is.read(chunk); assertEquals(chunk.length, size); - } - else { + } else { blob = rs.getBlob(1); stream = blob.getBinaryStream(); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); @@ -468,12 +456,12 @@ public void testUpdatorClob() throws Exception { String types[] = {"varchar(max)"}; testUpdateLobs(types, Clob.class); } - + @Test - @DisplayName("readBlobStreamAfterClosingRS") + @DisplayName("readBlobStreamAfterClosingRS") public void readBlobStreamAfterClosingRS() throws Exception { String types[] = {"varbinary(max)"}; - table = createTable(table, types, false); // create empty table + table = createTable(table, types, false); // create empty table int size = 10000; byte[] data = new byte[size]; @@ -490,7 +478,7 @@ public void readBlobStreamAfterClosingRS() throws Exception { byte[] chunk = new byte[size]; ResultSet rs = stmt.executeQuery("select * from " + table.getEscapedTableName()); rs.next(); - + blob = rs.getBlob(1); stream = blob.getBinaryStream(); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); @@ -510,18 +498,18 @@ public void readBlobStreamAfterClosingRS() throws Exception { blob.free(); dropTables(table); } - + @Test @DisplayName("readMultipleBlobStreamsThenCloseRS") public void readMultipleBlobStreamsThenCloseRS() throws Exception { - String types[] = {"varbinary(max)"}; - table = createTable(table, types, false); - int size = 10000; - - byte[] data = new byte[size]; - Blob[] blobs = {null, null, null, null, null}; + String types[] = {"varbinary(max)"}; + table = createTable(table, types, false); + int size = 10000; + + byte[] data = new byte[size]; + Blob[] blobs = {null, null, null, null, null}; InputStream stream = null; - for (int i = 0; i < 5; i++)//create 5 blobs + for (int i = 0; i < 5; i++)// create 5 blobs { PreparedStatement ps = conn.prepareStatement("INSERT INTO " + table.getEscapedTableName() + " VALUES(?)"); blobs[i] = conn.createBlob(); @@ -532,32 +520,29 @@ public void readMultipleBlobStreamsThenCloseRS() throws Exception { } byte[] chunk = new byte[size]; ResultSet rs = stmt.executeQuery("select * from " + table.getEscapedTableName()); - for (int i = 0; i < 5; i++) - { - rs.next(); - blobs[i] = rs.getBlob(1); - stream = blobs[i].getBinaryStream(); - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - int read = 0; - while ((read = stream.read(chunk)) > 0) - buffer.write(chunk, 0, read); - assertEquals(chunk.length, size); + for (int i = 0; i < 5; i++) { + rs.next(); + blobs[i] = rs.getBlob(1); + stream = blobs[i].getBinaryStream(); + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + int read = 0; + while ((read = stream.read(chunk)) > 0) + buffer.write(chunk, 0, read); + assertEquals(chunk.length, size); } rs.close(); - for (int i = 0; i < 5; i++) - { - stream = blobs[i].getBinaryStream(); - ByteArrayOutputStream buffer = new ByteArrayOutputStream(); - int read = 0; - while ((read = stream.read(chunk)) > 0) - buffer.write(chunk, 0, read); - assertEquals(chunk.length, size); + for (int i = 0; i < 5; i++) { + stream = blobs[i].getBinaryStream(); + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + int read = 0; + while ((read = stream.read(chunk)) > 0) + buffer.write(chunk, 0, read); + assertEquals(chunk.length, size); } } - private void testUpdateLobs(String types[], - Class lobClass) throws Exception { - table = createTable(table, types, false); // create empty table + private void testUpdateLobs(String types[], Class lobClass) throws Exception { + table = createTable(table, types, false); // create empty table int size = 10000; byte[] data = new byte[size]; @@ -574,8 +559,7 @@ private void testUpdateLobs(String types[], clob = conn.createClob(); clob.setString(1, stringData); ps.setClob(1, clob); - } - else if (nClobType == classType(lobClass)) { + } else if (nClobType == classType(lobClass)) { String stringData = new String(data); size = stringData.length(); nclob = conn.createNClob(); @@ -599,15 +583,13 @@ else if (nClobType == classType(lobClass)) { clob = conn.createClob(); clob.setString(1, stringData); rs.updateClob(1, clob); - } - else if (nClobType == classType(lobClass)) { + } else if (nClobType == classType(lobClass)) { String stringData = new String(data); size = stringData.length(); nclob = conn.createNClob(); nclob.setString(1, stringData); rs.updateClob(1, nclob); - } - else { + } else { blob = conn.createBlob(); rs.updateBlob(1, blob); @@ -633,19 +615,14 @@ else if (NClob.class == type) return blobType; } - private void updateLob(Object lob, - Object updater, - int index) throws Exception { + private void updateLob(Object lob, Object updater, int index) throws Exception { if (updater instanceof PreparedStatement) this.updatePreparedStatement((PreparedStatement) updater, lob, index, (int) streamLength); else this.updateResultSet((ResultSet) updater, lob, index, (int) streamLength); } - private void updatePreparedStatement(PreparedStatement ps, - Object lob, - int index, - int length) throws Exception { + private void updatePreparedStatement(PreparedStatement ps, Object lob, int index, int length) throws Exception { if (lob instanceof DBCharacterStream) ps.setCharacterStream(index, (DBCharacterStream) lob, length); else if (lob instanceof DBBinaryStream) @@ -657,20 +634,14 @@ else if (lob instanceof Clob) assertEquals(ps.executeUpdate(), 1, TestResource.getResource("R_incorrectUpdateCount")); } - private void updateResultSet(ResultSet rs, - Object lob, - int index, - int length) throws Exception { + private void updateResultSet(ResultSet rs, Object lob, int index, int length) throws Exception { if (lob instanceof DBCharacterStream) { rs.updateCharacterStream(index, (DBCharacterStream) lob, length); - } - else if (lob instanceof DBBinaryStream) { + } else if (lob instanceof DBBinaryStream) { rs.updateBinaryStream(index, (InputStream) lob, length); - } - else if (lob instanceof Clob) { + } else if (lob instanceof Clob) { rs.updateClob(index, (Clob) lob); - } - else { + } else { rs.updateBlob(index, (Blob) lob); } rs.updateRow(); @@ -678,7 +649,8 @@ else if (lob instanceof Clob) { private Object createLob(Class lobClass) { // Randomly indicate negative length - streamLength = ThreadLocalRandom.current().nextInt(3) < 2 ? datasize : -1 - ThreadLocalRandom.current().nextInt(datasize); + streamLength = ThreadLocalRandom.current().nextInt(3) < 2 ? datasize + : -1 - ThreadLocalRandom.current().nextInt(datasize); // For streams -1 means any length, avoid to ensure that an exception is always thrown if (streamLength == -1 && (lobClass == DBCharacterStream.class || lobClass == DBBinaryStream.class)) streamLength = datasize; @@ -696,8 +668,7 @@ else if (lobClass == DBBinaryStream.class) SqlType type = Utils.find(String.class); Object expected = type.createdata(String.class, data); return new DBInvalidUtil().new InvalidClob(expected, false); - } - else { + } else { ArrayList types = Utils.types(); SqlType type = Utils.find(byte[].class); Object expected = type.createdata(type.getClass(), data); @@ -706,9 +677,7 @@ else if (lobClass == DBBinaryStream.class) } - private static DBTable createTable(DBTable table, - String[] types, - boolean populateTable) throws Exception { + private static DBTable createTable(DBTable table, String[] types, boolean populateTable) throws Exception { DBStatement stmt = new DBConnection(connectionString).createStatement(); table = new DBTable(false); @@ -728,7 +697,8 @@ private static DBTable createTable(DBTable table, } private static void dropTables(DBTable table) throws SQLException { - stmt.executeUpdate("if object_id('" + table.getEscapedTableName() + "','U') is not null" + " drop table " + table.getEscapedTableName()); + stmt.executeUpdate("if object_id('" + table.getEscapedTableName() + "','U') is not null" + " drop table " + + table.getEscapedTableName()); } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/BatchExecuteWithErrorsTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/BatchExecuteWithErrorsTest.java index e3659adfc..ae9c2e8ba 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/BatchExecuteWithErrorsTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/BatchExecuteWithErrorsTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.unit.statement; @@ -37,6 +34,7 @@ import com.microsoft.sqlserver.testframework.Utils; import com.microsoft.sqlserver.testframework.util.RandomUtil; + /** * Tests batch execution with errors * @@ -55,20 +53,21 @@ public class BatchExecuteWithErrorsTest extends AbstractTest { /** * Batch test - * @throws Exception + * + * @throws Exception */ @Test @DisplayName("Batch Test") public void Repro47239() throws Exception { Repro47239Internal("BatchInsert"); } - + @Test @DisplayName("Batch Test using bulk copy API") public void Repro47239UseBulkCopyAPI() throws Exception { Repro47239Internal("BulkCopy"); } - + /** * Tests large methods, supported in 42 * @@ -79,13 +78,13 @@ public void Repro47239UseBulkCopyAPI() throws Exception { public void Repro47239large() throws Exception { Repro47239largeInternal("BatchInsert"); } - + @Test @DisplayName("Regression test for using 'large' methods using bulk copy API") public void Repro47239largeUseBulkCopyAPI() throws Exception { Repro47239largeInternal("BulkCopy"); } - + private void Repro47239Internal(String mode) throws Exception { String tableN = RandomUtil.getIdentifier("t_Repro47239"); final String tableName = AbstractSQLGenerator.escapeIdentifier(tableN); @@ -99,7 +98,8 @@ private void Repro47239Internal(String mode) throws Exception { String severe; con = DriverManager.getConnection(connectionString); if (DBConnection.isSqlAzure(con)) { - // SQL Azure will throw exception for "raiserror WITH LOG", so the following RAISERROR statements have not "with log" option + // SQL Azure will throw exception for "raiserror WITH LOG", so the following RAISERROR statements have not + // "with log" option warning = "RAISERROR ('raiserror level 4',4,1)"; error = "RAISERROR ('raiserror level 11',11,1)"; // On SQL Azure, raising FATAL error by RAISERROR() is not supported and there is no way to @@ -108,10 +108,11 @@ private void Repro47239Internal(String mode) throws Exception { // this simulation cannot be written entirely in TSQL (because it needs a new connection), // and thus it cannot be put into a TSQL batch and it is useless here. // So we have to skip the last scenario of this test case, i.e. "Test Severe (connection-closing) errors" - // It is worthwhile to still execute the first 5 test scenarios of this test case, in order to have best test coverage. - severe = "--Not executed when testing against SQL Azure"; // this is a dummy statement that never being executed on SQL Azure - } - else { + // It is worthwhile to still execute the first 5 test scenarios of this test case, in order to have best + // test coverage. + severe = "--Not executed when testing against SQL Azure"; // this is a dummy statement that never being + // executed on SQL Azure + } else { warning = "RAISERROR ('raiserror level 4',4,1) WITH LOG"; error = "RAISERROR ('raiserror level 11',11,1) WITH LOG"; severe = "RAISERROR ('raiserror level 20',20,1) WITH LOG"; @@ -125,8 +126,7 @@ private void Repro47239Internal(String mode) throws Exception { // SQL Server 2005 driver try { Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); - } - catch (ClassNotFoundException e1) { + } catch (ClassNotFoundException e1) { fail(e1.toString()); } try (Connection conn = DriverManager.getConnection(connectionString)) { @@ -134,14 +134,12 @@ private void Repro47239Internal(String mode) throws Exception { modifyConnectionForBulkCopyAPI((SQLServerConnection) conn); } try (Statement stmt = conn.createStatement()) { - + try { Utils.dropTableIfExists(tableName, stmt); - } - catch (Exception ignored) { - } - stmt.executeUpdate( - "create table " + tableName + " (c1_int int, c2_varchar varchar(20), c3_date datetime, c4_int int identity(1,1) primary key)"); + } catch (Exception ignored) {} + stmt.executeUpdate("create table " + tableName + + " (c1_int int, c2_varchar varchar(20), c3_date datetime, c4_int int identity(1,1) primary key)"); // Regular Statement batch update expectedUpdateCounts = new int[] {1, -2, 1, -2, 1, -2}; @@ -155,15 +153,13 @@ private void Repro47239Internal(String mode) throws Exception { try { actualUpdateCounts = batchStmt.executeBatch(); actualExceptionText = ""; - } - catch (BatchUpdateException bue) { + } catch (BatchUpdateException bue) { actualUpdateCounts = bue.getUpdateCounts(); actualExceptionText = bue.getMessage(); if (log.isLoggable(Level.FINE)) { log.fine("BatchUpdateException occurred. Message:" + actualExceptionText); } - } - finally { + } finally { batchStmt.close(); } if (log.isLoggable(Level.FINE)) { @@ -173,7 +169,8 @@ private void Repro47239Internal(String mode) throws Exception { log.fine("" + updateCount + ","); } log.fine(""); - assertTrue(Arrays.equals(actualUpdateCounts, expectedUpdateCounts), TestResource.getResource("R_testInterleaved")); + assertTrue(Arrays.equals(actualUpdateCounts, expectedUpdateCounts), + TestResource.getResource("R_testInterleaved")); expectedUpdateCounts = new int[] {-3, 1, 1, 1}; stmt.addBatch(error); @@ -183,8 +180,7 @@ private void Repro47239Internal(String mode) throws Exception { try { actualUpdateCounts = stmt.executeBatch(); actualExceptionText = ""; - } - catch (BatchUpdateException bue) { + } catch (BatchUpdateException bue) { actualUpdateCounts = bue.getUpdateCounts(); actualExceptionText = bue.getMessage(); } @@ -193,7 +189,8 @@ private void Repro47239Internal(String mode) throws Exception { log.fine("" + updateCount + ","); } log.fine(""); - assertTrue(Arrays.equals(actualUpdateCounts, expectedUpdateCounts), TestResource.getResource("R_errorFollowInserts")); + assertTrue(Arrays.equals(actualUpdateCounts, expectedUpdateCounts), + TestResource.getResource("R_errorFollowInserts")); // 50280 expectedUpdateCounts = new int[] {1, -3}; stmt.addBatch(insertStmt); @@ -201,8 +198,7 @@ private void Repro47239Internal(String mode) throws Exception { try { actualUpdateCounts = stmt.executeBatch(); actualExceptionText = ""; - } - catch (BatchUpdateException bue) { + } catch (BatchUpdateException bue) { actualUpdateCounts = bue.getUpdateCounts(); actualExceptionText = bue.getMessage(); } @@ -210,7 +206,8 @@ private void Repro47239Internal(String mode) throws Exception { log.fine("" + updateCount + ","); } log.fine(""); - assertTrue(Arrays.equals(actualUpdateCounts, expectedUpdateCounts), TestResource.getResource("R_errorFollow50280")); + assertTrue(Arrays.equals(actualUpdateCounts, expectedUpdateCounts), + TestResource.getResource("R_errorFollow50280")); // Test "soft" errors conn.setAutoCommit(false); @@ -222,9 +219,9 @@ private void Repro47239Internal(String mode) throws Exception { stmt.executeBatch(); // Soft error test: executeBatch unexpectedly succeeded assertEquals(true, false, TestResource.getResource("R_shouldThrowException")); - } - catch (BatchUpdateException bue) { - assertEquals("A result set was generated for update.", bue.getMessage(), TestResource.getResource("R_unexpectedExceptionContent")); + } catch (BatchUpdateException bue) { + assertEquals("A result set was generated for update.", bue.getMessage(), + TestResource.getResource("R_unexpectedExceptionContent")); assertEquals(Arrays.equals(bue.getUpdateCounts(), new int[] {-3, 1, -3, 1}), true, TestResource.getResource("R_incorrectUpdateCount")); } @@ -237,15 +234,15 @@ private void Repro47239Internal(String mode) throws Exception { stmt.addBatch(insertStmt); try { stmt.executeBatch(); - } - catch (BatchUpdateException bue) { + } catch (BatchUpdateException bue) { assertThat(bue.getMessage(), containsString(TestResource.getResource("R_syntaxErrorDateConvert"))); - // CTestLog.CompareStartsWith(bue.getMessage(), "Syntax error converting date", "Transaction rollback with conversion error threw wrong + // CTestLog.CompareStartsWith(bue.getMessage(), "Syntax error converting date", "Transaction + // rollback with conversion error threw wrong // BatchUpdateException"); - } - catch (SQLException e) { + } catch (SQLException e) { assertThat(e.getMessage(), containsString(TestResource.getResource("R_dateConvertError"))); - // CTestLog.CompareStartsWith(e.getMessage(), "Conversion failed when converting date", "Transaction rollback with conversion error threw + // CTestLog.CompareStartsWith(e.getMessage(), "Conversion failed when converting date", "Transaction + // rollback with conversion error threw // wrong SQLException"); } @@ -253,11 +250,14 @@ private void Repro47239Internal(String mode) throws Exception { // On SQL Azure, raising FATAL error by RAISERROR() is not supported and there is no way to // cut the current connection by a statement inside a SQL batch. - // Details: Although one can simulate a fatal error (that cuts the connections) by dropping the database, + // Details: Although one can simulate a fatal error (that cuts the connections) by dropping the + // database, // this simulation cannot be written entirely in TSQL (because it needs a new connection), // and thus it cannot be put into a TSQL batch and it is useless here. - // So we have to skip the last scenario of this test case, i.e. "Test Severe (connection-closing) errors" - // It is worthwhile to still execute the first 5 test scenarios of this test case, in order to have best test coverage. + // So we have to skip the last scenario of this test case, i.e. "Test Severe (connection-closing) + // errors" + // It is worthwhile to still execute the first 5 test scenarios of this test case, in order to have best + // test coverage. if (!DBConnection.isSqlAzure(conn)) { // Test Severe (connection-closing) errors stmt.addBatch(error); @@ -273,44 +273,45 @@ private void Repro47239Internal(String mode) throws Exception { stmt.executeBatch(); // Test fatal errors batch execution succeeded (should have failed) assertEquals(false, true, TestResource.getResource("R_shouldThrowException")); - } - catch (BatchUpdateException bue) { + } catch (BatchUpdateException bue) { // Test fatal errors returned BatchUpdateException rather than SQLException assertEquals(false, true, TestResource.getResource("R_unexpectedException") + bue.getMessage()); - } - catch (SQLException e) { + } catch (SQLException e) { actualExceptionText = e.getMessage(); if (actualExceptionText.endsWith("reset")) { - assertTrue(actualExceptionText.equalsIgnoreCase("Connection reset"), TestResource.getResource("R_unexpectedExceptionContent") + ": " + actualExceptionText); - } - else { - assertTrue(actualExceptionText.equalsIgnoreCase("raiserror level 20"), TestResource.getResource("R_unexpectedExceptionContent") + ": " + actualExceptionText); + assertTrue(actualExceptionText.equalsIgnoreCase("Connection reset"), + TestResource.getResource("R_unexpectedExceptionContent") + ": " + + actualExceptionText); + } else { + assertTrue(actualExceptionText.equalsIgnoreCase("raiserror level 20"), + TestResource.getResource("R_unexpectedExceptionContent") + ": " + + actualExceptionText); } } } try { stmt.executeUpdate("drop table " + tableName); - } - catch (Exception ignored) { - } + } catch (Exception ignored) {} } } } - + private void Repro47239largeInternal(String mode) throws Exception { - assumeTrue("JDBC42".equals(Utils.getConfiguredProperty("JDBC_Version")), TestResource.getResource("R_incompatJDBC")); + assumeTrue("JDBC42".equals(Utils.getConfiguredProperty("JDBC_Version")), + TestResource.getResource("R_incompatJDBC")); // the DBConnection for detecting whether the server is SQL Azure or SQL Server. con = DriverManager.getConnection(connectionString); final String warning; final String error; final String severe; if (DBConnection.isSqlAzure(con)) { - // SQL Azure will throw exception for "raiserror WITH LOG", so the following RAISERROR statements have not "with log" option + // SQL Azure will throw exception for "raiserror WITH LOG", so the following RAISERROR statements have not + // "with log" option warning = "RAISERROR ('raiserror level 4',4,1)"; error = "RAISERROR ('raiserror level 11',11,1)"; // On SQL Azure, raising FATAL error by RAISERROR() is not supported and there is no way to @@ -319,10 +320,11 @@ private void Repro47239largeInternal(String mode) throws Exception { // this simulation cannot be written entirely in TSQL (because it needs a new connection), // and thus it cannot be put into a TSQL batch and it is useless here. // So we have to skip the last scenario of this test case, i.e. "Test Severe (connection-closing) errors" - // It is worthwhile to still execute the first 5 test scenarios of this test case, in order to have best test coverage. - severe = "--Not executed when testing against SQL Azure"; // this is a dummy statement that never being executed on SQL Azure - } - else { + // It is worthwhile to still execute the first 5 test scenarios of this test case, in order to have best + // test coverage. + severe = "--Not executed when testing against SQL Azure"; // this is a dummy statement that never being + // executed on SQL Azure + } else { warning = "RAISERROR ('raiserror level 4',4,1) WITH LOG"; error = "RAISERROR ('raiserror level 11',11,1) WITH LOG"; severe = "RAISERROR ('raiserror level 20',20,1) WITH LOG"; @@ -335,7 +337,7 @@ private void Repro47239largeInternal(String mode) throws Exception { // SQL Server 2005 driver Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); - + try (Connection conn = DriverManager.getConnection(connectionString)) { if (mode.equalsIgnoreCase("bulkcopy")) { modifyConnectionForBulkCopyAPI((SQLServerConnection) conn); @@ -344,15 +346,11 @@ private void Repro47239largeInternal(String mode) throws Exception { try { Utils.dropTableIfExists(tableName, stmt); - } - catch (Exception ignored) { - } + } catch (Exception ignored) {} try { - stmt.executeLargeUpdate( - "create table " + tableName + " (c1_int int, c2_varchar varchar(20), c3_date datetime, c4_int int identity(1,1) primary key)"); - } - catch (Exception ignored) { - } + stmt.executeLargeUpdate("create table " + tableName + + " (c1_int int, c2_varchar varchar(20), c3_date datetime, c4_int int identity(1,1) primary key)"); + } catch (Exception ignored) {} // Regular Statement batch update expectedUpdateCounts = new long[] {1, -2, 1, -2, 1, -2}; Statement batchStmt = conn.createStatement(); @@ -365,13 +363,11 @@ private void Repro47239largeInternal(String mode) throws Exception { try { actualUpdateCounts = batchStmt.executeLargeBatch(); actualExceptionText = ""; - } - catch (BatchUpdateException bue) { + } catch (BatchUpdateException bue) { actualUpdateCounts = bue.getLargeUpdateCounts(); actualExceptionText = bue.getMessage(); log.fine("BatchUpdateException occurred. Message:" + actualExceptionText); - } - finally { + } finally { batchStmt.close(); } log.fine("UpdateCounts:"); @@ -379,7 +375,8 @@ private void Repro47239largeInternal(String mode) throws Exception { log.fine("" + updateCount + ","); } log.fine(""); - assertTrue(Arrays.equals(actualUpdateCounts, expectedUpdateCounts), TestResource.getResource("R_testInterleaved")); + assertTrue(Arrays.equals(actualUpdateCounts, expectedUpdateCounts), + TestResource.getResource("R_testInterleaved")); expectedUpdateCounts = new long[] {-3, 1, 1, 1}; stmt.addBatch(error); @@ -389,8 +386,7 @@ private void Repro47239largeInternal(String mode) throws Exception { try { actualUpdateCounts = stmt.executeLargeBatch(); actualExceptionText = ""; - } - catch (BatchUpdateException bue) { + } catch (BatchUpdateException bue) { actualUpdateCounts = bue.getLargeUpdateCounts(); actualExceptionText = bue.getMessage(); } @@ -399,7 +395,8 @@ private void Repro47239largeInternal(String mode) throws Exception { log.fine("" + updateCount + ","); } log.fine(""); - assertTrue(Arrays.equals(actualUpdateCounts, expectedUpdateCounts), TestResource.getResource("R_errorFollowInserts")); + assertTrue(Arrays.equals(actualUpdateCounts, expectedUpdateCounts), + TestResource.getResource("R_errorFollowInserts")); // 50280 expectedUpdateCounts = new long[] {1, -3}; @@ -408,8 +405,7 @@ private void Repro47239largeInternal(String mode) throws Exception { try { actualUpdateCounts = stmt.executeLargeBatch(); actualExceptionText = ""; - } - catch (BatchUpdateException bue) { + } catch (BatchUpdateException bue) { actualUpdateCounts = bue.getLargeUpdateCounts(); actualExceptionText = bue.getMessage(); } @@ -417,7 +413,8 @@ private void Repro47239largeInternal(String mode) throws Exception { log.fine("" + updateCount + ","); } log.fine(""); - assertTrue(Arrays.equals(actualUpdateCounts, expectedUpdateCounts), TestResource.getResource("R_errorFollow50280")); + assertTrue(Arrays.equals(actualUpdateCounts, expectedUpdateCounts), + TestResource.getResource("R_errorFollow50280")); // Test "soft" errors conn.setAutoCommit(false); @@ -429,10 +426,10 @@ private void Repro47239largeInternal(String mode) throws Exception { stmt.executeLargeBatch(); // Soft error test: executeLargeBatch unexpectedly succeeded assertEquals(false, true, TestResource.getResource("R_shouldThrowException")); - } - catch (BatchUpdateException bue) { + } catch (BatchUpdateException bue) { // Soft error test: wrong error message in BatchUpdateException - assertEquals("A result set was generated for update.", bue.getMessage(), TestResource.getResource("R_unexpectedExceptionContent")); + assertEquals("A result set was generated for update.", bue.getMessage(), + TestResource.getResource("R_unexpectedExceptionContent")); // Soft error test: wrong update counts in BatchUpdateException assertEquals(Arrays.equals(bue.getLargeUpdateCounts(), new long[] {-3, 1, -3, 1}), true, TestResource.getResource("R_incorrectUpdateCount")); @@ -446,11 +443,9 @@ private void Repro47239largeInternal(String mode) throws Exception { stmt.addBatch(insertStmt); try { stmt.executeLargeBatch(); - } - catch (BatchUpdateException bue) { + } catch (BatchUpdateException bue) { assertThat(bue.getMessage(), containsString(TestResource.getResource("R_syntaxErrorDateConvert"))); - } - catch (SQLException e) { + } catch (SQLException e) { assertThat(e.getMessage(), containsString(TestResource.getResource("R_dateConvertError"))); } @@ -458,11 +453,14 @@ private void Repro47239largeInternal(String mode) throws Exception { // On SQL Azure, raising FATAL error by RAISERROR() is not supported and there is no way to // cut the current connection by a statement inside a SQL batch. - // Details: Although one can simulate a fatal error (that cuts the connections) by dropping the database, + // Details: Although one can simulate a fatal error (that cuts the connections) by dropping the + // database, // this simulation cannot be written entirely in TSQL (because it needs a new connection), // and thus it cannot be put into a TSQL batch and it is useless here. - // So we have to skip the last scenario of this test case, i.e. "Test Severe (connection-closing) errors" - // It is worthwhile to still execute the first 5 test scenarios of this test case, in order to have best test coverage. + // So we have to skip the last scenario of this test case, i.e. "Test Severe (connection-closing) + // errors" + // It is worthwhile to still execute the first 5 test scenarios of this test case, in order to have best + // test coverage. if (!DBConnection.isSqlAzure(DriverManager.getConnection(connectionString))) { // Test Severe (connection-closing) errors stmt.addBatch(error); @@ -477,19 +475,20 @@ private void Repro47239largeInternal(String mode) throws Exception { stmt.executeLargeBatch(); // Test fatal errors batch execution succeeded (should have failed) assertEquals(false, true, TestResource.getResource("R_shouldThrowException")); - } - catch (BatchUpdateException bue) { + } catch (BatchUpdateException bue) { // Test fatal errors returned BatchUpdateException rather than SQLException assertEquals(false, true, TestResource.getResource("R_unexpectedException") + bue.getMessage()); - } - catch (SQLException e) { + } catch (SQLException e) { actualExceptionText = e.getMessage(); if (actualExceptionText.endsWith("reset")) { - assertTrue(actualExceptionText.equalsIgnoreCase("Connection reset"), TestResource.getResource("R_unexpectedExceptionContent") + ": " + actualExceptionText); - } - else { - assertTrue(actualExceptionText.equalsIgnoreCase("raiserror level 20"), TestResource.getResource("R_unexpectedExceptionContent") + ": " + actualExceptionText); + assertTrue(actualExceptionText.equalsIgnoreCase("Connection reset"), + TestResource.getResource("R_unexpectedExceptionContent") + ": " + + actualExceptionText); + } else { + assertTrue(actualExceptionText.equalsIgnoreCase("raiserror level 20"), + TestResource.getResource("R_unexpectedExceptionContent") + ": " + + actualExceptionText); } } @@ -497,18 +496,16 @@ private void Repro47239largeInternal(String mode) throws Exception { try { stmt.executeLargeUpdate("drop table " + tableName); - } - catch (Exception ignored) { - } + } catch (Exception ignored) {} } } } - + private void modifyConnectionForBulkCopyAPI(SQLServerConnection con) throws Exception { Field f1 = SQLServerConnection.class.getDeclaredField("isAzureDW"); f1.setAccessible(true); f1.set(con, true); - + con.setUseBulkCopyForBatchInsert(true); } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/BatchExecutionTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/BatchExecutionTest.java index a4e7004be..d572b62ca 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/BatchExecutionTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/BatchExecutionTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.unit.statement; @@ -33,6 +30,7 @@ import com.microsoft.sqlserver.testframework.DBConnection; import com.microsoft.sqlserver.testframework.Utils; + /** * Tests batch execution with AE On connection * @@ -47,8 +45,9 @@ public class BatchExecutionTest extends AbstractTest { static ResultSet rs = null; /** - * testAddBatch1 and testExecutionBatch one looks similar except for the parameters being passed for select query. + * testAddBatch1 and testExecutionBatch one looks similar except for the parameters being passed for select query. * TODO: we should look and simply the test later by parameterized values + * * @throws Exception */ @Test @@ -60,8 +59,8 @@ public void testBatchExceptionAEOn() throws Exception { } /** - * Get a PreparedStatement object and call the addBatch() method with 3 SQL statements and call the executeBatch() method and it should return - * array of Integer values of length 3 + * Get a PreparedStatement object and call the addBatch() method with 3 SQL statements and call the executeBatch() + * method and it should return array of Integer values of length 3 */ public void testAddBatch1() { testAddBatch1Internal("BatchInsert"); @@ -72,28 +71,29 @@ public void testAddBatch1UseBulkCopyAPI() { } /** - * Get a PreparedStatement object and call the addBatch() method with a 3 valid SQL statements and call the executeBatch() method It should return - * an array of Integer values of length 3. + * Get a PreparedStatement object and call the addBatch() method with a 3 valid SQL statements and call the + * executeBatch() method It should return an array of Integer values of length 3. */ public void testExecuteBatch1() { testExecuteBatch1Internal("BatchInsert"); } - + public void testExecuteBatch1UseBulkCopyAPI() { testExecuteBatch1Internal("BulkCopy"); } - + private void testExecuteBatch1Internal(String mode) { int i = 0; int retValue[] = {0, 0, 0}; int updateCountlen = 0; - try (Connection connection = DriverManager.getConnection(connectionString + ";columnEncryptionSetting=Enabled;");){ + try (Connection connection = DriverManager + .getConnection(connectionString + ";columnEncryptionSetting=Enabled;");) { String sPrepStmt = "update ctstable2 set PRICE=PRICE*20 where TYPE_ID=?"; if (mode.equalsIgnoreCase("bulkcopy")) { modifyConnectionForBulkCopyAPI((SQLServerConnection) connection); } - + pstmt = connection.prepareStatement(sPrepStmt); pstmt.setInt(1, 1); pstmt.addBatch(); @@ -107,7 +107,8 @@ private void testExecuteBatch1Internal(String mode) { int[] updateCount = pstmt.executeBatch(); updateCountlen = updateCount.length; - assertTrue(updateCountlen == 3, TestResource.getResource("R_executeBatchFailed") + ": " + TestResource.getResource("R_incorrectUpdateCount")); + assertTrue(updateCountlen == 3, TestResource.getResource("R_executeBatchFailed") + ": " + + TestResource.getResource("R_incorrectUpdateCount")); String sPrepStmt1 = "select count(*) from ctstable2 where TYPE_ID=?"; @@ -124,11 +125,11 @@ private void testExecuteBatch1Internal(String mode) { for (int j = 0; j < updateCount.length; j++) { if (updateCount[j] != retValue[j] && updateCount[j] != Statement.SUCCESS_NO_INFO) { - fail(TestResource.getResource("R_executeBatchFailed") + ": " + TestResource.getResource("R_incorrectUpdateCount")); + fail(TestResource.getResource("R_executeBatchFailed") + ": " + + TestResource.getResource("R_incorrectUpdateCount")); } } - } - catch (Exception e) { + } catch (Exception e) { fail(TestResource.getResource("R_executeBatchFailed") + ": " + e.getMessage()); } } @@ -154,17 +155,18 @@ private static void createTable() throws SQLException { stmt.execute(sqlin1); } - + private void testAddBatch1Internal(String mode) { int i = 0; int retValue[] = {0, 0, 0}; - try (Connection connection = DriverManager.getConnection(connectionString + ";columnEncryptionSetting=Enabled;");){ + try (Connection connection = DriverManager + .getConnection(connectionString + ";columnEncryptionSetting=Enabled;");) { String sPrepStmt = "update ctstable2 set PRICE=PRICE*20 where TYPE_ID=?"; - + if (mode.equalsIgnoreCase("bulkcopy")) { modifyConnectionForBulkCopyAPI((SQLServerConnection) connection); } - + pstmt = connection.prepareStatement(sPrepStmt); pstmt.setInt(1, 2); pstmt.addBatch(); @@ -178,7 +180,8 @@ private void testAddBatch1Internal(String mode) { int[] updateCount = pstmt.executeBatch(); int updateCountlen = updateCount.length; - assertTrue(updateCountlen == 3, TestResource.getResource("R_addBatchFailed") + ": " + TestResource.getResource("R_incorrectUpdateCount")); + assertTrue(updateCountlen == 3, TestResource.getResource("R_addBatchFailed") + ": " + + TestResource.getResource("R_incorrectUpdateCount")); String sPrepStmt1 = "select count(*) from ctstable2 where TYPE_ID=?"; @@ -200,17 +203,16 @@ private void testAddBatch1Internal(String mode) { fail(TestResource.getResource("R_incorrectUpdateCount")); } } - } - catch (Exception e) { + } catch (Exception e) { fail(TestResource.getResource("R_addBatchFailed") + ": " + e.getMessage()); } } - + private void modifyConnectionForBulkCopyAPI(SQLServerConnection con) throws Exception { Field f1 = SQLServerConnection.class.getDeclaredField("isAzureDW"); f1.setAccessible(true); f1.set(con, true); - + con.setUseBulkCopyForBatchInsert(true); } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/BatchTriggerTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/BatchTriggerTest.java index 5115a1f7f..2223f612d 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/BatchTriggerTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/BatchTriggerTest.java @@ -1,12 +1,12 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.unit.statement; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; @@ -19,14 +19,13 @@ import org.junit.platform.runner.JUnitPlatform; import org.junit.runner.RunWith; import org.opentest4j.TestAbortedException; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; import com.microsoft.sqlserver.jdbc.SQLServerStatement; import com.microsoft.sqlserver.jdbc.TestResource; import com.microsoft.sqlserver.testframework.AbstractTest; import com.microsoft.sqlserver.testframework.Utils; + /** * Tests batch execution with trigger exception * @@ -38,7 +37,8 @@ public class BatchTriggerTest extends AbstractTest { static Connection connection = null; static String tableName = "triggerTable"; static String triggerName = "triggerTest"; - static String insertQuery = "insert into " + tableName + " (col1, col2, col3, col4) values (1, '22-08-2017 17:30:00.000', 'R4760', 31)"; + static String insertQuery = "insert into " + tableName + + " (col1, col2, col3, col4) values (1, '22-08-2017 17:30:00.000', 'R4760', 31)"; /** * Tests that the proper trigger exception is thrown using statement @@ -53,8 +53,7 @@ public void statementTest() throws SQLException { stmt.addBatch(insertQuery); stmt.executeBatch(); fail(TestResource.getResource("R_expectedExceptionNotThrown")); - } - catch (Exception e) { + } catch (Exception e) { assertTrue(e.getMessage().equalsIgnoreCase(TestResource.getResource("R_customErrorMessage"))); } @@ -78,12 +77,10 @@ public void preparedStatementTest() throws SQLException { pstmt.addBatch(); pstmt.executeBatch(); fail(TestResource.getResource("R_expectedExceptionNotThrown")); - } - catch (Exception e) { + } catch (Exception e) { assertTrue(e.getMessage().equalsIgnoreCase(TestResource.getResource("R_customErrorMessage"))); - } - finally { + } finally { if (pstmt != null) { pstmt.close(); } @@ -97,9 +94,9 @@ public void preparedStatementTest() throws SQLException { * @throws SQLException */ private static void createTrigger(String triggerName) throws SQLException { - String sql = "create trigger " + triggerName + " on " + tableName + " for insert " + "as " + "begin " + "if (select col1 from " + tableName - + ") > 10 " + "begin " + "return " + "end " - + "RAISERROR ('" + TestResource.getResource("R_customErrorMessage") + "', 16, 0) " + "rollback transaction " + "end"; + String sql = "create trigger " + triggerName + " on " + tableName + " for insert " + "as " + "begin " + + "if (select col1 from " + tableName + ") > 10 " + "begin " + "return " + "end " + "RAISERROR ('" + + TestResource.getResource("R_customErrorMessage") + "', 16, 0) " + "rollback transaction " + "end"; stmt.execute(sql); } @@ -123,8 +120,9 @@ private static void createTable() throws SQLException { public static void testSetup() throws TestAbortedException, Exception { connection = DriverManager.getConnection(connectionString); stmt = (SQLServerStatement) connection.createStatement(); - stmt.execute("IF EXISTS (\r\n" + " SELECT *\r\n" + " FROM sys.objects\r\n" + " WHERE [type] = 'TR' AND [name] = '" + triggerName - + "'\r\n" + " )\r\n" + " DROP TRIGGER " + triggerName + ";"); + stmt.execute("IF EXISTS (\r\n" + " SELECT *\r\n" + " FROM sys.objects\r\n" + + " WHERE [type] = 'TR' AND [name] = '" + triggerName + "'\r\n" + " )\r\n" + " DROP TRIGGER " + + triggerName + ";"); dropTable(); createTable(); createTrigger(triggerName); @@ -147,8 +145,9 @@ private static void dropTable() throws SQLException { @AfterAll public static void terminateVariation() throws SQLException { dropTable(); - stmt.execute("IF EXISTS (\r\n" + " SELECT *\r\n" + " FROM sys.objects\r\n" + " WHERE [type] = 'TR' AND [name] = '" + triggerName - + "'\r\n" + " )\r\n" + " DROP TRIGGER " + triggerName + ";"); + stmt.execute("IF EXISTS (\r\n" + " SELECT *\r\n" + " FROM sys.objects\r\n" + + " WHERE [type] = 'TR' AND [name] = '" + triggerName + "'\r\n" + " )\r\n" + " DROP TRIGGER " + + triggerName + ";"); if (null != connection) { connection.close(); diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/CallableMixedTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/CallableMixedTest.java index ef0321af3..27269cf89 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/CallableMixedTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/CallableMixedTest.java @@ -1,12 +1,11 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.unit.statement; +import static org.junit.jupiter.api.Assertions.assertEquals; + import java.sql.CallableStatement; import java.sql.Connection; import java.sql.DriverManager; @@ -18,7 +17,6 @@ import org.junit.jupiter.api.Test; import org.junit.platform.runner.JUnitPlatform; import org.junit.runner.RunWith; -import static org.junit.jupiter.api.Assertions.assertEquals; import com.microsoft.sqlserver.jdbc.TestResource; import com.microsoft.sqlserver.testframework.AbstractSQLGenerator; @@ -26,6 +24,7 @@ import com.microsoft.sqlserver.testframework.Utils; import com.microsoft.sqlserver.testframework.util.RandomUtil; + /** * Callable Mix tests using stored procedure with input and output * @@ -46,16 +45,19 @@ public class CallableMixedTest extends AbstractTest { @Test @DisplayName("Test CallableMix") public void datatypesTest() throws SQLException { - try (Connection connection = DriverManager.getConnection(connectionString); Statement statement = connection.createStatement();) { + try (Connection connection = DriverManager.getConnection(connectionString); + Statement statement = connection.createStatement();) { statement.executeUpdate("create table " + tableName + " (c1_int int primary key, col2 int)"); statement.executeUpdate("Insert into " + tableName + " values(0, 1)"); statement.executeUpdate("CREATE PROCEDURE " + procName + " (@p2_int int, @p2_int_out int OUTPUT, @p4_smallint smallint, @p4_smallint_out smallint OUTPUT) AS begin transaction SELECT * FROM " - + tableName + " ; SELECT @p2_int_out=@p2_int, @p4_smallint_out=@p4_smallint commit transaction RETURN -2147483648"); + + tableName + + " ; SELECT @p2_int_out=@p2_int, @p4_smallint_out=@p4_smallint commit transaction RETURN -2147483648"); - try (CallableStatement callableStatement = connection.prepareCall("{ ? = CALL " + procName + " (?, ?, ?, ?) }")) { + try (CallableStatement callableStatement = connection + .prepareCall("{ ? = CALL " + procName + " (?, ?, ?, ?) }")) { callableStatement.registerOutParameter((int) 1, (int) 4); callableStatement.setObject((int) 2, Integer.valueOf("31"), (int) 4); callableStatement.registerOutParameter((int) 3, (int) 4); @@ -74,13 +76,15 @@ public void datatypesTest() throws SQLException { rs = callableStatement.executeQuery(); // get the param without getting the resultset rs = callableStatement.executeQuery(); - assertEquals(callableStatement.getInt((int) 1), -2147483648, TestResource.getResource("R_setDataNotEqual")); + assertEquals(callableStatement.getInt((int) 1), -2147483648, + TestResource.getResource("R_setDataNotEqual")); rs = callableStatement.executeQuery(); rs.next(); assertEquals(rs.getInt(1), 0, TestResource.getResource("R_setDataNotEqual")); - assertEquals(callableStatement.getInt((int) 1), -2147483648, TestResource.getResource("R_setDataNotEqual")); + assertEquals(callableStatement.getInt((int) 1), -2147483648, + TestResource.getResource("R_setDataNotEqual")); assertEquals(callableStatement.getInt((int) 5), -5372, TestResource.getResource("R_setDataNotEqual")); rs = callableStatement.executeQuery(); rs.close(); diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/LimitEscapeTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/LimitEscapeTest.java index b801cc10f..3a1461179 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/LimitEscapeTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/LimitEscapeTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.unit.statement; @@ -23,7 +20,6 @@ import java.util.Vector; import java.util.logging.Logger; -import org.junit.Before; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.DisplayName; @@ -35,6 +31,7 @@ import com.microsoft.sqlserver.testframework.AbstractTest; import com.microsoft.sqlserver.testframework.Utils; + /** * Testing with LimitEscape queries * @@ -62,29 +59,18 @@ static class Query { String exceptionMsg = null; /* - * This is used to test different SQL queries. Each SQL query to test is an instance of this class, and is initiated using this constructor. - * This constructor sets the expected results from the query and also verifies the translation by comparing it with manual translation. - * + * This is used to test different SQL queries. Each SQL query to test is an instance of this class, and is + * initiated using this constructor. This constructor sets the expected results from the query and also verifies + * the translation by comparing it with manual translation. * @param input The SQL query to test - * * @param output The manual translation of the query to verify with - * * @param rows The expected number of rows in ResultSet - * * @param columns The expected number of columns in ResultSet - * * @param ids The array of the expected id columns in the ResultSet - * * @param intCols The array of the expected int columns of each row in the ResultSet - * * @param stringCols The array of the expected String columns of each row in the ResultSet */ - Query(String input, - String output, - int rows, - int columns, - int[] ids, - int[][] intCols, + Query(String input, String output, int rows, int columns, int[] ids, int[][] intCols, String[][] stringCols) throws Exception { queryCount++; @@ -121,7 +107,6 @@ public void verifyTranslation() throws Exception { Object innerInstance = ctor.newInstance(); Method method = innerClass.getDeclaredMethod("translate", cArg); - method.setAccessible(true); Object str = method.invoke(innerInstance, inputSql); assertEquals(str, outputSql, TestResource.getResource("R_syntaxMatchError") + ": " + queryID); @@ -139,15 +124,14 @@ void executeSpecific(Connection conn) throws Exception { void execute(Connection conn) throws Exception { try { executeSpecific(conn); - } - catch (Exception e) { + } catch (Exception e) { if (null != exceptionMsg) { // This query is to verify right exception is thrown for errors in syntax. - assertTrue(e.getMessage().equalsIgnoreCase(exceptionMsg), TestResource.getResource("R_unexpectedExceptionContent") + e.getMessage()); + assertTrue(e.getMessage().equalsIgnoreCase(exceptionMsg), + TestResource.getResource("R_unexpectedExceptionContent") + e.getMessage()); // Exception message matched. Return as there is no result to verify. return; - } - else + } else throw e; } @@ -161,23 +145,28 @@ void execute(Connection conn) throws Exception { int rowCount = 0; while (resultSet.next()) { - // The int and string columns should be retrieved in order, for example cannot run a query that retrieves col2 but not col1 - assertEquals(resultSet.getInt(1), idCols[rowCount], TestResource.getResource("R_valueNotMatch") + queryID + ", row: " + rowCount); + // The int and string columns should be retrieved in order, for example cannot run a query that + // retrieves col2 but not col1 + assertEquals(resultSet.getInt(1), idCols[rowCount], + TestResource.getResource("R_valueNotMatch") + queryID + ", row: " + rowCount); for (int j = 0, colNumber = 1; null != intResultCols && j < intResultCols[rowCount].length; ++j) { String colName = "col" + colNumber; assertEquals(resultSet.getInt(colName), intResultCols[rowCount][j], - TestResource.getResource("R_valueNotMatch") + queryID + ", row: " + rowCount + ", column: " + colName); + TestResource.getResource("R_valueNotMatch") + queryID + ", row: " + rowCount + ", column: " + + colName); colNumber++; } for (int j = 0, colNumber = 3; null != stringResultCols && j < stringResultCols[rowCount].length; ++j) { String colName = "col" + colNumber; assertEquals(resultSet.getString(colName), stringResultCols[rowCount][j], - TestResource.getResource("R_valueNotMatch") + queryID + ", row: " + rowCount + ", column: " + colName); + TestResource.getResource("R_valueNotMatch") + queryID + ", row: " + rowCount + ", column: " + + colName); colNumber++; } rowCount++; } - assertEquals(rowCount, rows, TestResource.getResource("R_valueNotMatch") + "rowCount: " + rowCount + ", rows: " + rows); + assertEquals(rowCount, rows, + TestResource.getResource("R_valueNotMatch") + "rowCount: " + rowCount + ", rows: " + rows); assertEquals(resultSet.getMetaData().getColumnCount(), columns, "Column Count does not match"); } } @@ -185,14 +174,8 @@ void execute(Connection conn) throws Exception { static class PreparedQuery extends Query { int placeholderCount = 0; - PreparedQuery(String input, - String output, - int rows, - int columns, - int[] ids, - int[][] intCols, - String[][] stringCols, - int placeholderCount) throws Exception { + PreparedQuery(String input, String output, int rows, int columns, int[] ids, int[][] intCols, + String[][] stringCols, int placeholderCount) throws Exception { super(input, output, rows, columns, ids, intCols, stringCols); this.placeholderCount = placeholderCount; } @@ -207,14 +190,8 @@ void executeSpecific(Connection conn) throws Exception { } static class CallableQuery extends PreparedQuery { - CallableQuery(String input, - String output, - int rows, - int columns, - int[] ids, - int[][] intCols, - String[][] stringCols, - int placeholderCount) throws Exception { + CallableQuery(String input, String output, int rows, int columns, int[] ids, int[][] intCols, + String[][] stringCols, int placeholderCount) throws Exception { super(input, output, rows, columns, ids, intCols, stringCols, placeholderCount); } @@ -229,38 +206,24 @@ void execute(Connection conn) throws Exception { public static void createAndPopulateTables(Connection conn) throws Exception { Statement stmt = conn.createStatement(); - // Instead of table identifiers use some simple table names for this test only, as a lot of string manipulation is done + // Instead of table identifiers use some simple table names for this test only, as a lot of string manipulation + // is done // around table names. try { stmt.executeUpdate("drop table UnitStatement_LimitEscape_t1"); - } - catch (Exception ex) { - } - ; + } catch (Exception ex) {} ; try { stmt.executeUpdate("drop table UnitStatement_LimitEscape_t2"); - } - catch (Exception ex) { - } - ; + } catch (Exception ex) {} ; try { stmt.executeUpdate("drop table UnitStatement_LimitEscape_t3"); - } - catch (Exception ex) { - } - ; + } catch (Exception ex) {} ; try { stmt.executeUpdate("drop table UnitStatement_LimitEscape_t4"); - } - catch (Exception ex) { - } - ; + } catch (Exception ex) {} ; try { stmt.executeUpdate("drop procedure UnitStatement_LimitEscape_p1"); - } - catch (Exception ex) { - } - ; + } catch (Exception ex) {} ; stmt.executeUpdate( "create table UnitStatement_LimitEscape_t1 (col1 int, col2 int, col3 varchar(100), col4 varchar(100), id int identity(1,1) primary key)"); stmt.executeUpdate( @@ -284,6 +247,7 @@ public static void createAndPopulateTables(Connection conn) throws Exception { /** * Initialize and verify queries + * * @throws Exception */ @Test @@ -292,7 +256,8 @@ public void initAndVerifyQueries() throws Exception { Query qry; // 1 // Test whether queries without limit syntax works - qry = new Query("select TOP 1 * from UnitStatement_LimitEscape_t1", "select TOP 1 * from UnitStatement_LimitEscape_t1", 1, // # of rows + qry = new Query("select TOP 1 * from UnitStatement_LimitEscape_t1", + "select TOP 1 * from UnitStatement_LimitEscape_t1", 1, // # of rows 5, // # of columns new int[] {1}, // id column values new int[][] {{1, 1}}, // int column values @@ -301,12 +266,14 @@ public void initAndVerifyQueries() throws Exception { // 2 // Test parentheses in limit syntax - qry = new Query("select * from UnitStatement_LimitEscape_t1 {limit ( ( (2)))}", "select TOP ( ( (2))) * from UnitStatement_LimitEscape_t1", - 2, // # of rows + qry = new Query("select * from UnitStatement_LimitEscape_t1 {limit ( ( (2)))}", + "select TOP ( ( (2))) * from UnitStatement_LimitEscape_t1", 2, // # of rows 5, // # of columns new int[] {1, 2}, // id column values new int[][] {{1, 1}, {2, 2}}, // int column values - new String[][] {{"col3", "col4"}, {"row2 ' with ' quote", "row2 with limit {limit 22} {limit ?}"}}); // string column values + new String[][] {{"col3", "col4"}, {"row2 ' with ' quote", "row2 with limit {limit 22} {limit ?}"}}); // string + // column + // values qry.execute(conn); // 3 @@ -357,8 +324,10 @@ public void initAndVerifyQueries() throws Exception { // 7 // Test multiple parentheses in limit syntax and in subquery - qry = new Query("select id from (( (select * from UnitStatement_LimitEscape_t1 {limit 10})) ) t1 {limit ((1) )}", - "select TOP ((1) ) id from (( (select TOP 10 * from UnitStatement_LimitEscape_t1)) ) t1", 1, // # of rows + qry = new Query( + "select id from (( (select * from UnitStatement_LimitEscape_t1 {limit 10})) ) t1 {limit ((1) )}", + "select TOP ((1) ) id from (( (select TOP 10 * from UnitStatement_LimitEscape_t1)) ) t1", 1, // # of + // rows 1, // # of columns new int[] {1}, // id column values null, // int column values @@ -408,7 +377,9 @@ public void initAndVerifyQueries() throws Exception { 4, // # of columns new int[] {1, 2}, // id column values new int[][] {{1, 1}, {2, 2}}, // int column values - new String[][] {{"col3", "col4"}, {"row2 ' with ' quote", "row2 with limit {limit 22} {limit ?}"}}); // string column values + new String[][] {{"col3", "col4"}, {"row2 ' with ' quote", "row2 with limit {limit 22} {limit ?}"}}); // string + // column + // values qry.execute(conn); // 12 @@ -435,9 +406,10 @@ public void initAndVerifyQueries() throws Exception { // 14 // Test prepared statements with limit syntax - qry = new PreparedQuery("select * from UnitStatement_LimitEscape_t1 {limit (?)}", "select TOP (?) * from UnitStatement_LimitEscape_t1", 1, // # - // of - // rows + qry = new PreparedQuery("select * from UnitStatement_LimitEscape_t1 {limit (?)}", + "select TOP (?) * from UnitStatement_LimitEscape_t1", 1, // # + // of + // rows 5, // # of columns new int[] {1}, // id column values new int[][] {{1, 1}}, // int column values @@ -446,9 +418,10 @@ public void initAndVerifyQueries() throws Exception { // 15 // Test prepared statements with limit syntax with multiple parentheses/spaces - qry = new PreparedQuery("select * from UnitStatement_LimitEscape_t1 {limit ?}", "select TOP (?) * from UnitStatement_LimitEscape_t1", 1, // # - // of - // rows + qry = new PreparedQuery("select * from UnitStatement_LimitEscape_t1 {limit ?}", + "select TOP (?) * from UnitStatement_LimitEscape_t1", 1, // # + // of + // rows 5, // # of columns new int[] {1}, // id column values new int[][] {{1, 1}}, // int column values @@ -479,9 +452,10 @@ public void initAndVerifyQueries() throws Exception { // Test callable statements with limit syntax in string literals qry = new CallableQuery( "EXEC UnitStatement_LimitEscape_p1 @col3Value = 'row2 '' with '' quote', @col4Value = 'row2 with limit {limit 22} {limit ?}'", - "EXEC UnitStatement_LimitEscape_p1 @col3Value = 'row2 '' with '' quote', @col4Value = 'row2 with limit {limit 22} {limit ?}'", 1, // # - // of - // rows + "EXEC UnitStatement_LimitEscape_p1 @col3Value = 'row2 '' with '' quote', @col4Value = 'row2 with limit {limit 22} {limit ?}'", + 1, // # + // of + // rows 5, // # of columns new int[] {2}, // id column values new int[][] {{2, 2}}, // int column values @@ -497,7 +471,9 @@ public void initAndVerifyQueries() throws Exception { 5, // # of columns new int[] {3}, // id column values new int[][] {{3, 3}}, // int column values - new String[][] {{"row3 with subquery (select * from t1)", "row3 with subquery (select * from (select * from t1) {limit 4})"}}, 0); + new String[][] {{"row3 with subquery (select * from t1)", + "row3 with subquery (select * from (select * from t1) {limit 4})"}}, + 0); qry.execute(conn); // 20 @@ -514,8 +490,10 @@ public void initAndVerifyQueries() throws Exception { // 21 // Test callable statement escape syntax with quotes/scalar functions/limit syntax in string literals - qry = new CallableQuery("{call UnitStatement_LimitEscape_p1 ('select * from t1 {limit 4} ''quotes'' (braces)', 'ucase(scalar function)')}", - "EXEC UnitStatement_LimitEscape_p1 'select * from t1 {limit 4} ''quotes'' (braces)', 'ucase(scalar function)'", 1, // # of rows + qry = new CallableQuery( + "{call UnitStatement_LimitEscape_p1 ('select * from t1 {limit 4} ''quotes'' (braces)', 'ucase(scalar function)')}", + "EXEC UnitStatement_LimitEscape_p1 'select * from t1 {limit 4} ''quotes'' (braces)', 'ucase(scalar function)'", + 1, // # of rows 5, // # of columns new int[] {4}, // id column values new int[][] {{4, 4}}, // int column value @@ -526,20 +504,25 @@ public void initAndVerifyQueries() throws Exception { // Test callable statement escape syntax with openrowquery/openrowset/quotes in string literals qry = new CallableQuery( "{call UnitStatement_LimitEscape_p1 ('openquery(''server'', ''query'')', 'openrowset(''server'',''connection string'',''query'')')}", - "EXEC UnitStatement_LimitEscape_p1 'openquery(''server'', ''query'')', 'openrowset(''server'',''connection string'',''query'')'", 1, // # - // of - // rows + "EXEC UnitStatement_LimitEscape_p1 'openquery(''server'', ''query'')', 'openrowset(''server'',''connection string'',''query'')'", + 1, // # + // of + // rows 5, // # of columns new int[] {5}, // id column values new int[][] {{5, 5}}, // int column value - new String[][] {{"openquery('server', 'query')", "openrowset('server','connection string','query')"}}, 0); + new String[][] {{"openquery('server', 'query')", "openrowset('server','connection string','query')"}}, + 0); qry.execute(conn); // Do not execute this query as no lnked_server is setup. Only verify the translation for it. // 23 // Test openquery syntax translation with limit syntax - qry = new Query("select * from openquery('linked_server', 'select * from UnitStatement_LimitEscape_t1 {limit 2}') {limit 1}", - "select TOP 1 * from openquery('linked_server', 'select TOP 2 * from UnitStatement_LimitEscape_t1')", 1, // # of rows + qry = new Query( + "select * from openquery('linked_server', 'select * from UnitStatement_LimitEscape_t1 {limit 2}') {limit 1}", + "select TOP 1 * from openquery('linked_server', 'select TOP 2 * from UnitStatement_LimitEscape_t1')", 1, // # + // of + // rows 5, // # of columns new int[] {5}, // id column values new int[][] {{5, 5}}, // int column value @@ -571,8 +554,11 @@ public void initAndVerifyQueries() throws Exception { // Do not execute this query as it is a batch query, needs to be handled differently. // Only test the syntax translation. // Test batch query. - qry = new Query("select * from UnitStatement_LimitEscape_t1 {limit 1}; select * from UnitStatement_LimitEscape_t1 {limit 4}", - "select TOP 1 * from UnitStatement_LimitEscape_t1; select TOP 4 * from UnitStatement_LimitEscape_t1", 0, // # of rows + qry = new Query( + "select * from UnitStatement_LimitEscape_t1 {limit 1}; select * from UnitStatement_LimitEscape_t1 {limit 4}", + "select TOP 1 * from UnitStatement_LimitEscape_t1; select TOP 4 * from UnitStatement_LimitEscape_t1", 0, // # + // of + // rows 5, // # of columns null, // id column values null, // int column values @@ -615,8 +601,10 @@ public void initAndVerifyQueries() throws Exception { qry.execute(conn); // 29 - // Execute query, and verify exception for limit syntax error. The translator should leave the query unchanged as limit syntax is not correct. - qry = new Query("select * from UnitStatement_LimitEscape_t1 {limit1}", "select * from UnitStatement_LimitEscape_t1 {limit1}", 0, // # of rows + // Execute query, and verify exception for limit syntax error. The translator should leave the query unchanged + // as limit syntax is not correct. + qry = new Query("select * from UnitStatement_LimitEscape_t1 {limit1}", + "select * from UnitStatement_LimitEscape_t1 {limit1}", 0, // # of rows 0, // # of columns null, // id column values null, // int column values @@ -626,9 +614,11 @@ public void initAndVerifyQueries() throws Exception { qry.execute(conn); // 30 - // Execute query, and verify exception for limit syntax error. The translator should leave the query unchanged as limit syntax is not correct. - qry = new Query("select * from UnitStatement_LimitEscape_t1 {limit(1}", "select * from UnitStatement_LimitEscape_t1 {limit(1}", 0, // # of - // rows + // Execute query, and verify exception for limit syntax error. The translator should leave the query unchanged + // as limit syntax is not correct. + qry = new Query("select * from UnitStatement_LimitEscape_t1 {limit(1}", + "select * from UnitStatement_LimitEscape_t1 {limit(1}", 0, // # of + // rows 0, // # of columns null, // id column values null, // int column values @@ -638,7 +628,8 @@ public void initAndVerifyQueries() throws Exception { qry.execute(conn); // 31 - // Execute query, and verify exception for limit syntax error. The translator should leave the query unchanged as limit syntax is not correct. + // Execute query, and verify exception for limit syntax error. The translator should leave the query unchanged + // as limit syntax is not correct. qry = new Query("select * from UnitStatement_LimitEscape_t1 {limit 1 offset10}", "select * from UnitStatement_LimitEscape_t1 {limit 1 offset10}", 0, // # of rows 0, // # of columns @@ -650,7 +641,8 @@ public void initAndVerifyQueries() throws Exception { qry.execute(conn); // 32 - // Execute query, and verify exception for limit syntax error. The translator should leave the query unchanged as limit syntax is not correct. + // Execute query, and verify exception for limit syntax error. The translator should leave the query unchanged + // as limit syntax is not correct. qry = new Query("select * from UnitStatement_LimitEscape_t1 {limit1 offset 10}", "select * from UnitStatement_LimitEscape_t1 {limit1 offset 10}", 0, // # of rows 0, // # of columns @@ -662,7 +654,8 @@ public void initAndVerifyQueries() throws Exception { qry.execute(conn); // 33 - // Execute query, and verify exception for limit syntax error. The translator should leave the query unchanged as limit syntax is not correct. + // Execute query, and verify exception for limit syntax error. The translator should leave the query unchanged + // as limit syntax is not correct. qry = new Query("select * from UnitStatement_LimitEscape_t1 {limit1 offset10}", "select * from UnitStatement_LimitEscape_t1 {limit1 offset10}", 0, // # of rows 0, // # of columns @@ -674,7 +667,8 @@ public void initAndVerifyQueries() throws Exception { qry.execute(conn); // 34 - // Execute query, and verify exception for syntax error. The translator should leave the query unchanged as limit syntax is not correct. + // Execute query, and verify exception for syntax error. The translator should leave the query unchanged as + // limit syntax is not correct. qry = new Query("insert into UnitStatement_LimitEscape_t1(col3) values({limit 1})", "insert into UnitStatement_LimitEscape_t1(col3) values({limit 1})", 0, // # of rows 0, // # of columns @@ -686,10 +680,12 @@ public void initAndVerifyQueries() throws Exception { qry.execute(conn); // 35 - // Execute query, and verify exception for syntax error. The translator should leave the query unchanged as limit syntax is not correct. - qry = new Query("select * from UnitStatement_LimitEscape_t1 {limit {limit 5}}", "select TOP 5 * from UnitStatement_LimitEscape_t1 {limit}", 0, // # - // of - // rows + // Execute query, and verify exception for syntax error. The translator should leave the query unchanged as + // limit syntax is not correct. + qry = new Query("select * from UnitStatement_LimitEscape_t1 {limit {limit 5}}", + "select TOP 5 * from UnitStatement_LimitEscape_t1 {limit}", 0, // # + // of + // rows 0, // # of columns null, // id column values null, // int column values @@ -699,7 +695,8 @@ public void initAndVerifyQueries() throws Exception { qry.execute(conn); // 36 - // Execute query, and verify exception for syntax error. The translator should leave the query unchanged as limit syntax is not correct. + // Execute query, and verify exception for syntax error. The translator should leave the query unchanged as + // limit syntax is not correct. qry = new Query("select * from UnitStatement_LimitEscape_t1 {limit 1} {limit 2}", "select TOP 1 * from UnitStatement_LimitEscape_t1 {limit 2}", 0, // # of rows 0, // # of columns @@ -715,11 +712,12 @@ public void initAndVerifyQueries() throws Exception { /** * Verify offset Exception + * * @throws Exception */ @Test @DisplayName("verifyOffsetException") - public void verifyOffsetException() throws Exception { + public void verifyOffsetException() throws Exception { offsetQuery.addElement("select * from UnitStatement_LimitEscape_t1 {limit 2 offset 1}"); offsetQuery.addElement("select * from UnitStatement_LimitEscape_t1 {limit 2232 offset 1232}"); offsetQuery.addElement("select * from UnitStatement_LimitEscape_t1 {limit (2) offset (1)}"); @@ -756,7 +754,7 @@ public void verifyOffsetException() throws Exception { catch (InvocationTargetException e) { assertEquals(e.toString(), "java.lang.reflect.InvocationTargetException"); } - } + } /** * clean up @@ -766,14 +764,14 @@ public static void beforeAll() { try { conn = DriverManager.getConnection(connectionString); createAndPopulateTables(conn); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } /** * Clean up + * * @throws Exception */ @AfterAll @@ -785,11 +783,9 @@ public static void afterAll() throws Exception { Utils.dropTableIfExists("UnitStatement_LimitEscape_t2", stmt); Utils.dropTableIfExists("UnitStatement_LimitEscape_t3", stmt); Utils.dropTableIfExists("UnitStatement_LimitEscape_t4", stmt); - } - catch (Exception ex) { + } catch (Exception ex) { fail(ex.toString()); - } - finally { + } finally { stmt.close(); conn.close(); } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/MergeTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/MergeTest.java index 5f681796a..335f1283e 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/MergeTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/MergeTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.unit.statement; @@ -27,6 +24,7 @@ import com.microsoft.sqlserver.testframework.DBStatement; import com.microsoft.sqlserver.testframework.Utils; + /** * Testing merge queries */ @@ -41,11 +39,13 @@ public class MergeTest extends AbstractTest { + "INSERT INTO dbo.CricketTeams_UpdatedList VALUES (1, 'Australia', 'Australia'), (2, 'India', 'Asia'), (3, 'Pakistan', 'Asia'), (4, 'Srilanka', 'Asia'), (5, 'Bangaladesh', 'Asia')," + " (6, 'Thailand', 'Asia'), (8, 'England', 'Europe'), (9, 'South Africa', 'Africa'), (10, 'West Indies', 'North America'), (11, 'Zimbabwe', 'Africa');"; - private static final String mergeCmd2 = "MERGE dbo.CricketTeams AS TARGET " + "USING dbo.CricketTeams_UpdatedList AS SOURCE " - + "ON (TARGET.CricketTeamID = SOURCE.CricketTeamID) " + "WHEN MATCHED AND TARGET.CricketTeamContinent <> SOURCE.CricketTeamContinent OR " + private static final String mergeCmd2 = "MERGE dbo.CricketTeams AS TARGET " + + "USING dbo.CricketTeams_UpdatedList AS SOURCE " + "ON (TARGET.CricketTeamID = SOURCE.CricketTeamID) " + + "WHEN MATCHED AND TARGET.CricketTeamContinent <> SOURCE.CricketTeamContinent OR " + "TARGET.CricketTeamCountry <> SOURCE.CricketTeamCountry " - + "THEN UPDATE SET TARGET.CricketTeamContinent = SOURCE.CricketTeamContinent ," + "TARGET.CricketTeamCountry = SOURCE.CricketTeamCountry " - + "WHEN NOT MATCHED THEN " + "INSERT (CricketTeamID, CricketTeamCountry, CricketTeamContinent) " + + "THEN UPDATE SET TARGET.CricketTeamContinent = SOURCE.CricketTeamContinent ," + + "TARGET.CricketTeamCountry = SOURCE.CricketTeamCountry " + "WHEN NOT MATCHED THEN " + + "INSERT (CricketTeamID, CricketTeamCountry, CricketTeamContinent) " + "VALUES (SOURCE.CricketTeamID, SOURCE.CricketTeamCountry, SOURCE.CricketTeamContinent) " + "WHEN NOT MATCHED BY SOURCE THEN DELETE;"; @@ -59,7 +59,8 @@ public class MergeTest extends AbstractTest { public void runTest() throws Exception { try (DBConnection conn = new DBConnection(connectionString)) { if (conn.getServerVersion() >= 10) { - try (DBStatement stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE);) { + try (DBStatement stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, + ResultSet.CONCUR_UPDATABLE);) { stmt.executeUpdate(setupTables); stmt.executeUpdate(mergeCmd2); int updateCount = stmt.getUpdateCount(); @@ -81,8 +82,7 @@ public static void afterAll() throws Exception { try (Connection con = DriverManager.getConnection(connectionString); Statement stmt = con.createStatement()) { try { Utils.dropTableIfExists("dbo.CricketTeams", stmt); - } - catch (Exception ex) { + } catch (Exception ex) { fail(ex.toString()); } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/NamedParamMultiPartTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/NamedParamMultiPartTest.java index 62997ffcc..6966889dd 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/NamedParamMultiPartTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/NamedParamMultiPartTest.java @@ -1,14 +1,10 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.unit.statement; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.fail; import java.sql.CallableStatement; import java.sql.Connection; @@ -27,6 +23,7 @@ import com.microsoft.sqlserver.testframework.AbstractTest; import com.microsoft.sqlserver.testframework.Utils; + /** * Multipart parameters * @@ -47,7 +44,8 @@ public static void beforeAll() throws SQLException { connection = DriverManager.getConnection(connectionString); try (Statement statement = connection.createStatement()) { Utils.dropProcedureIfExists("mystoredproc", statement); - statement.executeUpdate("CREATE PROCEDURE [mystoredproc] (@p_out varchar(255) OUTPUT) AS set @p_out = '" + dataPut + "'"); + statement.executeUpdate( + "CREATE PROCEDURE [mystoredproc] (@p_out varchar(255) OUTPUT) AS set @p_out = '" + dataPut + "'"); } } @@ -153,8 +151,7 @@ public void update6() throws Exception { public static void afterAll() throws SQLException { try (Statement stmt = connection.createStatement()) { Utils.dropProcedureIfExists("mystoredproc", stmt); - } - finally { + } finally { if (connection != null) { connection.close(); } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/PQImpsTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/PQImpsTest.java index 210dd264c..79fd32e6b 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/PQImpsTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/PQImpsTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.unit.statement; @@ -33,6 +30,7 @@ import com.microsoft.sqlserver.testframework.Utils; import com.microsoft.sqlserver.testframework.util.RandomUtil; + /** * Tests different kinds of queries * @@ -49,14 +47,20 @@ public class PQImpsTest extends AbstractTest { private static int version = -1; private static String nameTable = AbstractSQLGenerator.escapeIdentifier(RandomUtil.getIdentifier("names_DB")); - private static String phoneNumberTable = AbstractSQLGenerator.escapeIdentifier(RandomUtil.getIdentifier("phoneNumbers_DB")); - private static String mergeNameDesTable = AbstractSQLGenerator.escapeIdentifier(RandomUtil.getIdentifier("mergeNameDesTable_DB")); - private static String numericTable = AbstractSQLGenerator.escapeIdentifier(RandomUtil.getIdentifier("numericTable_DB")); + private static String phoneNumberTable = AbstractSQLGenerator + .escapeIdentifier(RandomUtil.getIdentifier("phoneNumbers_DB")); + private static String mergeNameDesTable = AbstractSQLGenerator + .escapeIdentifier(RandomUtil.getIdentifier("mergeNameDesTable_DB")); + private static String numericTable = AbstractSQLGenerator + .escapeIdentifier(RandomUtil.getIdentifier("numericTable_DB")); private static String charTable = AbstractSQLGenerator.escapeIdentifier(RandomUtil.getIdentifier("charTable_DB")); private static String charTable2 = AbstractSQLGenerator.escapeIdentifier(RandomUtil.getIdentifier("charTable2_DB")); - private static String binaryTable = AbstractSQLGenerator.escapeIdentifier(RandomUtil.getIdentifier("binaryTable_DB")); - private static String dateAndTimeTable = AbstractSQLGenerator.escapeIdentifier(RandomUtil.getIdentifier("dateAndTimeTable_DB")); - private static String multipleTypesTable = AbstractSQLGenerator.escapeIdentifier(RandomUtil.getIdentifier("multipleTypesTable_DB")); + private static String binaryTable = AbstractSQLGenerator + .escapeIdentifier(RandomUtil.getIdentifier("binaryTable_DB")); + private static String dateAndTimeTable = AbstractSQLGenerator + .escapeIdentifier(RandomUtil.getIdentifier("dateAndTimeTable_DB")); + private static String multipleTypesTable = AbstractSQLGenerator + .escapeIdentifier(RandomUtil.getIdentifier("multipleTypesTable_DB")); private static String spaceTable = AbstractSQLGenerator.escapeIdentifier(RandomUtil.getIdentifier("spaceTable_DB")); /** @@ -102,8 +106,7 @@ public void numericTest() throws SQLException { } deleteNumeric(); checkNumericMetaData(); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } @@ -129,8 +132,7 @@ public void charTests() throws SQLException { } deleteChar(); checkCharMetaData(4); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } @@ -158,8 +160,7 @@ public void binaryTests() throws SQLException { } deleteBinary(); checkBinaryMetaData(); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } @@ -187,8 +188,7 @@ public void temporalTests() throws SQLException { } deleteDateAndTime(); checkDateAndTimeMetaData(); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } @@ -208,8 +208,7 @@ public void MultipleTypesTableTest() throws Exception { testInsertMultipleTypes(); testMixedWithHardcodedValues(); } - } - catch (SQLException e) { + } catch (SQLException e) { fail(e.toString()); } @@ -290,57 +289,50 @@ private static void checkDateAndTimeMetaData() throws SQLException { compareParameterMetaData(pmd, 9, "java.sql.Time", 92, "time", 14, 5); } - private static void compareParameterMetaData(ParameterMetaData pmd, - int index, - String expectedClassName, - int expectedType, - String expectedTypeName, - int expectedPrecision, - int expectedScale) { + private static void compareParameterMetaData(ParameterMetaData pmd, int index, String expectedClassName, + int expectedType, String expectedTypeName, int expectedPrecision, int expectedScale) { try { assertTrue(pmd.getParameterClassName(index).equalsIgnoreCase(expectedClassName), - "Parameter class Name error:\n" + "expected: " + expectedClassName + "\n" + "actual: " + pmd.getParameterClassName(index)); - } - catch (SQLException e) { + "Parameter class Name error:\n" + "expected: " + expectedClassName + "\n" + "actual: " + + pmd.getParameterClassName(index)); + } catch (SQLException e) { fail(e.toString()); } try { - assertTrue(pmd.getParameterType(index) == expectedType, - "getParameterType: " + TestResource.getResource("R_valueNotMatch") + expectedType + ", " + pmd.getParameterType(index)); - } - catch (SQLException e) { + assertTrue(pmd.getParameterType(index) == expectedType, "getParameterType: " + + TestResource.getResource("R_valueNotMatch") + expectedType + ", " + pmd.getParameterType(index)); + } catch (SQLException e) { fail(e.toString()); } try { assertTrue(pmd.getParameterTypeName(index).equalsIgnoreCase(expectedTypeName), - "getParameterTypeName: " + TestResource.getResource("R_valueNotMatch") + expectedTypeName + ", " + pmd.getParameterTypeName(index)); - } - catch (SQLException e) { + "getParameterTypeName: " + TestResource.getResource("R_valueNotMatch") + expectedTypeName + ", " + + pmd.getParameterTypeName(index)); + } catch (SQLException e) { fail(e.toString()); } try { - assertTrue(pmd.getPrecision(index) == expectedPrecision, - "getPrecision: " + TestResource.getResource("R_valueNotMatch") + expectedPrecision + ", " + pmd.getPrecision(index)); - } - catch (SQLException e) { + assertTrue(pmd.getPrecision(index) == expectedPrecision, "getPrecision: " + + TestResource.getResource("R_valueNotMatch") + expectedPrecision + ", " + pmd.getPrecision(index)); + } catch (SQLException e) { fail(e.toString()); } try { - assertTrue(pmd.getScale(index) == expectedScale, - "getScale: " + TestResource.getResource("R_valueNotMatch") + expectedScale + ", " + pmd.getScale(index)); - } - catch (SQLException e) { + assertTrue(pmd.getScale(index) == expectedScale, "getScale: " + TestResource.getResource("R_valueNotMatch") + + expectedScale + ", " + pmd.getScale(index)); + } catch (SQLException e) { fail(e.toString()); } } private static void populateNumericTable() throws SQLException { - stmt.execute("insert into " + numericTable + " values (" + "1.123," + "1.123," + "1.2345," + "1.2345," + "1.543," + "1.543," + "5.1234," - + "104935," + "34323," + "123," + "5," + "1.45," + "1.3," + "0.123456789," + "0.1234567890123456789012345678901234567" + ")"); + stmt.execute("insert into " + numericTable + " values (" + "1.123," + "1.123," + "1.2345," + "1.2345," + + "1.543," + "1.543," + "5.1234," + "104935," + "34323," + "123," + "5," + "1.45," + "1.3," + + "0.123456789," + "0.1234567890123456789012345678901234567" + ")"); } private static void testBeforeExcute() throws SQLException { @@ -348,8 +340,9 @@ private static void testBeforeExcute() throws SQLException { pstmt.close(); } - String sql = "select * from " + numericTable + " where " + "c1 = ? and " + "c2 = ? and " + "c3 = ? and " + "c4 = ? and " + "c5 = ? and " - + "c6 = ? and " + "c7 = ? and " + "c8 = ? and " + "c9 = ? and " + "c10 = ? and " + "c11 = ? and " + "c12 = ? and " + "c13 = ? and " + "c14 = ? and " + "c15 = ? "; + String sql = "select * from " + numericTable + " where " + "c1 = ? and " + "c2 = ? and " + "c3 = ? and " + + "c4 = ? and " + "c5 = ? and " + "c6 = ? and " + "c7 = ? and " + "c8 = ? and " + "c9 = ? and " + + "c10 = ? and " + "c11 = ? and " + "c12 = ? and " + "c13 = ? and " + "c14 = ? and " + "c15 = ? "; pstmt = connection.prepareStatement(sql); @@ -361,8 +354,9 @@ private static void testBeforeExcute() throws SQLException { } private static void selectNumeric() throws SQLException { - String sql = "select * from " + numericTable + " where " + "c1 = ? and " + "c2 = ? and " + "c3 = ? and " + "c4 = ? and " + "c5 = ? and " - + "c6 = ? and " + "c7 = ? and " + "c8 = ? and " + "c9 = ? and " + "c10 = ? and " + "c11 = ? and " + "c12 = ? and " + "c13 = ? and " + "c14 = ? and " + "c15 = ? "; + String sql = "select * from " + numericTable + " where " + "c1 = ? and " + "c2 = ? and " + "c3 = ? and " + + "c4 = ? and " + "c5 = ? and " + "c6 = ? and " + "c7 = ? and " + "c8 = ? and " + "c9 = ? and " + + "c10 = ? and " + "c11 = ? and " + "c12 = ? and " + "c13 = ? and " + "c14 = ? and " + "c15 = ? "; pstmt = connection.prepareStatement(sql); @@ -375,7 +369,8 @@ private static void selectNumeric() throws SQLException { private static void insertNumeric() throws SQLException { - String sql = "insert into " + numericTable + " values( " + "?," + "?," + "?," + "?," + "?," + "?," + "?," + "?," + "?," + "?," + "?," + "?," + "?," + "?," + "?" + ")"; + String sql = "insert into " + numericTable + " values( " + "?," + "?," + "?," + "?," + "?," + "?," + "?," + "?," + + "?," + "?," + "?," + "?," + "?," + "?," + "?" + ")"; pstmt = connection.prepareStatement(sql); @@ -388,8 +383,9 @@ private static void insertNumeric() throws SQLException { private static void updateNumeric() throws SQLException { - String sql = "update " + numericTable + " set " + "c1 = ?," + "c2 = ?," + "c3 = ?," + "c4 = ?," + "c5 = ?," + "c6 = ?," + "c7 = ?," - + "c8 = ?," + "c9 = ?," + "c10 = ?," + "c11 = ?," + "c12 = ?," + "c13 = ?," + "c14 = ?," + "c15 = ?" + ";"; + String sql = "update " + numericTable + " set " + "c1 = ?," + "c2 = ?," + "c3 = ?," + "c4 = ?," + "c5 = ?," + + "c6 = ?," + "c7 = ?," + "c8 = ?," + "c9 = ?," + "c10 = ?," + "c11 = ?," + "c12 = ?," + "c13 = ?," + + "c14 = ?," + "c15 = ?" + ";"; pstmt = connection.prepareStatement(sql); @@ -402,8 +398,9 @@ private static void updateNumeric() throws SQLException { private static void deleteNumeric() throws SQLException { - String sql = "delete from " + numericTable + " where " + "c1 = ? and " + "c2 = ? and " + "c3 = ? and " + "c4 = ? and " + "c5 = ? and " - + "c6 = ? and " + "c7 = ? and " + "c8 = ? and " + "c9 = ? and " + "c10 = ? and " + "c11 = ? and " + "c12 = ? and " + "c13 = ? and " + "c14 = ? and " + "c15 = ?" + ";"; + String sql = "delete from " + numericTable + " where " + "c1 = ? and " + "c2 = ? and " + "c3 = ? and " + + "c4 = ? and " + "c5 = ? and " + "c6 = ? and " + "c7 = ? and " + "c8 = ? and " + "c9 = ? and " + + "c10 = ? and " + "c11 = ? and " + "c12 = ? and " + "c13 = ? and " + "c14 = ? and " + "c15 = ?" + ";"; pstmt = connection.prepareStatement(sql); @@ -416,21 +413,24 @@ private static void deleteNumeric() throws SQLException { private static void createNumericTable() throws SQLException { - stmt.execute("Create table " + numericTable + " (" + "c1 decimal not null," + "c2 decimal(10,5) not null," + "c3 numeric not null," - + "c4 numeric(8,4) not null," + "c5 float not null," + "c6 float(10) not null," + "c7 real not null," + "c8 int not null," - + "c9 bigint not null," + "c10 smallint not null," + "c11 tinyint not null," + "c12 money not null," + "c13 smallmoney not null," + stmt.execute("Create table " + numericTable + " (" + "c1 decimal not null," + "c2 decimal(10,5) not null," + + "c3 numeric not null," + "c4 numeric(8,4) not null," + "c5 float not null," + "c6 float(10) not null," + + "c7 real not null," + "c8 int not null," + "c9 bigint not null," + "c10 smallint not null," + + "c11 tinyint not null," + "c12 money not null," + "c13 smallmoney not null," + "c14 decimal(10,9) not null," + "c15 decimal(38,37) not null" + ")"); } private static void createCharTable() throws SQLException { - stmt.execute("Create table " + charTable + " (" + "c1 char(50) not null," + "c2 varchar(20) not null," + "c3 nchar(30) not null," - + "c4 nvarchar(60) not null," + "c5 text not null," + "c6 ntext not null" + ")"); + stmt.execute("Create table " + charTable + " (" + "c1 char(50) not null," + "c2 varchar(20) not null," + + "c3 nchar(30) not null," + "c4 nvarchar(60) not null," + "c5 text not null," + "c6 ntext not null" + + ")"); } private static void createSpaceTable() throws SQLException { - stmt.execute("Create table " + spaceTable + " (" + "[c1*/someString withspace] char(50) not null," + "c2 varchar(20) not null," - + "c3 nchar(30) not null," + "c4 nvarchar(60) not null," + "c5 text not null," + "c6 ntext not null" + ")"); + stmt.execute("Create table " + spaceTable + " (" + "[c1*/someString withspace] char(50) not null," + + "c2 varchar(20) not null," + "c3 nchar(30) not null," + "c4 nvarchar(60) not null," + + "c5 text not null," + "c6 ntext not null" + ")"); } private static void createChar2Table() throws SQLException { @@ -438,11 +438,13 @@ private static void createChar2Table() throws SQLException { } private static void populateCharTable() throws SQLException { - stmt.execute("insert into " + charTable + " values (" + "'Hello'," + "'Hello'," + "N'Hello'," + "N'Hello'," + "'Hello'," + "N'Hello'" + ")"); + stmt.execute("insert into " + charTable + " values (" + "'Hello'," + "'Hello'," + "N'Hello'," + "N'Hello'," + + "'Hello'," + "N'Hello'" + ")"); } private static void selectChar() throws SQLException { - String sql = "select * from " + charTable + " where " + "c1 = ? and " + "c2 = ? and " + "c3 = ? and " + "c4 = ? "; + String sql = "select * from " + charTable + " where " + "c1 = ? and " + "c2 = ? and " + "c3 = ? and " + + "c4 = ? "; pstmt = connection.prepareStatement(sql); @@ -468,7 +470,8 @@ private static void insertChar() throws SQLException { private static void updateChar() throws SQLException { - String sql = "update " + charTable + " set " + "c1 = ?," + "c2 = ?," + "c3 = ?," + "c4 = ?," + "c5 = ?," + "c6 = ?" + ";"; + String sql = "update " + charTable + " set " + "c1 = ?," + "c2 = ?," + "c3 = ?," + "c4 = ?," + "c5 = ?," + + "c6 = ?" + ";"; pstmt = connection.prepareStatement(sql); @@ -494,13 +497,14 @@ private static void deleteChar() throws SQLException { private static void createBinaryTable() throws SQLException { - stmt.execute("Create table " + binaryTable + " (" + "c1 binary(100) not null," + "c2 varbinary(200) not null" + ")"); + stmt.execute( + "Create table " + binaryTable + " (" + "c1 binary(100) not null," + "c2 varbinary(200) not null" + ")"); } private static void populateBinaryTable() throws SQLException { - stmt.execute("insert into " + binaryTable + " values (" + "convert(binary(50), 'Simba tech', 0), " + "convert(varbinary(50), 'Simba tech', 0)" - + ")"); + stmt.execute("insert into " + binaryTable + " values (" + "convert(binary(50), 'Simba tech', 0), " + + "convert(varbinary(50), 'Simba tech', 0)" + ")"); } private static void selectBinary() throws SQLException { @@ -558,20 +562,22 @@ private static void deleteBinary() throws SQLException { private static void createDateAndTimeTable() throws SQLException { - stmt.execute("Create table " + dateAndTimeTable + " (" + "c1 date not null," + "c2 datetime not null," + "c3 datetime2 not null," - + "c4 datetime2(5) not null," + "c5 datetimeoffset not null," + "c6 datetimeoffset(5) not null," + "c7 smalldatetime not null," - + "c8 time not null," + "c9 time(5) not null" + ")"); + stmt.execute("Create table " + dateAndTimeTable + " (" + "c1 date not null," + "c2 datetime not null," + + "c3 datetime2 not null," + "c4 datetime2(5) not null," + "c5 datetimeoffset not null," + + "c6 datetimeoffset(5) not null," + "c7 smalldatetime not null," + "c8 time not null," + + "c9 time(5) not null" + ")"); } private static void populateDateAndTimeTable() throws SQLException { - stmt.execute("insert into " + dateAndTimeTable + " values (" + "'1991-10-23'," + "'1991-10-23 06:20:50'," + "'1991-10-23 07:20:50.123'," - + "'1991-10-23 07:20:50.123'," + "'1991-10-23 08:20:50.123'," + "'1991-10-23 08:20:50.123'," + "'1991-10-23 09:20:50'," - + "'10:20:50'," + "'10:20:50'" + ")"); + stmt.execute("insert into " + dateAndTimeTable + " values (" + "'1991-10-23'," + "'1991-10-23 06:20:50'," + + "'1991-10-23 07:20:50.123'," + "'1991-10-23 07:20:50.123'," + "'1991-10-23 08:20:50.123'," + + "'1991-10-23 08:20:50.123'," + "'1991-10-23 09:20:50'," + "'10:20:50'," + "'10:20:50'" + ")"); } private static void insertDateAndTime() throws SQLException { - String sql = "insert into " + dateAndTimeTable + " values( " + "?," + "?," + "?," + "?," + "?," + "?," + "?," + "?," + "?" + ")"; + String sql = "insert into " + dateAndTimeTable + " values( " + "?," + "?," + "?," + "?," + "?," + "?," + "?," + + "?," + "?" + ")"; pstmt = connection.prepareStatement(sql); @@ -584,8 +590,8 @@ private static void insertDateAndTime() throws SQLException { private static void updateDateAndTime() throws SQLException { - String sql = "update " + dateAndTimeTable + " set " + "c1 = ?," + "c2 = ?," + "c3 = ?," + "c4 = ?," + "c5 = ?," + "c6 = ?," + "c7 = ?," - + "c8 = ?," + "c9 = ?" + ";"; + String sql = "update " + dateAndTimeTable + " set " + "c1 = ?," + "c2 = ?," + "c3 = ?," + "c4 = ?," + "c5 = ?," + + "c6 = ?," + "c7 = ?," + "c8 = ?," + "c9 = ?" + ";"; pstmt = connection.prepareStatement(sql); @@ -598,8 +604,8 @@ private static void updateDateAndTime() throws SQLException { private static void deleteDateAndTime() throws SQLException { - String sql = "delete from " + dateAndTimeTable + " where " + "c1 = ? and " + "c2 = ? and " + "c3 = ? and " + "c4 = ? and " + "c5 = ? and " - + "c6 = ? and " + "c7 = ? and " + "c8 = ? and " + "c9 = ?" + ";"; + String sql = "delete from " + dateAndTimeTable + " where " + "c1 = ? and " + "c2 = ? and " + "c3 = ? and " + + "c4 = ? and " + "c5 = ? and " + "c6 = ? and " + "c7 = ? and " + "c8 = ? and " + "c9 = ?" + ";"; pstmt = connection.prepareStatement(sql); @@ -611,8 +617,8 @@ private static void deleteDateAndTime() throws SQLException { } private static void selectDateAndTime() throws SQLException { - String sql = "select * from " + dateAndTimeTable + " where " + "c1 = ? and " + "c2 = ? and " + "c3 = ? and " + "c4 = ? and " + "c5 = ? and " - + "c6 = ? and " + "c7 = ? and " + "c8 = ? and " + "c9 = ? "; + String sql = "select * from " + dateAndTimeTable + " where " + "c1 = ? and " + "c2 = ? and " + "c3 = ? and " + + "c4 = ? and " + "c5 = ? and " + "c6 = ? and " + "c7 = ? and " + "c8 = ? and " + "c9 = ? "; pstmt = connection.prepareStatement(sql); @@ -626,38 +632,40 @@ private static void selectDateAndTime() throws SQLException { private static void createTablesForCompexQueries() throws SQLException { stmt.executeUpdate("if object_id('" + nameTable + "','U') is not null" + " drop table " + nameTable); - stmt.executeUpdate("if object_id('" + phoneNumberTable + "','U') is not null" + " drop table " + phoneNumberTable); + stmt.executeUpdate( + "if object_id('" + phoneNumberTable + "','U') is not null" + " drop table " + phoneNumberTable); - stmt.executeUpdate("if object_id('" + mergeNameDesTable + "','U') is not null" + " drop table " + mergeNameDesTable); + stmt.executeUpdate( + "if object_id('" + mergeNameDesTable + "','U') is not null" + " drop table " + mergeNameDesTable); String sql = "create table " + nameTable + " (" // + "ID int NOT NULL," - + "PlainID int not null," + "ID smallint NOT NULL," + "FirstName varchar(50) NOT NULL," + "LastName nchar(60) NOT NULL" + ");"; + + "PlainID int not null," + "ID smallint NOT NULL," + "FirstName varchar(50) NOT NULL," + + "LastName nchar(60) NOT NULL" + ");"; try { stmt.execute(sql); - } - catch (SQLException e) { + } catch (SQLException e) { fail(e.toString()); } - sql = "create table " + phoneNumberTable + " (" + "PlainID smallint not null," + "ID int NOT NULL," + "PhoneNumber bigint NOT NULL" + ");"; + sql = "create table " + phoneNumberTable + " (" + "PlainID smallint not null," + "ID int NOT NULL," + + "PhoneNumber bigint NOT NULL" + ");"; try { stmt.execute(sql); - } - catch (SQLException e) { + } catch (SQLException e) { fail(e.toString()); } sql = "create table " + mergeNameDesTable + " (" // + "ID int NOT NULL," - + "PlainID smallint not null," + "ID int NULL," + "FirstName char(30) NULL," + "LastName varchar(50) NULL" + ");"; + + "PlainID smallint not null," + "ID int NULL," + "FirstName char(30) NULL," + + "LastName varchar(50) NULL" + ");"; try { stmt.execute(sql); - } - catch (SQLException e) { + } catch (SQLException e) { fail(e.toString()); } } @@ -736,8 +744,8 @@ private static void populateTablesForCompexQueries() throws SQLException { @DisplayName("SubQuery") public void testSubquery() throws SQLException { if (version >= SQL_SERVER_2012_VERSION) { - String sql = "SELECT FirstName,LastName" + " FROM " + nameTable + " WHERE ID IN " + " (SELECT ID" + " FROM " + phoneNumberTable - + " WHERE PhoneNumber = ? and ID = ? and PlainID = ?" + ")"; + String sql = "SELECT FirstName,LastName" + " FROM " + nameTable + " WHERE ID IN " + " (SELECT ID" + " FROM " + + phoneNumberTable + " WHERE PhoneNumber = ? and ID = ? and PlainID = ?" + ")"; pstmt = connection.prepareStatement(sql); @@ -746,8 +754,7 @@ public void testSubquery() throws SQLException { try { pmd = pstmt.getParameterMetaData(); assertEquals(pmd.getParameterCount(), 3, TestResource.getResource("R_paramNotRecognized")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } @@ -769,8 +776,8 @@ public void testJoin() throws SQLException { String sql = String.format( "select %s.FirstName, %s.LastName, %s.PhoneNumber" + " from %s join %s on %s.PlainID = %s.PlainID" + " where %s.ID = ? and %s.PlainID = ?", - nameTable, nameTable, phoneNumberTable, nameTable, phoneNumberTable, nameTable, phoneNumberTable, phoneNumberTable, - phoneNumberTable); + nameTable, nameTable, phoneNumberTable, nameTable, phoneNumberTable, nameTable, phoneNumberTable, + phoneNumberTable, phoneNumberTable); pstmt = connection.prepareStatement(sql); @@ -779,8 +786,7 @@ public void testJoin() throws SQLException { try { pmd = pstmt.getParameterMetaData(); assertEquals(pmd.getParameterCount(), 2, TestResource.getResource("R_paramNotRecognized")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } @@ -798,8 +804,8 @@ public void testJoin() throws SQLException { @DisplayName("Merge Queries") public void testMerge() throws SQLException { if (version >= SQL_SERVER_2012_VERSION) { - String sql = "merge " + mergeNameDesTable + " as T" + " using " + nameTable + " as S" + " on T.PlainID=S.PlainID" + " when matched" - + " then update set T.firstName = ?, T.lastName = ?;"; + String sql = "merge " + mergeNameDesTable + " as T" + " using " + nameTable + " as S" + + " on T.PlainID=S.PlainID" + " when matched" + " then update set T.firstName = ?, T.lastName = ?;"; pstmt = connection.prepareStatement(sql); @@ -812,8 +818,7 @@ public void testMerge() throws SQLException { try { pmd = pstmt.getParameterMetaData(); assertEquals(pmd.getParameterCount(), 2, TestResource.getResource("R_paramNotRecognized")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } @@ -824,24 +829,26 @@ public void testMerge() throws SQLException { private static void createMultipleTypesTable() throws SQLException { - stmt.execute("Create table " + multipleTypesTable + " (" + "c1n decimal not null," + "c2n decimal(10,5) not null," + "c3n numeric not null," - + "c4n numeric(8,4) not null," + "c5n float not null," + "c6n float(10) not null," + "c7n real not null," + "c8n int not null," - + "c9n bigint not null," + "c10n smallint not null," + "c11n tinyint not null," + "c12n money not null," + "c13n smallmoney not null," + stmt.execute("Create table " + multipleTypesTable + " (" + "c1n decimal not null," + + "c2n decimal(10,5) not null," + "c3n numeric not null," + "c4n numeric(8,4) not null," + + "c5n float not null," + "c6n float(10) not null," + "c7n real not null," + "c8n int not null," + + "c9n bigint not null," + "c10n smallint not null," + "c11n tinyint not null," + "c12n money not null," + + "c13n smallmoney not null," - + "c1c char(50) not null," + "c2c varchar(20) not null," + "c3c nchar(30) not null," + "c4c nvarchar(60) not null," - + "c5c text not null," + "c6c ntext not null," + + "c1c char(50) not null," + "c2c varchar(20) not null," + "c3c nchar(30) not null," + + "c4c nvarchar(60) not null," + "c5c text not null," + "c6c ntext not null," + "c1 binary(100) not null," + "c2 varbinary(200) not null," - + "c1d date not null," + "c2d datetime not null," + "c3d datetime2 not null," + "c4d datetime2(5) not null," - + "c5d datetimeoffset not null," + "c6d datetimeoffset(5) not null," + "c7d smalldatetime not null," + "c8d time not null," - + "c9d time(5) not null" + ")"); + + "c1d date not null," + "c2d datetime not null," + "c3d datetime2 not null," + + "c4d datetime2(5) not null," + "c5d datetimeoffset not null," + "c6d datetimeoffset(5) not null," + + "c7d smalldatetime not null," + "c8d time not null," + "c9d time(5) not null" + ")"); } private static void testInsertMultipleTypes() throws SQLException { - String sql = "insert into " + multipleTypesTable + " values( " + "?,?,?,?,?,?,?,?,?,?,?,?,?," + "?,?,?,?,?,?," + "?,?," + "?,?,?,?,?,?,?,?,?" - + ")"; + String sql = "insert into " + multipleTypesTable + " values( " + "?,?,?,?,?,?,?,?,?,?,?,?,?," + "?,?,?,?,?,?," + + "?,?," + "?,?,?,?,?,?,?,?,?" + ")"; pstmt = connection.prepareStatement(sql); @@ -865,8 +872,7 @@ private static void testInsertMultipleTypes() throws SQLException { try { pmd = pstmt.getParameterMetaData(); assertEquals(pmd.getParameterCount(), 30, TestResource.getResource("R_paramNotRecognized")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } @@ -879,8 +885,7 @@ private static void testInsertMultipleTypes() throws SQLException { compareParameterMetaData(pmd, 7, "java.lang.Float", 7, "real", 7, 0); if (version >= SQL_SERVER_2012_VERSION) { compareParameterMetaData(pmd, 8, "java.lang.Integer", 4, "int", 10, 0); - } - else { + } else { compareParameterMetaData(pmd, 8, "java.lang.Integer", 4, "int", 10, 0); } compareParameterMetaData(pmd, 9, "java.lang.Long", -5, "bigint", 19, 0); @@ -923,16 +928,15 @@ public void testNoParameter() throws SQLException { try { pmd = pstmt.getParameterMetaData(); assertEquals(pmd.getParameterCount(), 0, TestResource.getResource("R_paramNotRecognized")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } private static void testMixedWithHardcodedValues() throws SQLException { - String sql = "insert into " + multipleTypesTable + " values( " + "1,?,?,1,?,?,?,1,?,?,?,1,1," + "?,'simba tech','simba tech',?,?,?," + "?,?," - + "?,'1991-10-23',?,?,?,'1991-10-23',?,?,?" + ")"; + String sql = "insert into " + multipleTypesTable + " values( " + "1,?,?,1,?,?,?,1,?,?,?,1,1," + + "?,'simba tech','simba tech',?,?,?," + "?,?," + "?,'1991-10-23',?,?,?,'1991-10-23',?,?,?" + ")"; pstmt = connection.prepareStatement(sql); @@ -957,8 +961,7 @@ private static void testMixedWithHardcodedValues() throws SQLException { pmd = pstmt.getParameterMetaData(); assertEquals(pmd.getParameterCount(), 21, TestResource.getResource("R_paramNotRecognized")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } @@ -996,8 +999,8 @@ private static void testMixedWithHardcodedValues() throws SQLException { @Test @DisplayName("Test OrderBy") public void testOrderBy() throws SQLException { - String sql = "SELECT FirstName,LastName" + " FROM " + nameTable + " WHERE FirstName = ? and LastName = ? and PlainID = ? and ID = ? " - + " ORDER BY ID ASC"; + String sql = "SELECT FirstName,LastName" + " FROM " + nameTable + + " WHERE FirstName = ? and LastName = ? and PlainID = ? and ID = ? " + " ORDER BY ID ASC"; pstmt = connection.prepareStatement(sql); @@ -1006,8 +1009,7 @@ public void testOrderBy() throws SQLException { try { pmd = pstmt.getParameterMetaData(); assertEquals(pmd.getParameterCount(), 4, TestResource.getResource("R_paramNotRecognized")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } @@ -1026,8 +1028,8 @@ public void testOrderBy() throws SQLException { @Test @DisplayName("Test GroupBy") private void testGroupBy() throws SQLException { - String sql = "SELECT FirstName,COUNT(LastName)" + " FROM " + nameTable + " WHERE FirstName = ? and LastName = ? and PlainID = ? and ID = ? " - + " group by Firstname"; + String sql = "SELECT FirstName,COUNT(LastName)" + " FROM " + nameTable + + " WHERE FirstName = ? and LastName = ? and PlainID = ? and ID = ? " + " group by Firstname"; pstmt = connection.prepareStatement(sql); @@ -1036,8 +1038,7 @@ private void testGroupBy() throws SQLException { try { pmd = pstmt.getParameterMetaData(); assertEquals(pmd.getParameterCount(), 4, TestResource.getResource("R_paramNotRecognized")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } @@ -1055,7 +1056,8 @@ private void testGroupBy() throws SQLException { */ @Test public void testLower() throws SQLException { - String sql = "SELECT FirstName,LOWER(LastName)" + " FROM " + nameTable + " WHERE FirstName = ? and LastName = ? and PlainID = ? and ID = ? "; + String sql = "SELECT FirstName,LOWER(LastName)" + " FROM " + nameTable + + " WHERE FirstName = ? and LastName = ? and PlainID = ? and ID = ? "; pstmt = connection.prepareStatement(sql); @@ -1065,8 +1067,7 @@ public void testLower() throws SQLException { pmd = pstmt.getParameterMetaData(); assertEquals(pmd.getParameterCount(), 4, TestResource.getResource("R_paramNotRecognized")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } @@ -1084,7 +1085,8 @@ public void testLower() throws SQLException { */ @Test public void testPower() throws SQLException { - String sql = "SELECT POWER(ID,2)" + " FROM " + nameTable + " WHERE FirstName = ? and LastName = ? and PlainID = ? and ID = ? "; + String sql = "SELECT POWER(ID,2)" + " FROM " + nameTable + + " WHERE FirstName = ? and LastName = ? and PlainID = ? and ID = ? "; pstmt = connection.prepareStatement(sql); @@ -1093,8 +1095,7 @@ public void testPower() throws SQLException { try { pmd = pstmt.getParameterMetaData(); assertEquals(pmd.getParameterCount(), 4, TestResource.getResource("R_paramNotRecognized")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } @@ -1115,10 +1116,10 @@ public void testPower() throws SQLException { public void testAllInOneQuery() throws SQLException { if (version >= SQL_SERVER_2012_VERSION) { - String sql = "select lower(FirstName), count(lastName) from " + nameTable + "where ID = ? and FirstName in" + "(" + " select " + nameTable - + ".FirstName from " + nameTable + " join " + phoneNumberTable + " on " + nameTable + ".ID = " + phoneNumberTable + ".ID" - + " where " + nameTable + ".ID = ? and " + phoneNumberTable + ".ID = ?" + ")" + " group by FirstName " - + " order by FirstName ASC"; + String sql = "select lower(FirstName), count(lastName) from " + nameTable + "where ID = ? and FirstName in" + + "(" + " select " + nameTable + ".FirstName from " + nameTable + " join " + phoneNumberTable + + " on " + nameTable + ".ID = " + phoneNumberTable + ".ID" + " where " + nameTable + ".ID = ? and " + + phoneNumberTable + ".ID = ?" + ")" + " group by FirstName " + " order by FirstName ASC"; pstmt = connection.prepareStatement(sql); @@ -1128,8 +1129,7 @@ public void testAllInOneQuery() throws SQLException { pmd = pstmt.getParameterMetaData(); assertEquals(pmd.getParameterCount(), 3, TestResource.getResource("R_paramNotRecognized")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } @@ -1152,8 +1152,7 @@ public void testQueryWithMultipleLineComments1() throws SQLException { try { pstmt.getParameterMetaData(); pstmt.executeQuery(); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } @@ -1166,14 +1165,14 @@ public void testQueryWithMultipleLineComments1() throws SQLException { @Test public void testQueryWithMultipleLineComments2() throws SQLException { pstmt = connection - .prepareStatement("/*/*te\nst*/ te/*test*/st /*te\nst*/*//*te/*test*/st*/select top 100 c1 from " + charTable + " where c1 = ?"); + .prepareStatement("/*/*te\nst*/ te/*test*/st /*te\nst*/*//*te/*test*/st*/select top 100 c1 from " + + charTable + " where c1 = ?"); pstmt.setString(1, "abc"); try { pstmt.getParameterMetaData(); pstmt.executeQuery(); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } @@ -1189,8 +1188,7 @@ public void testQueryWithMultipleLineCommentsInsert() throws SQLException { try { pstmt.getParameterMetaData(); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } @@ -1206,8 +1204,7 @@ public void testQueryWithMultipleLineCommentsUpdate() throws SQLException { try { pstmt.getParameterMetaData(); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } @@ -1223,8 +1220,7 @@ public void testQueryWithMultipleLineCommentsDeletion() throws SQLException { try { pstmt.getParameterMetaData(); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } @@ -1242,8 +1238,7 @@ public void testQueryWithSingleLineComments1() throws SQLException { try { pstmt.getParameterMetaData(); pstmt.executeQuery(); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } @@ -1261,8 +1256,7 @@ public void testQueryWithSingleLineComments2() throws SQLException { try { pstmt.getParameterMetaData(); pstmt.executeQuery(); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } @@ -1280,8 +1274,7 @@ public void testQueryWithSingleLineComments3() throws SQLException { try { pstmt.getParameterMetaData(); pstmt.executeQuery(); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } @@ -1297,8 +1290,7 @@ public void testQueryWithSingleLineCommentsInsert() throws SQLException { try { pstmt.getParameterMetaData(); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } @@ -1314,8 +1306,7 @@ public void testQueryWithSingleLineCommentsUpdate() throws SQLException { try { pstmt.getParameterMetaData(); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } @@ -1331,8 +1322,7 @@ public void testQueryWithSingleLineCommentsDeletion() throws SQLException { try { pstmt.getParameterMetaData(); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } @@ -1348,8 +1338,7 @@ public void testQueryWithSpaceAndEndCommentMarkInColumnName() throws SQLExceptio try { pstmt.getParameterMetaData(); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } @@ -1361,16 +1350,15 @@ public void testQueryWithSpaceAndEndCommentMarkInColumnName() throws SQLExceptio */ @Test public void testComplexQueryWithMultipleTables() throws SQLException { - pstmt = connection.prepareStatement( - "insert into " + charTable + " (c1) select ? where not exists (select * from " + charTable2 + " where table2c1 = ?)"); + pstmt = connection.prepareStatement("insert into " + charTable + + " (c1) select ? where not exists (select * from " + charTable2 + " where table2c1 = ?)"); try { SQLServerParameterMetaData pMD = (SQLServerParameterMetaData) pstmt.getParameterMetaData(); int parameterCount = pMD.getParameterCount(); assertTrue(2 == parameterCount, "Parameter Count should be 2."); - } - catch (Exception e) { + } catch (Exception e) { fail(e.toString()); } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/PoolableTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/PoolableTest.java index 72fd663d5..7b8d1f6b1 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/PoolableTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/PoolableTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.unit.statement; @@ -30,6 +27,7 @@ import com.microsoft.sqlserver.testframework.AbstractTest; import com.microsoft.sqlserver.testframework.Utils; + /** * Test Poolable statements * @@ -46,34 +44,40 @@ public class PoolableTest extends AbstractTest { @Test @DisplayName("Poolable Test") public void poolableTest() throws SQLException, ClassNotFoundException { - try (Connection conn = DriverManager.getConnection(connectionString); Statement statement = conn.createStatement()) { + try (Connection conn = DriverManager.getConnection(connectionString); + Statement statement = conn.createStatement()) { try { // First get the default values boolean isPoolable = ((SQLServerStatement) statement).isPoolable(); - assertEquals(isPoolable, false, "SQLServerStatement: " + TestResource.getResource("R_incorrectDefault")); + assertEquals(isPoolable, false, + "SQLServerStatement: " + TestResource.getResource("R_incorrectDefault")); try (PreparedStatement prepStmt = connection.prepareStatement("select 1")) { isPoolable = ((SQLServerPreparedStatement) prepStmt).isPoolable(); - assertEquals(isPoolable, true, "SQLServerPreparedStatement: " + TestResource.getResource("R_incorrectDefault")); + assertEquals(isPoolable, true, + "SQLServerPreparedStatement: " + TestResource.getResource("R_incorrectDefault")); } - try (CallableStatement callableStatement = connection.prepareCall("{ ? = CALL " + "ProcName" + " (?, ?, ?, ?) }");) { + try (CallableStatement callableStatement = connection + .prepareCall("{ ? = CALL " + "ProcName" + " (?, ?, ?, ?) }");) { isPoolable = ((SQLServerCallableStatement) callableStatement).isPoolable(); - assertEquals(isPoolable, true, "SQLServerCallableStatement: " + TestResource.getResource("R_incorrectDefault")); + assertEquals(isPoolable, true, + "SQLServerCallableStatement: " + TestResource.getResource("R_incorrectDefault")); // Now do couple of sets and gets ((SQLServerCallableStatement) callableStatement).setPoolable(false); - assertEquals(((SQLServerCallableStatement) callableStatement).isPoolable(), false, "set did not work"); + assertEquals(((SQLServerCallableStatement) callableStatement).isPoolable(), false, + "set did not work"); } ((SQLServerStatement) statement).setPoolable(true); assertEquals(((SQLServerStatement) statement).isPoolable(), true, "set did not work"); - } - catch (UnsupportedOperationException e) { + } catch (UnsupportedOperationException e) { // PoolableTest should be supported in anything other than 1.5 - assertEquals(System.getProperty("java.specification.version"), "1.5", "PoolableTest " + TestResource.getResource("R_shouldBeSupported")); + assertEquals(System.getProperty("java.specification.version"), "1.5", + "PoolableTest " + TestResource.getResource("R_shouldBeSupported")); assertEquals(e.getMessage(), TestResource.getResource("R_operationNotSupported")); assertEquals(e.getMessage(), TestResource.getResource("R_unexpectedExceptionContent")); } @@ -90,8 +94,7 @@ public static void afterAll() throws Exception { try (Connection conn = DriverManager.getConnection(connectionString); Statement stmt = conn.createStatement()) { try { Utils.dropProcedureIfExists("ProcName", stmt); - } - catch (Exception ex) { + } catch (Exception ex) { fail(ex.toString()); } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/PreparedStatementTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/PreparedStatementTest.java index 78b2777b0..7f0c8ad47 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/PreparedStatementTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/PreparedStatementTest.java @@ -1,17 +1,14 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.unit.statement; import static java.util.concurrent.TimeUnit.SECONDS; -import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertNotSame; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import java.lang.reflect.Field; @@ -37,8 +34,9 @@ import com.microsoft.sqlserver.jdbc.TestResource; import com.microsoft.sqlserver.testframework.AbstractTest; + @RunWith(JUnitPlatform.class) -public class PreparedStatementTest extends AbstractTest { +public class PreparedStatementTest extends AbstractTest { private void executeSQL(SQLServerConnection conn, String sql) throws SQLException { Statement stmt = conn.createStatement(); stmt.execute(sql); @@ -47,10 +45,10 @@ private void executeSQL(SQLServerConnection conn, String sql) throws SQLExceptio private int executeSQLReturnFirstInt(SQLServerConnection conn, String sql) throws SQLException { Statement stmt = conn.createStatement(); ResultSet result = stmt.executeQuery(sql); - + int returnValue = -1; - if(result.next()) + if (result.next()) returnValue = result.getInt(1); return returnValue; @@ -65,39 +63,46 @@ private int executeSQLReturnFirstInt(SQLServerConnection conn, String sql) throw public void testBatchedUnprepare() throws SQLException { SQLServerConnection conOuter = null; - try (SQLServerConnection con = (SQLServerConnection)DriverManager.getConnection(connectionString)) { + try (SQLServerConnection con = (SQLServerConnection) DriverManager.getConnection(connectionString)) { conOuter = con; // Turn off use of prepared statement cache. con.setStatementPoolingCacheSize(0); // Clean-up proc cache - this.executeSQL(con, "DBCC FREEPROCCACHE;"); - + this.executeSQL(con, "DBCC FREEPROCCACHE;"); + String lookupUniqueifier = UUID.randomUUID().toString(); - String queryCacheLookup = String.format("%%/*unpreparetest_%s%%*/SELECT * FROM sys.tables;", lookupUniqueifier); - String query = String.format("/*unpreparetest_%s only sp_executesql*/SELECT * FROM sys.tables;", lookupUniqueifier); + String queryCacheLookup = String.format("%%/*unpreparetest_%s%%*/SELECT * FROM sys.tables;", + lookupUniqueifier); + String query = String.format("/*unpreparetest_%s only sp_executesql*/SELECT * FROM sys.tables;", + lookupUniqueifier); // Verify nothing in cache. - String verifyTotalCacheUsesQuery = String.format("SELECT CAST(ISNULL(SUM(usecounts), 0) AS INT) FROM sys.dm_exec_cached_plans AS p CROSS APPLY sys.dm_exec_sql_text(p.plan_handle) AS s WHERE s.text LIKE '%s'", queryCacheLookup); + String verifyTotalCacheUsesQuery = String.format( + "SELECT CAST(ISNULL(SUM(usecounts), 0) AS INT) FROM sys.dm_exec_cached_plans AS p CROSS APPLY sys.dm_exec_sql_text(p.plan_handle) AS s WHERE s.text LIKE '%s'", + queryCacheLookup); assertSame(0, executeSQLReturnFirstInt(con, verifyTotalCacheUsesQuery)); int iterations = 25; - query = String.format("/*unpreparetest_%s, sp_executesql->sp_prepexec->sp_execute- batched sp_unprepare*/SELECT * FROM sys.tables;", lookupUniqueifier); + query = String.format( + "/*unpreparetest_%s, sp_executesql->sp_prepexec->sp_execute- batched sp_unprepare*/SELECT * FROM sys.tables;", + lookupUniqueifier); int prevDiscardActionCount = 0; - - // Now verify unprepares are needed. - for(int i = 0; i < iterations; ++i) { + + // Now verify unprepares are needed. + for (int i = 0; i < iterations; ++i) { // Verify current queue depth is expected. assertSame(prevDiscardActionCount, con.getDiscardedServerPreparedStatementCount()); - - try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement)con.prepareStatement(String.format("%s--%s", query, i))) { + + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con + .prepareStatement(String.format("%s--%s", query, i))) { pstmt.execute(); // sp_executesql - + pstmt.execute(); // sp_prepexec ++prevDiscardActionCount; @@ -105,26 +110,24 @@ public void testBatchedUnprepare() throws SQLException { } // Verify clean-up is happening as expected. - if(prevDiscardActionCount > con.getServerPreparedStatementDiscardThreshold()) { + if (prevDiscardActionCount > con.getServerPreparedStatementDiscardThreshold()) { prevDiscardActionCount = 0; } assertSame(prevDiscardActionCount, con.getDiscardedServerPreparedStatementCount()); - } + } // Skipped for now due to unexpected failures. Not functional so not critical. /* - // Verify total cache use. - int expectedCacheHits = iterations * 4; - int allowedDiscrepency = 20; - // Allow some discrepency in number of cache hits to not fail test ( - // TODO: Follow up on why there is sometimes a discrepency in number of cache hits (less than expected). - assertTrue(expectedCacheHits >= executeSQLReturnFirstInt(con, verifyTotalCacheUsesQuery)); - assertTrue(expectedCacheHits - allowedDiscrepency < executeSQLReturnFirstInt(con, verifyTotalCacheUsesQuery)); - */ - } + * // Verify total cache use. int expectedCacheHits = iterations * 4; int allowedDiscrepency = 20; // Allow + * some discrepency in number of cache hits to not fail test ( // TODO: Follow up on why there is sometimes + * a discrepency in number of cache hits (less than expected). assertTrue(expectedCacheHits >= + * executeSQLReturnFirstInt(con, verifyTotalCacheUsesQuery)); assertTrue(expectedCacheHits - + * allowedDiscrepency < executeSQLReturnFirstInt(con, verifyTotalCacheUsesQuery)); + */ + } // Verify clean-up happened on connection close. - assertSame(0, conOuter.getDiscardedServerPreparedStatementCount()); + assertSame(0, conOuter.getDiscardedServerPreparedStatementCount()); } /** @@ -142,17 +145,17 @@ public void testStatementPooling() throws Exception { * Test handling of statement pooling for prepared statements. * * @throws SQLException - * @throws SecurityException - * @throws NoSuchFieldException - * @throws IllegalAccessException - * @throws IllegalArgumentException + * @throws SecurityException + * @throws NoSuchFieldException + * @throws IllegalAccessException + * @throws IllegalArgumentException */ @Test @Tag("slow") public void testStatementPoolingUseBulkCopyAPI() throws Exception { testStatementPoolingInternal("BulkCopy"); } - + /** * Test handling of eviction from statement pooling for prepared statements. * @@ -162,24 +165,26 @@ public void testStatementPoolingUseBulkCopyAPI() throws Exception { public void testStatementPoolingEviction() throws SQLException { for (int testNo = 0; testNo < 2; ++testNo) { - try (SQLServerConnection con = (SQLServerConnection)DriverManager.getConnection(connectionString)) { - int cacheSize = 10; - int discardedStatementCount = testNo == 0 ? 5 /*batched unprepares*/ : 0 /*regular unprepares*/; + try (SQLServerConnection con = (SQLServerConnection) DriverManager.getConnection(connectionString)) { + int cacheSize = 10; + int discardedStatementCount = testNo == 0 ? 5 /* batched unprepares */ : 0 /* regular unprepares */; // enabling caching con.setDisableStatementPooling(false); - con.setStatementPoolingCacheSize(cacheSize); + con.setStatementPoolingCacheSize(cacheSize); con.setServerPreparedStatementDiscardThreshold(discardedStatementCount); String lookupUniqueifier = UUID.randomUUID().toString(); - String query = String.format("/*statementpoolingevictiontest_%s*/SELECT * FROM sys.tables; -- ", lookupUniqueifier); + String query = String.format("/*statementpoolingevictiontest_%s*/SELECT * FROM sys.tables; -- ", + lookupUniqueifier); // Add new statements to fill up the statement pool. for (int i = 0; i < cacheSize; ++i) { - try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement)con.prepareStatement(query + String.valueOf(i))) { + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con + .prepareStatement(query + String.valueOf(i))) { pstmt.execute(); // sp_executesql pstmt.execute(); // sp_prepexec, actual handle created and cached. - } + } // Make sure no handles in discard queue (still only in statement pool). assertSame(0, con.getDiscardedServerPreparedStatementCount()); } @@ -187,16 +192,17 @@ public void testStatementPoolingEviction() throws SQLException { // No discarded handles yet, all in statement pool. assertSame(0, con.getDiscardedServerPreparedStatementCount()); - // Add new statements to fill up the statement discard action queue - // (new statement pushes existing statement from pool into discard + // Add new statements to fill up the statement discard action queue + // (new statement pushes existing statement from pool into discard // action queue). for (int i = cacheSize; i < cacheSize + 5; ++i) { - try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement)con.prepareStatement(query + String.valueOf(i))) { + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con + .prepareStatement(query + String.valueOf(i))) { pstmt.execute(); // sp_executesql pstmt.execute(); // sp_prepexec, actual handle created and cached. - } + } // If we use discard queue handles should start going into discard queue. - if(0 == testNo) + if (0 == testNo) assertNotSame(0, con.getDiscardedServerPreparedStatementCount()); else assertSame(0, con.getDiscardedServerPreparedStatementCount()); @@ -208,23 +214,23 @@ public void testStatementPoolingEviction() throws SQLException { else assertSame(0, con.getDiscardedServerPreparedStatementCount()); - // Adding one more statement should cause one more pooled statement to be invalidated and + // Adding one more statement should cause one more pooled statement to be invalidated and // discarding actions should be executed (i.e. sp_unprepare batch), clearing out the discard // action queue. - try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement)con.prepareStatement(query)) { + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con.prepareStatement(query)) { pstmt.execute(); // sp_executesql pstmt.execute(); // sp_prepexec, actual handle created and cached. - } + } // Discard queue should now be empty. assertSame(0, con.getDiscardedServerPreparedStatementCount()); // Set statement pool size to 0 and verify statements get discarded. - int statementsInCache = con.getStatementHandleCacheEntryCount(); + int statementsInCache = con.getStatementHandleCacheEntryCount(); con.setStatementPoolingCacheSize(0); assertSame(0, con.getStatementHandleCacheEntryCount()); - if(0 == testNo) + if (0 == testNo) // Verify statements moved over to discard action queue. assertSame(statementsInCache, con.getDiscardedServerPreparedStatementCount()); @@ -234,13 +240,13 @@ public void testStatementPoolingEviction() throws SQLException { assertSame(0, con.getDiscardedServerPreparedStatementCount()); // Verify new statement does not go into cache (since cache is now off) - try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement)con.prepareStatement(query)) { + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con.prepareStatement(query)) { pstmt.execute(); // sp_executesql pstmt.execute(); // sp_prepexec, actual handle created and cached. assertSame(0, con.getStatementHandleCacheEntryCount()); - } - } + } + } } } @@ -257,13 +263,12 @@ final class TestPrepareRace implements Runnable { } @Override - public void run() - { + public void run() { for (int j = 0; j < 500000; j++) { - try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con.prepareStatement(queries[j % 3])) { + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con + .prepareStatement(queries[j % 3])) { pstmt.execute(); - } - catch (SQLException e) { + } catch (SQLException e) { exception.set(e); break; } @@ -281,7 +286,7 @@ public void testPrepareRace() throws Exception { ExecutorService threadPool = Executors.newFixedThreadPool(4); AtomicReference exception = new AtomicReference<>(); - try (SQLServerConnection con = (SQLServerConnection)DriverManager.getConnection(connectionString)) { + try (SQLServerConnection con = (SQLServerConnection) DriverManager.getConnection(connectionString)) { for (int i = 0; i < 4; i++) { threadPool.execute(new TestPrepareRace(con, queries, exception)); @@ -316,60 +321,104 @@ public void testStatementPoolingPreparedStatementExecAndUnprepareConfig() throws // Verify change dataSource.setStatementPoolingCacheSize(0); assertSame(0, dataSource.getStatementPoolingCacheSize()); - dataSource.setEnablePrepareOnFirstPreparedStatementCall(!dataSource.getEnablePrepareOnFirstPreparedStatementCall()); - dataSource.setServerPreparedStatementDiscardThreshold(dataSource.getServerPreparedStatementDiscardThreshold() + 1); + dataSource.setEnablePrepareOnFirstPreparedStatementCall( + !dataSource.getEnablePrepareOnFirstPreparedStatementCall()); + dataSource.setServerPreparedStatementDiscardThreshold( + dataSource.getServerPreparedStatementDiscardThreshold() + 1); // Verify connection from data source has same parameters. - SQLServerConnection connDataSource = (SQLServerConnection)dataSource.getConnection(); + SQLServerConnection connDataSource = (SQLServerConnection) dataSource.getConnection(); assertSame(dataSource.getStatementPoolingCacheSize(), connDataSource.getStatementPoolingCacheSize()); - assertSame(dataSource.getEnablePrepareOnFirstPreparedStatementCall(), connDataSource.getEnablePrepareOnFirstPreparedStatementCall()); - assertSame(dataSource.getServerPreparedStatementDiscardThreshold(), connDataSource.getServerPreparedStatementDiscardThreshold()); + assertSame(dataSource.getEnablePrepareOnFirstPreparedStatementCall(), + connDataSource.getEnablePrepareOnFirstPreparedStatementCall()); + assertSame(dataSource.getServerPreparedStatementDiscardThreshold(), + connDataSource.getServerPreparedStatementDiscardThreshold()); // Test connection string properties. // Test disableStatementPooling String connectionStringDisableStatementPooling = connectionString + ";disableStatementPooling=true;"; - SQLServerConnection connectionDisableStatementPooling = (SQLServerConnection)DriverManager.getConnection(connectionStringDisableStatementPooling); - connectionDisableStatementPooling.setStatementPoolingCacheSize(10); // to turn on caching and check if disableStatementPooling is true, even setting cachesize won't matter and will disable it. + SQLServerConnection connectionDisableStatementPooling = (SQLServerConnection) DriverManager + .getConnection(connectionStringDisableStatementPooling); + connectionDisableStatementPooling.setStatementPoolingCacheSize(10); // to turn on caching and check if + // disableStatementPooling is true, even + // setting cachesize won't matter and will + // disable it. assertSame(10, connectionDisableStatementPooling.getStatementPoolingCacheSize()); assertTrue(!connectionDisableStatementPooling.isStatementPoolingEnabled()); String connectionStringEnableStatementPooling = connectionString + ";disableStatementPooling=false;"; - SQLServerConnection connectionEnableStatementPooling = (SQLServerConnection)DriverManager.getConnection(connectionStringEnableStatementPooling); - connectionEnableStatementPooling.setStatementPoolingCacheSize(10); // to turn on caching. - assertTrue(0 < connectionEnableStatementPooling.getStatementPoolingCacheSize()); // for now, it won't affect if disable is false or true. Since statementPoolingCacheSize is set to 0 as default. - //If only disableStatementPooling is set to true, it makes sure that statementPoolingCacheSize is zero, thus disabling the prepared statement metadata caching. + SQLServerConnection connectionEnableStatementPooling = (SQLServerConnection) DriverManager + .getConnection(connectionStringEnableStatementPooling); + connectionEnableStatementPooling.setStatementPoolingCacheSize(10); // to turn on caching. + assertTrue(0 < connectionEnableStatementPooling.getStatementPoolingCacheSize()); // for now, it won't affect if + // disable is false or true. + // Since + // statementPoolingCacheSize is + // set to 0 as default. + // If only disableStatementPooling is set to true, it makes sure that statementPoolingCacheSize is zero, thus + // disabling the prepared statement metadata caching. assertTrue(connectionEnableStatementPooling.isStatementPoolingEnabled()); - - String connectionPropertyStringEnableStatementPooling = connectionString + ";disableStatementPooling=false;statementPoolingCacheSize=10"; - SQLServerConnection connectionPropertyEnableStatementPooling = (SQLServerConnection)DriverManager.getConnection(connectionPropertyStringEnableStatementPooling); - assertTrue(0 < connectionPropertyEnableStatementPooling.getStatementPoolingCacheSize()); // for now, it won't affect if disable is false or true. Since statementPoolingCacheSize is set to 0 as default. - //If only disableStatementPooling is set to true, it makes sure that statementPoolingCacheSize is zero, thus disabling the prepared statement metadata caching. + + String connectionPropertyStringEnableStatementPooling = connectionString + + ";disableStatementPooling=false;statementPoolingCacheSize=10"; + SQLServerConnection connectionPropertyEnableStatementPooling = (SQLServerConnection) DriverManager + .getConnection(connectionPropertyStringEnableStatementPooling); + assertTrue(0 < connectionPropertyEnableStatementPooling.getStatementPoolingCacheSize()); // for now, it won't + // affect if disable is + // false or true. Since + // statementPoolingCacheSize + // is set to 0 as + // default. + // If only disableStatementPooling is set to true, it makes sure that statementPoolingCacheSize is zero, thus + // disabling the prepared statement metadata caching. assertTrue(connectionPropertyEnableStatementPooling.isStatementPoolingEnabled()); - - String connectionPropertyStringDisableStatementPooling = connectionString + ";disableStatementPooling=true;statementPoolingCacheSize=10"; - SQLServerConnection connectionPropertyDisableStatementPooling = (SQLServerConnection)DriverManager.getConnection(connectionPropertyStringDisableStatementPooling); - assertTrue(0 < connectionPropertyDisableStatementPooling.getStatementPoolingCacheSize()); // for now, it won't affect if disable is false or true. Since statementPoolingCacheSize is set to 0 as default. - //If only disableStatementPooling is set to true, it makes sure that statementPoolingCacheSize is zero, thus disabling the prepared statement metadata caching. + + String connectionPropertyStringDisableStatementPooling = connectionString + + ";disableStatementPooling=true;statementPoolingCacheSize=10"; + SQLServerConnection connectionPropertyDisableStatementPooling = (SQLServerConnection) DriverManager + .getConnection(connectionPropertyStringDisableStatementPooling); + assertTrue(0 < connectionPropertyDisableStatementPooling.getStatementPoolingCacheSize()); // for now, it won't + // affect if disable + // is false or true. + // Since + // statementPoolingCacheSize + // is set to 0 as + // default. + // If only disableStatementPooling is set to true, it makes sure that statementPoolingCacheSize is zero, thus + // disabling the prepared statement metadata caching. assertTrue(!connectionPropertyDisableStatementPooling.isStatementPoolingEnabled()); - - String connectionPropertyStringDisableStatementPooling2 = connectionString + ";disableStatementPooling=false;statementPoolingCacheSize=0"; - SQLServerConnection connectionPropertyDisableStatementPooling2 = (SQLServerConnection)DriverManager.getConnection(connectionPropertyStringDisableStatementPooling2); - assertTrue(0 == connectionPropertyDisableStatementPooling2.getStatementPoolingCacheSize()); // for now, it won't affect if disable is false or true. Since statementPoolingCacheSize is set to 0 as default. - //If only disableStatementPooling is set to true, it makes sure that statementPoolingCacheSize is zero, thus disabling the prepared statement metadata caching. + + String connectionPropertyStringDisableStatementPooling2 = connectionString + + ";disableStatementPooling=false;statementPoolingCacheSize=0"; + SQLServerConnection connectionPropertyDisableStatementPooling2 = (SQLServerConnection) DriverManager + .getConnection(connectionPropertyStringDisableStatementPooling2); + assertTrue(0 == connectionPropertyDisableStatementPooling2.getStatementPoolingCacheSize()); // for now, it won't + // affect if disable + // is false or true. + // Since + // statementPoolingCacheSize + // is set to 0 as + // default. + // If only disableStatementPooling is set to true, it makes sure that statementPoolingCacheSize is zero, thus + // disabling the prepared statement metadata caching. assertTrue(!connectionPropertyDisableStatementPooling2.isStatementPoolingEnabled()); - + // Test EnablePrepareOnFirstPreparedStatementCall String connectionStringNoExecuteSQL = connectionString + ";enablePrepareOnFirstPreparedStatementCall=true;"; - SQLServerConnection connectionNoExecuteSQL = (SQLServerConnection)DriverManager.getConnection(connectionStringNoExecuteSQL); + SQLServerConnection connectionNoExecuteSQL = (SQLServerConnection) DriverManager + .getConnection(connectionStringNoExecuteSQL); assertSame(true, connectionNoExecuteSQL.getEnablePrepareOnFirstPreparedStatementCall()); // Test ServerPreparedStatementDiscardThreshold String connectionStringThreshold3 = connectionString + ";ServerPreparedStatementDiscardThreshold=3;"; - SQLServerConnection connectionThreshold3 = (SQLServerConnection)DriverManager.getConnection(connectionStringThreshold3); + SQLServerConnection connectionThreshold3 = (SQLServerConnection) DriverManager + .getConnection(connectionStringThreshold3); assertSame(3, connectionThreshold3.getServerPreparedStatementDiscardThreshold()); // Test combination of EnablePrepareOnFirstPreparedStatementCall and ServerPreparedStatementDiscardThreshold - String connectionStringThresholdAndNoExecuteSQL = connectionString + ";ServerPreparedStatementDiscardThreshold=3;enablePrepareOnFirstPreparedStatementCall=true;"; - SQLServerConnection connectionThresholdAndNoExecuteSQL = (SQLServerConnection)DriverManager.getConnection(connectionStringThresholdAndNoExecuteSQL); + String connectionStringThresholdAndNoExecuteSQL = connectionString + + ";ServerPreparedStatementDiscardThreshold=3;enablePrepareOnFirstPreparedStatementCall=true;"; + SQLServerConnection connectionThresholdAndNoExecuteSQL = (SQLServerConnection) DriverManager + .getConnection(connectionStringThresholdAndNoExecuteSQL); assertSame(true, connectionThresholdAndNoExecuteSQL.getEnablePrepareOnFirstPreparedStatementCall()); assertSame(3, connectionThresholdAndNoExecuteSQL.getServerPreparedStatementDiscardThreshold()); @@ -378,21 +427,20 @@ public void testStatementPoolingPreparedStatementExecAndUnprepareConfig() throws String connectionStringThresholdError = connectionString + ";ServerPreparedStatementDiscardThreshold=hej;"; DriverManager.getConnection(connectionStringThresholdError); fail("Error for invalid ServerPreparedStatementDiscardThresholdexpected."); - } - catch(SQLException e) { + } catch (SQLException e) { // Good! } try { - String connectionStringNoExecuteSQLError = connectionString + ";enablePrepareOnFirstPreparedStatementCall=dobidoo;"; + String connectionStringNoExecuteSQLError = connectionString + + ";enablePrepareOnFirstPreparedStatementCall=dobidoo;"; DriverManager.getConnection(connectionStringNoExecuteSQLError); fail("Error for invalid enablePrepareOnFirstPreparedStatementCall expected."); - } - catch(SQLException e) { + } catch (SQLException e) { // Good! } // Verify instance setting is followed. - try (SQLServerConnection con = (SQLServerConnection)DriverManager.getConnection(connectionString)) { + try (SQLServerConnection con = (SQLServerConnection) DriverManager.getConnection(connectionString)) { // Turn off use of prepared statement cache. con.setStatementPoolingCacheSize(0); @@ -403,7 +451,7 @@ public void testStatementPoolingPreparedStatementExecAndUnprepareConfig() throws assertTrue(1 < con.getServerPreparedStatementDiscardThreshold()); // Verify first use is batched. - try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement)con.prepareStatement(query)) { + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con.prepareStatement(query)) { pstmt.execute(); // sp_executesql pstmt.execute(); // sp_prepexec } @@ -418,60 +466,64 @@ public void testStatementPoolingPreparedStatementExecAndUnprepareConfig() throws assertSame(0, con.getDiscardedServerPreparedStatementCount()); // Set instance setting to serial execution of un-prepare actions. - con.setServerPreparedStatementDiscardThreshold(1); + con.setServerPreparedStatementDiscardThreshold(1); - try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement)con.prepareStatement(query)) { + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con.prepareStatement(query)) { pstmt.execute(); } // Verify that the un-prepare action was handled immediately. assertSame(0, con.getDiscardedServerPreparedStatementCount()); } } - + private void testStatementPoolingInternal(String mode) throws Exception { // Test % handle re-use - try (SQLServerConnection con = (SQLServerConnection)DriverManager.getConnection(connectionString)) { + try (SQLServerConnection con = (SQLServerConnection) DriverManager.getConnection(connectionString)) { if (mode.equalsIgnoreCase("bulkcopy")) { modifyConnectionForBulkCopyAPI(con); } - String query = String.format("/*statementpoolingtest_re-use_%s*/SELECT TOP(1) * FROM sys.tables;", UUID.randomUUID().toString()); + String query = String.format("/*statementpoolingtest_re-use_%s*/SELECT TOP(1) * FROM sys.tables;", + UUID.randomUUID().toString()); con.setStatementPoolingCacheSize(10); boolean[] prepOnFirstCalls = {false, true}; - for(boolean prepOnFirstCall : prepOnFirstCalls) { + for (boolean prepOnFirstCall : prepOnFirstCalls) { con.setEnablePrepareOnFirstPreparedStatementCall(prepOnFirstCall); int[] queryCounts = {10, 20, 30, 40}; - for(int queryCount : queryCounts) { + for (int queryCount : queryCounts) { String[] queries = new String[queryCount]; - for(int i = 0; i < queries.length; ++i) { + for (int i = 0; i < queries.length; ++i) { queries[i] = String.format("%s--%s--%s--%s", query, i, queryCount, prepOnFirstCall); } int testsWithHandleReuse = 0; final int testCount = 500; - for(int i = 0; i < testCount; ++i) { + for (int i = 0; i < testCount; ++i) { Random random = new Random(); int queryNumber = random.nextInt(queries.length); - try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con.prepareStatement(queries[queryNumber])) { + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con + .prepareStatement(queries[queryNumber])) { pstmt.execute(); // Grab handle-reuse before it would be populated if initially created. - if(0 < pstmt.getPreparedStatementHandle()) + if (0 < pstmt.getPreparedStatementHandle()) testsWithHandleReuse++; pstmt.getMoreResults(); // Make sure handle is updated. } } - System.out.println(String.format("Prep on first call: %s Query count:%s: %s of %s (%s)", prepOnFirstCall, queryCount, testsWithHandleReuse, testCount, (double)testsWithHandleReuse/(double)testCount)); + System.out.println(String.format("Prep on first call: %s Query count:%s: %s of %s (%s)", + prepOnFirstCall, queryCount, testsWithHandleReuse, testCount, + (double) testsWithHandleReuse / (double) testCount)); } } } - try (SQLServerConnection con = (SQLServerConnection)DriverManager.getConnection(connectionString)) { + try (SQLServerConnection con = (SQLServerConnection) DriverManager.getConnection(connectionString)) { if (mode.equalsIgnoreCase("bulkcopy")) { modifyConnectionForBulkCopyAPI(con); } @@ -487,10 +539,11 @@ private void testStatementPoolingInternal(String mode) throws Exception { for (int i = 0; i < 100; ++i) { try { assertSame(1, pstmt.executeUpdate()); - } - catch (SQLException e) { - // Error "Prepared handle GAH" is expected to happen. But it should not terminate the execution with RAISERROR. - // Since the original "Could not find prepared statement with handle" error does not terminate the execution after it. + } catch (SQLException e) { + // Error "Prepared handle GAH" is expected to happen. But it should not terminate the execution + // with RAISERROR. + // Since the original "Could not find prepared statement with handle" error does not terminate + // the execution after it. if (!e.getMessage().contains("Prepared handle GAH")) { throw e; } @@ -519,10 +572,11 @@ private void testStatementPoolingInternal(String mode) throws Exception { int[] updateCounts = null; try { updateCounts = pstmt.executeBatch(); - } - catch (BatchUpdateException e) { - // Error "Prepared handle GAH" is expected to happen. But it should not terminate the execution with RAISERROR. - // Since the original "Could not find prepared statement with handle" error does not terminate the execution after it. + } catch (BatchUpdateException e) { + // Error "Prepared handle GAH" is expected to happen. But it should not terminate the execution with + // RAISERROR. + // Since the original "Could not find prepared statement with handle" error does not terminate the + // execution after it. if (!e.getMessage().contains("Prepared handle GAH")) { throw e; } @@ -539,8 +593,8 @@ private void testStatementPoolingInternal(String mode) throws Exception { } } } - - try (SQLServerConnection con = (SQLServerConnection)DriverManager.getConnection(connectionString)) { + + try (SQLServerConnection con = (SQLServerConnection) DriverManager.getConnection(connectionString)) { if (mode.equalsIgnoreCase("bulkcopy")) { modifyConnectionForBulkCopyAPI(con); } @@ -552,57 +606,57 @@ private void testStatementPoolingInternal(String mode) throws Exception { String query = String.format("/*statementpoolingtest_%s*/SELECT * FROM sys.tables;", lookupUniqueifier); // Execute statement first, should create cache entry WITHOUT handle (since sp_executesql was used). - try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement)con.prepareStatement(query)) { + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con.prepareStatement(query)) { pstmt.execute(); // sp_executesql pstmt.getMoreResults(); // Make sure handle is updated. assertSame(0, pstmt.getPreparedStatementHandle()); - } + } // Execute statement again, should now create handle. int handle = 0; - try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement)con.prepareStatement(query)) { + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con.prepareStatement(query)) { pstmt.execute(); // sp_prepexec pstmt.getMoreResults(); // Make sure handle is updated. - + handle = pstmt.getPreparedStatementHandle(); assertNotSame(0, handle); - } + } - // Execute statement again and verify same handle was used. - try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement)con.prepareStatement(query)) { + // Execute statement again and verify same handle was used. + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con.prepareStatement(query)) { pstmt.execute(); // sp_execute pstmt.getMoreResults(); // Make sure handle is updated. assertNotSame(0, pstmt.getPreparedStatementHandle()); assertSame(handle, pstmt.getPreparedStatementHandle()); - } + } - // Execute new statement with different SQL text and verify it does NOT get same handle (should now fall back to using sp_executesql). + // Execute new statement with different SQL text and verify it does NOT get same handle (should now fall + // back to using sp_executesql). SQLServerPreparedStatement outer = null; - try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement)con.prepareStatement(query + ";")) { + try (SQLServerPreparedStatement pstmt = (SQLServerPreparedStatement) con.prepareStatement(query + ";")) { outer = pstmt; pstmt.execute(); // sp_executesql pstmt.getMoreResults(); // Make sure handle is updated. assertSame(0, pstmt.getPreparedStatementHandle()); assertNotSame(handle, pstmt.getPreparedStatementHandle()); - } + } try { System.out.println(outer.getPreparedStatementHandle()); fail(TestResource.getResource("R_invalidGetPreparedStatementHandle")); - } - catch(Exception e) { + } catch (Exception e) { // Good! } - } + } } - + private void modifyConnectionForBulkCopyAPI(SQLServerConnection con) throws Exception { Field f1 = SQLServerConnection.class.getDeclaredField("isAzureDW"); f1.setAccessible(true); f1.set(con, true); - + con.setUseBulkCopyForBatchInsert(true); } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/RegressionTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/RegressionTest.java index 1efa1e25a..1cdac5dc2 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/RegressionTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/RegressionTest.java @@ -1,21 +1,17 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.unit.statement; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assumptions.assumeTrue; +import java.sql.Connection; import java.sql.DriverManager; import java.sql.JDBCType; import java.sql.PreparedStatement; import java.sql.ResultSet; -import java.sql.Connection; -import java.sql.Statement; import java.sql.SQLException; import java.sql.Statement; import java.sql.Types; @@ -32,6 +28,7 @@ import com.microsoft.sqlserver.testframework.DBConnection; import com.microsoft.sqlserver.testframework.Utils; + @RunWith(JUnitPlatform.class) public class RegressionTest extends AbstractTest { private static String tableName = "[ServerCursorPStmt]"; @@ -67,27 +64,30 @@ public void testServerCursorPStmt() throws SQLException { if (DBConnection.isSqlAzure(con)) { // On SQL Azure, 'SELECT INTO' is not supported. So do not use it. - storedProcString = "CREATE PROCEDURE " + procName + " @param varchar(3) AS SELECT col3 FROM " + tableName + " WHERE col2 = @param"; - } - else { + storedProcString = "CREATE PROCEDURE " + procName + " @param varchar(3) AS SELECT col3 FROM " + tableName + + " WHERE col2 = @param"; + } else { // On SQL Server - storedProcString = "CREATE PROCEDURE " + procName + " @param varchar(3) AS SELECT col3 INTO #TMPTABLE FROM " + tableName - + " WHERE col2 = @param SELECT col3 FROM #TMPTABLE"; + storedProcString = "CREATE PROCEDURE " + procName + " @param varchar(3) AS SELECT col3 INTO #TMPTABLE FROM " + + tableName + " WHERE col2 = @param SELECT col3 FROM #TMPTABLE"; } stmt.executeUpdate(storedProcString); // execute stored proc via pstmt - pstmt = con.prepareStatement("EXEC " + procName + " ?", ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); + pstmt = con.prepareStatement("EXEC " + procName + " ?", ResultSet.TYPE_SCROLL_INSENSITIVE, + ResultSet.CONCUR_READ_ONLY); pstmt.setString(1, col3Lookup); // should return 1 row rs = pstmt.executeQuery(); rs.last(); - assertEquals(rs.getRow(), numRowsInResult, TestResource.getResource("R_valueNotMatch") + rs.getRow() + ", " + numRowsInResult); + assertEquals(rs.getRow(), numRowsInResult, + TestResource.getResource("R_valueNotMatch") + rs.getRow() + ", " + numRowsInResult); rs.beforeFirst(); while (rs.next()) { - assertEquals(rs.getString(1), col3Value, TestResource.getResource("R_valueNotMatch") + rs.getString(1) + ", " + col3Value); + assertEquals(rs.getString(1), col3Value, + TestResource.getResource("R_valueNotMatch") + rs.getString(1) + ", " + col3Value); } if (null != stmt) @@ -104,32 +104,34 @@ public void testServerCursorPStmt() throws SQLException { @Test public void testSelectIntoUpdateCount() throws SQLException { SQLServerConnection con = (SQLServerConnection) DriverManager.getConnection(connectionString); - + // Azure does not do SELECT INTO if (!DBConnection.isSqlAzure(con)) { final String tableName = "[#SourceTableForSelectInto]"; - + Statement stmt = con.createStatement(); - stmt.executeUpdate("CREATE TABLE " + tableName + " (col1 int primary key, col2 varchar(3), col3 varchar(128))"); + stmt.executeUpdate( + "CREATE TABLE " + tableName + " (col1 int primary key, col2 varchar(3), col3 varchar(128))"); stmt.executeUpdate("INSERT INTO " + tableName + " VALUES (1, 'CAN', 'Canada')"); stmt.executeUpdate("INSERT INTO " + tableName + " VALUES (2, 'USA', 'United States of America')"); stmt.executeUpdate("INSERT INTO " + tableName + " VALUES (3, 'JPN', 'Japan')"); // expected values int numRowsToCopy = 2; - - PreparedStatement ps = con.prepareStatement("SELECT * INTO #TMPTABLE FROM " + tableName + " WHERE col1 <= ?"); + + PreparedStatement ps = con + .prepareStatement("SELECT * INTO #TMPTABLE FROM " + tableName + " WHERE col1 <= ?"); ps.setInt(1, numRowsToCopy); int updateCount = ps.executeUpdate(); assertEquals(numRowsToCopy, updateCount, TestResource.getResource("R_incorrectUpdateCount")); - + if (null != stmt) stmt.close(); } if (null != con) con.close(); } - + /** * Tests update query * @@ -137,13 +139,14 @@ public void testSelectIntoUpdateCount() throws SQLException { */ @Test public void testUpdateQuery() throws SQLException { - assumeTrue("JDBC41".equals(Utils.getConfiguredProperty("JDBC_Version")), TestResource.getResource("R_incompatJDBC")); + assumeTrue("JDBC41".equals(Utils.getConfiguredProperty("JDBC_Version")), + TestResource.getResource("R_incompatJDBC")); SQLServerConnection con = (SQLServerConnection) DriverManager.getConnection(connectionString); String sql; SQLServerPreparedStatement pstmt = null; JDBCType[] targets = {JDBCType.INTEGER, JDBCType.SMALLINT}; - int rows = 3; + int rows = 3; final String tableName = "[updateQuery]"; Statement stmt = con.createStatement(); @@ -154,9 +157,9 @@ public void testUpdateQuery() throws SQLException { * populate table */ sql = "insert into " + tableName + " values(" + "?,?" + ")"; - pstmt = (SQLServerPreparedStatement)con.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, + pstmt = (SQLServerPreparedStatement) con.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, connection.getHoldability()); - + for (int i = 1; i <= rows; i++) { pstmt.setObject(1, i, JDBCType.INTEGER); pstmt.setObject(2, i, JDBCType.INTEGER); @@ -168,20 +171,20 @@ public void testUpdateQuery() throws SQLException { */ sql = "update " + tableName + " SET c1= ? where PK =1"; for (int i = 1; i <= rows; i++) { - pstmt = (SQLServerPreparedStatement)con.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + pstmt = (SQLServerPreparedStatement) con.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, + ResultSet.CONCUR_READ_ONLY); for (JDBCType target : targets) { pstmt.setObject(1, 5 + i, target); pstmt.executeUpdate(); } } - + /* * Verify */ - ResultSet rs = stmt.executeQuery("select * from " + tableName); + ResultSet rs = stmt.executeQuery("select * from " + tableName); rs.next(); assertEquals(rs.getInt(1), 8, "Value mismatch"); - if (null != stmt) stmt.close(); @@ -191,14 +194,15 @@ public void testUpdateQuery() throws SQLException { private String xmlTableName = "try_SQLXML_Table"; - /** + /** * Tests XML query * * @throws SQLException */ @Test public void testXmlQuery() throws SQLException { - assumeTrue("JDBC41".equals(Utils.getConfiguredProperty("JDBC_Version")), TestResource.getResource("R_incompatJDBC")); + assumeTrue("JDBC41".equals(Utils.getConfiguredProperty("JDBC_Version")), + TestResource.getResource("R_incompatJDBC")); Connection connection = DriverManager.getConnection(connectionString); @@ -222,7 +226,7 @@ public void testXmlQuery() throws SQLException { pstmt = (SQLServerPreparedStatement) connection.prepareStatement(sql); pstmt.setObject(1, null); pstmt.setObject(2, null, Types.SQLXML); - pstmt.executeUpdate(); + pstmt.executeUpdate(); } private void dropTables(Statement stmt) throws SQLException { diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/RegressionTestAlwaysEncrypted.java b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/RegressionTestAlwaysEncrypted.java index 8fe6d0f9a..005a40e01 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/RegressionTestAlwaysEncrypted.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/RegressionTestAlwaysEncrypted.java @@ -1,313 +1,109 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ -/* TODO: Make possible to run automated (including certs, only works on Windows now etc.)*/ +/* TODO: Make possible to run automated (including certs, only works on Windows now etc.) */ /* -package com.microsoft.sqlserver.jdbc.unit.statement; - -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.sql.Connection; -import java.sql.Date; -import java.sql.DriverManager; -import java.sql.JDBCType; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -import org.junit.jupiter.api.Test; -import org.junit.platform.runner.JUnitPlatform; -import org.junit.runner.RunWith; - -import com.microsoft.sqlserver.jdbc.SQLServerConnection; -import com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement; -import com.microsoft.sqlserver.jdbc.SQLServerResultSet; -import com.microsoft.sqlserver.testframework.AbstractTest; - -@RunWith(JUnitPlatform.class) -public class RegressionTestAlwaysEncrypted extends AbstractTest { - String dateTable = "DateTable"; - String charTable = "CharTable"; - String numericTable = "NumericTable"; - Statement stmt = null; - Connection connection = null; - Date date; - String cekName = "CEK_Auto1"; // you need to change this to your CEK - long dateValue = 212921879801519L; - - @Test - public void alwaysEncrypted1() throws Exception { - - Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); - connection = DriverManager.getConnection(connectionString + ";trustservercertificate=true;columnEncryptionSetting=enabled;database=Tobias;"); - assertTrue(null != connection); - - stmt = ((SQLServerConnection) connection).createStatement(); - - date = new Date(dateValue); - - dropTable(); - createNumericTable(); - populateNumericTable(); - printNumericTable(); - - dropTable(); - createDateTable(); - populateDateTable(); - printDateTable(); - - dropTable(); - createNumericTable(); - populateNumericTableWithNull(); - printNumericTable(); - } - - @Test - public void alwaysEncrypted2() throws Exception { - - Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); - connection = DriverManager.getConnection(connectionString + ";trustservercertificate=true;columnEncryptionSetting=enabled;database=Tobias;"); - assertTrue(null != connection); - - stmt = ((SQLServerConnection) connection).createStatement(); - - date = new Date(dateValue); - - dropTable(); - createCharTable(); - populateCharTable(); - printCharTable(); - - dropTable(); - createDateTable(); - populateDateTable(); - printDateTable(); - - dropTable(); - createNumericTable(); - populateNumericTableSpecificSetter(); - printNumericTable(); - - } - - private void populateDateTable() { - - try { - String sql = "insert into " + dateTable + " values( " + "?" + ")"; - SQLServerPreparedStatement sqlPstmt = (SQLServerPreparedStatement) ((SQLServerConnection) connection).prepareStatement(sql, - ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, connection.getHoldability()); - sqlPstmt.setObject(1, date); - sqlPstmt.executeUpdate(); - } - catch (Exception e) { - e.printStackTrace(); - } - } - - private void populateCharTable() { - - try { - String sql = "insert into " + charTable + " values( " + "?,?,?,?,?,?" + ")"; - SQLServerPreparedStatement sqlPstmt = (SQLServerPreparedStatement) ((SQLServerConnection) connection).prepareStatement(sql, - ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, connection.getHoldability()); - sqlPstmt.setObject(1, "hi"); - sqlPstmt.setObject(2, "sample"); - sqlPstmt.setObject(3, "hey"); - sqlPstmt.setObject(4, "test"); - sqlPstmt.setObject(5, "hello"); - sqlPstmt.setObject(6, "caching"); - sqlPstmt.executeUpdate(); - } - catch (Exception e) { - e.printStackTrace(); - } - } - - private void populateNumericTable() throws Exception { - String sql = "insert into " + numericTable + " values( " + "?,?,?,?,?,?,?,?,?" + ")"; - SQLServerPreparedStatement sqlPstmt = (SQLServerPreparedStatement) ((SQLServerConnection) connection).prepareStatement(sql, - ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, connection.getHoldability()); - sqlPstmt.setObject(1, true); - sqlPstmt.setObject(2, false); - sqlPstmt.setObject(3, true); - - Integer value = 255; - sqlPstmt.setObject(4, value.shortValue(), JDBCType.TINYINT); - sqlPstmt.setObject(5, value.shortValue(), JDBCType.TINYINT); - sqlPstmt.setObject(6, value.shortValue(), JDBCType.TINYINT); - - sqlPstmt.setObject(7, Short.valueOf("1"), JDBCType.SMALLINT); - sqlPstmt.setObject(8, Short.valueOf("2"), JDBCType.SMALLINT); - sqlPstmt.setObject(9, Short.valueOf("3"), JDBCType.SMALLINT); - - sqlPstmt.executeUpdate(); - } - - private void populateNumericTableSpecificSetter() { - - try { - String sql = "insert into " + numericTable + " values( " + "?,?,?,?,?,?,?,?,?" + ")"; - SQLServerPreparedStatement sqlPstmt = (SQLServerPreparedStatement) ((SQLServerConnection) connection).prepareStatement(sql, - ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, connection.getHoldability()); - sqlPstmt.setBoolean(1, true); - sqlPstmt.setBoolean(2, false); - sqlPstmt.setBoolean(3, true); - - Integer value = 255; - sqlPstmt.setShort(4, value.shortValue()); - sqlPstmt.setShort(5, value.shortValue()); - sqlPstmt.setShort(6, value.shortValue()); - - sqlPstmt.setByte(7, Byte.valueOf("127")); - sqlPstmt.setByte(8, Byte.valueOf("127")); - sqlPstmt.setByte(9, Byte.valueOf("127")); - - sqlPstmt.executeUpdate(); - } - catch (Exception e) { - e.printStackTrace(); - } - } - - private void populateNumericTableWithNull() { - - try { - String sql = "insert into " + numericTable + " values( " + "?,?,?" + ",?,?,?" + ",?,?,?" + ")"; - SQLServerPreparedStatement sqlPstmt = (SQLServerPreparedStatement) ((SQLServerConnection) connection).prepareStatement(sql, - ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, connection.getHoldability()); - sqlPstmt.setObject(1, null, java.sql.Types.BIT); - sqlPstmt.setObject(2, null, java.sql.Types.BIT); - sqlPstmt.setObject(3, null, java.sql.Types.BIT); - - sqlPstmt.setObject(4, null, java.sql.Types.TINYINT); - sqlPstmt.setObject(5, null, java.sql.Types.TINYINT); - sqlPstmt.setObject(6, null, java.sql.Types.TINYINT); - - sqlPstmt.setObject(7, null, java.sql.Types.SMALLINT); - sqlPstmt.setObject(8, null, java.sql.Types.SMALLINT); - sqlPstmt.setObject(9, null, java.sql.Types.SMALLINT); - - sqlPstmt.executeUpdate(); - } - catch (Exception e) { - e.printStackTrace(); - } - } - - private void printDateTable() throws SQLException { - - stmt = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); - SQLServerResultSet rs = (SQLServerResultSet) stmt.executeQuery("select * from " + dateTable); - - while (rs.next()) { - System.out.println(rs.getObject(1)); - } - } - - private void printCharTable() throws SQLException { - stmt = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); - SQLServerResultSet rs = (SQLServerResultSet) stmt.executeQuery("select * from " + charTable); - - while (rs.next()) { - System.out.println(rs.getObject(1)); - System.out.println(rs.getObject(2)); - System.out.println(rs.getObject(3)); - System.out.println(rs.getObject(4)); - System.out.println(rs.getObject(5)); - System.out.println(rs.getObject(6)); - } - - } - - private void printNumericTable() throws SQLException { - stmt = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); - SQLServerResultSet rs = (SQLServerResultSet) stmt.executeQuery("select * from " + numericTable); - - while (rs.next()) { - System.out.println(rs.getObject(1)); - System.out.println(rs.getObject(2)); - System.out.println(rs.getObject(3)); - System.out.println(rs.getObject(4)); - System.out.println(rs.getObject(5)); - System.out.println(rs.getObject(6)); - } - - } - - private void createDateTable() throws SQLException { - - String sql = "create table " + dateTable + " (" - + "RandomizedDate date ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " - + cekName + ") NULL," + ");"; - - try { - stmt.execute(sql); - } - catch (SQLException e) { - System.out.println(e); - } - } - - private 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," - - + ");"; - - try { - stmt.execute(sql); - } - catch (SQLException e) { - System.out.println(e.getMessage()); - } - } - - private 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," - - + ");"; - - try { - stmt.execute(sql); - } - catch (SQLException e) { - System.out.println(e.getMessage()); - } - } - - private void dropTable() throws SQLException { - stmt.executeUpdate("if object_id('" + dateTable + "','U') is not null" + " drop table " + dateTable); - stmt.executeUpdate("if object_id('" + charTable + "','U') is not null" + " drop table " + charTable); - stmt.executeUpdate("if object_id('" + numericTable + "','U') is not null" + " drop table " + numericTable); - } -} -*/ \ No newline at end of file + * package com.microsoft.sqlserver.jdbc.unit.statement; import static org.junit.jupiter.api.Assertions.assertTrue; + * import java.sql.Connection; import java.sql.Date; import java.sql.DriverManager; import java.sql.JDBCType; import + * java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import org.junit.jupiter.api.Test; + * import org.junit.platform.runner.JUnitPlatform; import org.junit.runner.RunWith; import + * com.microsoft.sqlserver.jdbc.SQLServerConnection; import com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement; + * import com.microsoft.sqlserver.jdbc.SQLServerResultSet; import com.microsoft.sqlserver.testframework.AbstractTest; + * @RunWith(JUnitPlatform.class) public class RegressionTestAlwaysEncrypted extends AbstractTest { String dateTable = + * "DateTable"; String charTable = "CharTable"; String numericTable = "NumericTable"; Statement stmt = null; Connection + * connection = null; Date date; String cekName = "CEK_Auto1"; // you need to change this to your CEK long dateValue = + * 212921879801519L; + * @Test public void alwaysEncrypted1() throws Exception { + * Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); connection = + * DriverManager.getConnection(connectionString + + * ";trustservercertificate=true;columnEncryptionSetting=enabled;database=Tobias;"); assertTrue(null != connection); + * stmt = ((SQLServerConnection) connection).createStatement(); date = new Date(dateValue); dropTable(); + * createNumericTable(); populateNumericTable(); printNumericTable(); dropTable(); createDateTable(); + * populateDateTable(); printDateTable(); dropTable(); createNumericTable(); populateNumericTableWithNull(); + * printNumericTable(); } + * @Test public void alwaysEncrypted2() throws Exception { + * Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); connection = + * DriverManager.getConnection(connectionString + + * ";trustservercertificate=true;columnEncryptionSetting=enabled;database=Tobias;"); assertTrue(null != connection); + * stmt = ((SQLServerConnection) connection).createStatement(); date = new Date(dateValue); dropTable(); + * createCharTable(); populateCharTable(); printCharTable(); dropTable(); createDateTable(); populateDateTable(); + * printDateTable(); dropTable(); createNumericTable(); populateNumericTableSpecificSetter(); printNumericTable(); } + * private void populateDateTable() { try { String sql = "insert into " + dateTable + " values( " + "?" + ")"; + * SQLServerPreparedStatement sqlPstmt = (SQLServerPreparedStatement) ((SQLServerConnection) + * connection).prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, + * connection.getHoldability()); sqlPstmt.setObject(1, date); sqlPstmt.executeUpdate(); } catch (Exception e) { + * e.printStackTrace(); } } private void populateCharTable() { try { String sql = "insert into " + charTable + + * " values( " + "?,?,?,?,?,?" + ")"; SQLServerPreparedStatement sqlPstmt = (SQLServerPreparedStatement) + * ((SQLServerConnection) connection).prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, + * connection.getHoldability()); sqlPstmt.setObject(1, "hi"); sqlPstmt.setObject(2, "sample"); sqlPstmt.setObject(3, + * "hey"); sqlPstmt.setObject(4, "test"); sqlPstmt.setObject(5, "hello"); sqlPstmt.setObject(6, "caching"); + * sqlPstmt.executeUpdate(); } catch (Exception e) { e.printStackTrace(); } } private void populateNumericTable() throws + * Exception { String sql = "insert into " + numericTable + " values( " + "?,?,?,?,?,?,?,?,?" + ")"; + * SQLServerPreparedStatement sqlPstmt = (SQLServerPreparedStatement) ((SQLServerConnection) + * connection).prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, + * connection.getHoldability()); sqlPstmt.setObject(1, true); sqlPstmt.setObject(2, false); sqlPstmt.setObject(3, true); + * Integer value = 255; sqlPstmt.setObject(4, value.shortValue(), JDBCType.TINYINT); sqlPstmt.setObject(5, + * value.shortValue(), JDBCType.TINYINT); sqlPstmt.setObject(6, value.shortValue(), JDBCType.TINYINT); + * sqlPstmt.setObject(7, Short.valueOf("1"), JDBCType.SMALLINT); sqlPstmt.setObject(8, Short.valueOf("2"), + * JDBCType.SMALLINT); sqlPstmt.setObject(9, Short.valueOf("3"), JDBCType.SMALLINT); sqlPstmt.executeUpdate(); } private + * void populateNumericTableSpecificSetter() { try { String sql = "insert into " + numericTable + " values( " + + * "?,?,?,?,?,?,?,?,?" + ")"; SQLServerPreparedStatement sqlPstmt = (SQLServerPreparedStatement) ((SQLServerConnection) + * connection).prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, + * connection.getHoldability()); sqlPstmt.setBoolean(1, true); sqlPstmt.setBoolean(2, false); sqlPstmt.setBoolean(3, + * true); Integer value = 255; sqlPstmt.setShort(4, value.shortValue()); sqlPstmt.setShort(5, value.shortValue()); + * sqlPstmt.setShort(6, value.shortValue()); sqlPstmt.setByte(7, Byte.valueOf("127")); sqlPstmt.setByte(8, + * Byte.valueOf("127")); sqlPstmt.setByte(9, Byte.valueOf("127")); sqlPstmt.executeUpdate(); } catch (Exception e) { + * e.printStackTrace(); } } private void populateNumericTableWithNull() { try { String sql = "insert into " + + * numericTable + " values( " + "?,?,?" + ",?,?,?" + ",?,?,?" + ")"; SQLServerPreparedStatement sqlPstmt = + * (SQLServerPreparedStatement) ((SQLServerConnection) connection).prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, + * ResultSet.CONCUR_READ_ONLY, connection.getHoldability()); sqlPstmt.setObject(1, null, java.sql.Types.BIT); + * sqlPstmt.setObject(2, null, java.sql.Types.BIT); sqlPstmt.setObject(3, null, java.sql.Types.BIT); + * sqlPstmt.setObject(4, null, java.sql.Types.TINYINT); sqlPstmt.setObject(5, null, java.sql.Types.TINYINT); + * sqlPstmt.setObject(6, null, java.sql.Types.TINYINT); sqlPstmt.setObject(7, null, java.sql.Types.SMALLINT); + * sqlPstmt.setObject(8, null, java.sql.Types.SMALLINT); sqlPstmt.setObject(9, null, java.sql.Types.SMALLINT); + * sqlPstmt.executeUpdate(); } catch (Exception e) { e.printStackTrace(); } } private void printDateTable() throws + * SQLException { stmt = connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); + * SQLServerResultSet rs = (SQLServerResultSet) stmt.executeQuery("select * from " + dateTable); while (rs.next()) { + * System.out.println(rs.getObject(1)); } } private void printCharTable() throws SQLException { stmt = + * connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); SQLServerResultSet rs = + * (SQLServerResultSet) stmt.executeQuery("select * from " + charTable); while (rs.next()) { + * System.out.println(rs.getObject(1)); System.out.println(rs.getObject(2)); System.out.println(rs.getObject(3)); + * System.out.println(rs.getObject(4)); System.out.println(rs.getObject(5)); System.out.println(rs.getObject(6)); } } + * private void printNumericTable() throws SQLException { stmt = + * connection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); SQLServerResultSet rs = + * (SQLServerResultSet) stmt.executeQuery("select * from " + numericTable); while (rs.next()) { + * System.out.println(rs.getObject(1)); System.out.println(rs.getObject(2)); System.out.println(rs.getObject(3)); + * System.out.println(rs.getObject(4)); System.out.println(rs.getObject(5)); System.out.println(rs.getObject(6)); } } + * private void createDateTable() throws SQLException { String sql = "create table " + dateTable + " (" + + * "RandomizedDate date ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = " + * + cekName + ") NULL," + ");"; try { stmt.execute(sql); } catch (SQLException e) { System.out.println(e); } } private + * 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," + ");"; try { stmt.execute(sql); } catch (SQLException e) { System.out.println(e.getMessage()); + * } } private 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," + ");"; try { stmt.execute(sql); } catch (SQLException e) { System.out.println(e.getMessage()); + * } } private void dropTable() throws SQLException { stmt.executeUpdate("if object_id('" + dateTable + + * "','U') is not null" + " drop table " + dateTable); stmt.executeUpdate("if object_id('" + charTable + + * "','U') is not null" + " drop table " + charTable); stmt.executeUpdate("if object_id('" + numericTable + + * "','U') is not null" + " drop table " + numericTable); } } + */ diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/StatementCancellationTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/StatementCancellationTest.java index 224414a9f..e8dcb6dff 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/StatementCancellationTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/StatementCancellationTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.unit.statement; @@ -21,6 +18,7 @@ import com.microsoft.sqlserver.jdbc.TestResource; import com.microsoft.sqlserver.testframework.AbstractTest; + @RunWith(JUnitPlatform.class) public class StatementCancellationTest extends AbstractTest { private static final long DELAY_WAIT_MILLISECONDS = 10000; @@ -46,8 +44,7 @@ public void run() { try { Thread.sleep(CANCEL_WAIT_MILLISECONDS); stmt.cancel(); - } - catch (Exception e) { + } catch (Exception e) { e.printStackTrace(); } } @@ -58,20 +55,20 @@ public void run() { try { timeStart = System.currentTimeMillis(); stmt.execute("WAITFOR DELAY '00:00:" + (DELAY_WAIT_MILLISECONDS / 1000) + "'"); - } - catch (SQLException e) { + } catch (SQLException e) { // The query was canceled"), "Unexpected error message - assertTrue(e.getMessage().startsWith(TestResource.getResource("R_queryCancelled")), TestResource.getResource("R_unexpectedExceptionContent")); + assertTrue(e.getMessage().startsWith(TestResource.getResource("R_queryCancelled")), + TestResource.getResource("R_unexpectedExceptionContent")); } } } - } - finally { + } finally { timeEnd = System.currentTimeMillis(); long timeDifference = timeEnd - timeStart; assertTrue(timeDifference >= CANCEL_WAIT_MILLISECONDS, TestResource.getResource("R_cancellationFailed")); assertTrue(timeDifference < DELAY_WAIT_MILLISECONDS, TestResource.getResource("R_cancellationFailed")); - assertTrue((timeDifference - CANCEL_WAIT_MILLISECONDS) < 1000, TestResource.getResource("R_cancellationFailed")); + assertTrue((timeDifference - CANCEL_WAIT_MILLISECONDS) < 1000, + TestResource.getResource("R_cancellationFailed")); } } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/StatementTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/StatementTest.java index 2b322c47b..8eff3089b 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/StatementTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/StatementTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.unit.statement; @@ -55,6 +52,7 @@ import com.microsoft.sqlserver.testframework.Utils; import com.microsoft.sqlserver.testframework.util.RandomUtil; + /** * * Statement class for testing statement APIs and triggers @@ -69,9 +67,9 @@ public class TCAttentionHandling { private static final int NUM_TABLE_ROWS = 1000; private static final int MIN_TABLE_ROWS = 100; private static final String TEST_STRING = "Hello." + " This is a test string." - + " It is particularly long so that we will get a multipacket TDS response back from the server." + " This is a test string." - + " This is a test string." + " This is a test string." + " This is a test string." + " This is a test string." - + " This is a test string."; + + " It is particularly long so that we will get a multipacket TDS response back from the server." + + " This is a test string." + " This is a test string." + " This is a test string." + + " This is a test string." + " This is a test string." + " This is a test string."; String tableN = RandomUtil.getIdentifier("TCAttentionHandling"); String tableName = AbstractSQLGenerator.escapeIdentifier(tableN); @@ -82,12 +80,12 @@ public void init() throws Exception { Statement stmt = con.createStatement(); try { Utils.dropTableIfExists(tableName, stmt); - } - catch (SQLException e) { - } - stmt.executeUpdate("CREATE TABLE " + tableName + " (col1 INT PRIMARY KEY, col2 VARCHAR(" + TEST_STRING.length() + "))"); + } catch (SQLException e) {} + stmt.executeUpdate("CREATE TABLE " + tableName + " (col1 INT PRIMARY KEY, col2 VARCHAR(" + + TEST_STRING.length() + "))"); for (int i = 0; i < NUM_TABLE_ROWS; i++) - stmt.executeUpdate("INSERT INTO " + tableName + " (col1, col2) VALUES (" + i + ", '" + TEST_STRING + "')"); + stmt.executeUpdate( + "INSERT INTO " + tableName + " (col1, col2) VALUES (" + i + ", '" + TEST_STRING + "')"); stmt.close(); con.commit(); con.close(); @@ -99,9 +97,7 @@ public void terminate() throws Exception { Statement stmt = con.createStatement(); try { Utils.dropTableIfExists(tableName, stmt); - } - catch (SQLException e) { - } + } catch (SQLException e) {} stmt.close(); con.close(); } @@ -133,8 +129,9 @@ public void testCancelBeforeExecute() throws Exception { * * Expected: Attention sent and handled gracefully. Subsequent use of connection succeeds. * - * Details: Do a batch update that is longer than one TDS packet (so that we are guaranteed to send at least one packet to the server) where - * the last item in the batch contains an unrecoverable error (misstating the length of a stream value). + * Details: Do a batch update that is longer than one TDS packet (so that we are guaranteed to send at least one + * packet to the server) where the last item in the batch contains an unrecoverable error (misstating the length + * of a stream value). */ @Test public void testErrorInRequest() throws Exception { @@ -151,11 +148,10 @@ public void testErrorInRequest() throws Exception { try { ps.executeBatch(); - } - catch (SQLException e) { + } catch (SQLException e) { assertEquals( - "The stream value is not the specified length. The specified length was " + (TEST_STRING.length() - 1) - + ", the actual length is " + TEST_STRING.length() + ".", + "The stream value is not the specified length. The specified length was " + + (TEST_STRING.length() - 1) + ", the actual length is " + TEST_STRING.length() + ".", e.getMessage(), TestResource.getResource("R_unexpectedException")); } @@ -187,10 +183,11 @@ public void testQueryTimeout() throws Exception { ps.execute(); assertEquals(false, true, TestResource.getResource("R_executionNotTimeout")); - } - catch (SQLException e) { - assertTrue(TestResource.getResource("R_queryTimedOut").equalsIgnoreCase(e.getMessage()), TestResource.getResource("R_unexpectedException")); - assertTrue("The query has timed out.".equalsIgnoreCase(e.getMessage()), TestResource.getResource("R_unexpectedException")); + } catch (SQLException e) { + assertTrue(TestResource.getResource("R_queryTimedOut").equalsIgnoreCase(e.getMessage()), + TestResource.getResource("R_unexpectedException")); + assertTrue("The query has timed out.".equalsIgnoreCase(e.getMessage()), + TestResource.getResource("R_unexpectedException")); } elapsedMillis += System.currentTimeMillis(); if (elapsedMillis >= 3000) { @@ -220,32 +217,33 @@ public void testQueryTimeout() throws Exception { * * Expected: Response terminates before complete. Verify subsequent use of connection succeeds. * - * Details: Test does a large SELECT and expects to get back fewer rows than it asked for after cancelling the ResultSet's associated - * Statement. + * Details: Test does a large SELECT and expects to get back fewer rows than it asked for after cancelling the + * ResultSet's associated Statement. */ @Test public void testCancelLongResponse() throws Exception { - assumeTrue("JDBC42".equals(Utils.getConfiguredProperty("JDBC_Version")), TestResource.getResource("R_incompatJDBC")); + assumeTrue("JDBC42".equals(Utils.getConfiguredProperty("JDBC_Version")), + TestResource.getResource("R_incompatJDBC")); Connection con = DriverManager.getConnection(connectionString); - Statement stmt = con.createStatement(SQLServerResultSet.TYPE_SS_DIRECT_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + Statement stmt = con.createStatement(SQLServerResultSet.TYPE_SS_DIRECT_FORWARD_ONLY, + ResultSet.CONCUR_READ_ONLY); ((SQLServerStatement) stmt).setResponseBuffering("adaptive"); // enable isCloseOnCompletion try { stmt.closeOnCompletion(); - } - catch (Exception e) { + } catch (Exception e) { throw new SQLException(TestResource.getResource("R_unexpectedException") + ": ", e); } - ResultSet rs = stmt.executeQuery("SELECT " + "a.col1, a.col2 FROM " + tableName + " a CROSS JOIN " + tableName + " b"); + ResultSet rs = stmt + .executeQuery("SELECT " + "a.col1, a.col2 FROM " + tableName + " a CROSS JOIN " + tableName + " b"); // Scan the first MIN_TABLE_ROWS rows int numSelectedRows = 0; - while (rs.next() && ++numSelectedRows < MIN_TABLE_ROWS) - ; + while (rs.next() && ++numSelectedRows < MIN_TABLE_ROWS); // Verify that MIN_TABLE_ROWS rows were returned // Wrong number of rows returned in first scan @@ -260,9 +258,9 @@ public void testCancelLongResponse() throws Exception { ++numSelectedRows; assertEquals(false, true, TestResource.getResource("R_expectedExceptionNotThrown")); - } - catch (SQLException e) { - assertEquals(TestResource.getResource("R_queryCancelled"), TestResource.getResource("R_unexpectedException")); + } catch (SQLException e) { + assertEquals(TestResource.getResource("R_queryCancelled"), + TestResource.getResource("R_unexpectedException")); } assertEquals(false, NUM_TABLE_ROWS * NUM_TABLE_ROWS == numSelectedRows, "All rows returned after cancel"); @@ -278,16 +276,16 @@ public void testCancelLongResponse() throws Exception { * * Expected: Response can be cancelled. Connection is still usable. * - * Details: One connection locks part of the table while another connection tries to SELECT everything. The SELECT connection blocks while - * reading the rows from the ResultSet. Cancelling the blocking statement (from another thread) should allow it to finish execution normally, - * up to the row where it was canceled. No cancellation exception is thrown. + * Details: One connection locks part of the table while another connection tries to SELECT everything. The + * SELECT connection blocks while reading the rows from the ResultSet. Cancelling the blocking statement (from + * another thread) should allow it to finish execution normally, up to the row where it was canceled. No + * cancellation exception is thrown. */ class OneShotCancel implements Runnable { private Statement stmt; int timeout; - OneShotCancel(Statement stmt, - int timeout) { + OneShotCancel(Statement stmt, int timeout) { this.stmt = stmt; this.timeout = timeout; } @@ -295,15 +293,13 @@ class OneShotCancel implements Runnable { public void run() { try { Thread.sleep(1000 * timeout); - } - catch (InterruptedException e) { + } catch (InterruptedException e) { log.fine("OneShotCancel sleep interrupted: " + e.getMessage()); return; } try { stmt.cancel(); - } - catch (SQLException e) { + } catch (SQLException e) { log.fine("Statement.cancel threw exception: " + e.getMessage()); } return; @@ -327,7 +323,8 @@ public void testCancelBlockedResponse() throws Exception { conLock = DriverManager.getConnection(connectionString); conLock.setAutoCommit(false); stmtLock = conLock.createStatement(); - stmtLock.executeUpdate("UPDATE " + tableName + " SET col2 = 'New Value!' WHERE col1 = " + (NUM_TABLE_ROWS - MIN_TABLE_ROWS)); + stmtLock.executeUpdate("UPDATE " + tableName + " SET col2 = 'New Value!' WHERE col1 = " + + (NUM_TABLE_ROWS - MIN_TABLE_ROWS)); con = DriverManager.getConnection(connectionString); // In SQL Azure, both ALLOW_SNAPSHOT_ISOLATION and READ_COMMITTED_SNAPSHOT options @@ -368,9 +365,9 @@ public void testCancelBlockedResponse() throws Exception { log.fine("numSelectedRows: " + numSelectedRows); assertEquals(false, true, TestResource.getResource("R_expectedExceptionNotThrown")); - } - catch (SQLException e) { - assertTrue(TestResource.getResource("R_queryCancelled").equalsIgnoreCase(e.getMessage()), TestResource.getResource("R_unexpectedException")); + } catch (SQLException e) { + assertTrue(TestResource.getResource("R_queryCancelled").equalsIgnoreCase(e.getMessage()), + TestResource.getResource("R_unexpectedException")); } elapsedMillis += System.currentTimeMillis(); @@ -379,7 +376,8 @@ public void testCancelBlockedResponse() throws Exception { // Note that we may actually get fewer rows than the number of rows before the blocked row // if SQL Server is a little slow in returning rows to us. if (numSelectedRows >= NUM_TABLE_ROWS - MIN_TABLE_ROWS) { - assertEquals(NUM_TABLE_ROWS - MIN_TABLE_ROWS, numSelectedRows, TestResource.getResource("R_valueNotMatch")); + assertEquals(NUM_TABLE_ROWS - MIN_TABLE_ROWS, numSelectedRows, + TestResource.getResource("R_valueNotMatch")); } // If we were able to iterate through all of the expected @@ -394,34 +392,24 @@ public void testCancelBlockedResponse() throws Exception { // Verify the statement & connection are still usable after cancelling rs = stmt.executeQuery("SELECT 1"); - while (rs.next()) - ; - } - finally { + while (rs.next()); + } finally { if (null != rs) try { rs.close(); - } - catch (SQLException e) { - } + } catch (SQLException e) {} if (null != stmt) try { stmt.close(); - } - catch (SQLException e) { - } + } catch (SQLException e) {} if (null != con) try { con.close(); - } - catch (SQLException e) { - } + } catch (SQLException e) {} if (null != conLock) try { conLock.close(); - } - catch (SQLException e) { - } + } catch (SQLException e) {} } } @@ -442,7 +430,8 @@ public void testCancelBlockedResponsePS() throws Exception { conLock = DriverManager.getConnection(connectionString); conLock.setAutoCommit(false); stmtLock = conLock.createStatement(); - stmtLock.executeUpdate("UPDATE " + tableName + " SET col2 = 'New Value!' WHERE col1 = " + (NUM_TABLE_ROWS - MIN_TABLE_ROWS)); + stmtLock.executeUpdate("UPDATE " + tableName + " SET col2 = 'New Value!' WHERE col1 = " + + (NUM_TABLE_ROWS - MIN_TABLE_ROWS)); con = DriverManager.getConnection(connectionString); // In SQL Azure, both ALLOW_SNAPSHOT_ISOLATION and READ_COMMITTED_SNAPSHOT options @@ -463,7 +452,8 @@ public void testCancelBlockedResponsePS() throws Exception { // // Need to use adaptive response buffering when executing the statement. // Otherwise, we would block in executeQuery()... - stmt = con.prepareStatement("SELECT * FROM " + tableName, SQLServerResultSet.TYPE_SS_DIRECT_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + stmt = con.prepareStatement("SELECT * FROM " + tableName, + SQLServerResultSet.TYPE_SS_DIRECT_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); ((SQLServerStatement) stmt).setResponseBuffering("adaptive"); rs = stmt.executeQuery(); @@ -481,9 +471,9 @@ public void testCancelBlockedResponsePS() throws Exception { ++numSelectedRows; assertEquals(false, true, TestResource.getResource("R_expectedExceptionNotThrown")); - } - catch (SQLException e) { - assertTrue(TestResource.getResource("R_queryCancelled").contains(e.getMessage()), TestResource.getResource("R_unexpectedException")); + } catch (SQLException e) { + assertTrue(TestResource.getResource("R_queryCancelled").contains(e.getMessage()), + TestResource.getResource("R_unexpectedException")); } elapsedMillis += System.currentTimeMillis(); @@ -492,7 +482,8 @@ public void testCancelBlockedResponsePS() throws Exception { // Note that we may actually get fewer rows than the number of rows before the blocked row // if SQL Server is a little slow in returning rows to us. if (numSelectedRows >= NUM_TABLE_ROWS - MIN_TABLE_ROWS) { - assertEquals(NUM_TABLE_ROWS - MIN_TABLE_ROWS, numSelectedRows, TestResource.getResource("R_valueNotMatch")); + assertEquals(NUM_TABLE_ROWS - MIN_TABLE_ROWS, numSelectedRows, + TestResource.getResource("R_valueNotMatch")); } // If we were able to iterate through all of the expected @@ -509,39 +500,31 @@ public void testCancelBlockedResponsePS() throws Exception { rs = stmt.executeQuery(); rs.next(); stmt.cancel(); - } - finally { + } finally { if (null != rs) try { rs.close(); - } - catch (SQLException e) { - } + } catch (SQLException e) {} if (null != stmt) try { stmt.close(); - } - catch (SQLException e) { - } + } catch (SQLException e) {} if (null != con) try { con.close(); - } - catch (SQLException e) { - } + } catch (SQLException e) {} if (null != conLock) try { conLock.close(); - } - catch (SQLException e) { - } + } catch (SQLException e) {} } } /** * Same as testCancelBlockedResponse, but with a server cursor. * - * Expected: Statement cancel should cancel blocked server fetch in rs.next() call and connection should remain usable. + * Expected: Statement cancel should cancel blocked server fetch in rs.next() call and connection should remain + * usable. */ @Test public void testCancelBlockedCursoredResponse() throws Exception { @@ -559,7 +542,8 @@ public void testCancelBlockedCursoredResponse() throws Exception { conLock = DriverManager.getConnection(connectionString); conLock.setAutoCommit(false); stmtLock = conLock.createStatement(); - stmtLock.executeUpdate("UPDATE " + tableName + " SET col2 = 'New Value!' WHERE col1 = " + (NUM_TABLE_ROWS - MIN_TABLE_ROWS)); + stmtLock.executeUpdate("UPDATE " + tableName + " SET col2 = 'New Value!' WHERE col1 = " + + (NUM_TABLE_ROWS - MIN_TABLE_ROWS)); con = DriverManager.getConnection(connectionString); // In SQL Azure, both ALLOW_SNAPSHOT_ISOLATION and READ_COMMITTED_SNAPSHOT options @@ -574,8 +558,8 @@ public void testCancelBlockedCursoredResponse() throws Exception { con.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ); } - stmt = con.prepareStatement("SELECT * FROM " + tableName, SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY, - ResultSet.CONCUR_READ_ONLY); + stmt = con.prepareStatement("SELECT * FROM " + tableName, + SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); // Start up a thread to cancel the following SELECT after 3 seconds of blocking. oneShotCancel = new Thread(new OneShotCancel(stmt, 3)); @@ -601,9 +585,9 @@ public void testCancelBlockedCursoredResponse() throws Exception { ++numSelectedRows; assertEquals(false, true, TestResource.getResource("R_expectedExceptionNotThrown")); - } - catch (SQLException e) { - assertTrue(TestResource.getResource("R_queryCancelled").contains(e.getMessage()), TestResource.getResource("R_unexpectedException")); + } catch (SQLException e) { + assertTrue(TestResource.getResource("R_queryCancelled").contains(e.getMessage()), + TestResource.getResource("R_unexpectedException")); } elapsedMillis += System.currentTimeMillis(); @@ -619,20 +603,15 @@ public void testCancelBlockedCursoredResponse() throws Exception { // then something went wrong. assertEquals(true, (numSelectedRows <= NUM_TABLE_ROWS - MIN_TABLE_ROWS), TestResource.getResource("R_valueNotMatch")); - } - finally { + } finally { if (null != con) try { con.close(); - } - catch (SQLException e) { - } + } catch (SQLException e) {} if (null != conLock) try { conLock.close(); - } - catch (SQLException e) { - } + } catch (SQLException e) {} } } @@ -671,8 +650,8 @@ public void testCancelAfterResponse() throws Exception { } /** - * Test various scenarios for cancelling CallableStatement execution between first availability of the results and handling of the last OUT - * parameter + * Test various scenarios for cancelling CallableStatement execution between first availability of the results + * and handling of the last OUT parameter */ @Test public void testCancelGetOutParams() throws Exception { @@ -685,13 +664,10 @@ public void testCancelGetOutParams() throws Exception { try { Utils.dropProcedureIfExists(procName, stmt); - } - catch (Exception ex) { - } - ; - stmt.executeUpdate( - "CREATE PROCEDURE " + procName + " @arg1 CHAR(512) OUTPUT, " + " @arg2 CHAR(512) OUTPUT, " + " @arg3 CHAR(512) OUTPUT " - + "AS " + "BEGIN " + " SET @arg1='hi' " + " SET @arg2='there' " + " SET @arg3='!' " + "END"); + } catch (Exception ex) {} ; + stmt.executeUpdate("CREATE PROCEDURE " + procName + " @arg1 CHAR(512) OUTPUT, " + + " @arg2 CHAR(512) OUTPUT, " + " @arg3 CHAR(512) OUTPUT " + "AS " + "BEGIN " + + " SET @arg1='hi' " + " SET @arg2='there' " + " SET @arg3='!' " + "END"); CallableStatement cstmt = con.prepareCall("{call " + procName + "(?, ?, ?)}"); ((SQLServerStatement) cstmt).setResponseBuffering("adaptive"); cstmt.registerOutParameter(1, Types.CHAR); @@ -728,17 +704,20 @@ public void testCancelGetOutParams() throws Exception { static final int RUN_TIME_MILLIS = 10000; /** - * Test that tries to flush out cancellation synchronization issues by repeatedly executing and cancelling statements on multiple threads. + * Test that tries to flush out cancellation synchronization issues by repeatedly executing and cancelling + * statements on multiple threads. * - * Typical expected failures would be liveness issues (which would manifest as a test being non-responsive), incorrect results, or TDS corruption problems. + * Typical expected failures would be liveness issues (which would manifest as a test being non-responsive), + * incorrect results, or TDS corruption problems. * - * A set of thread pairs runs for 10 seconds. Each pair has one thread repeatedly executing a SELECT statement and one thread repeatedly - * cancelling execution of that statement. Nothing is done to validate whether any particular call to cancel had any affect on the statement. - * Liveness issues typically would manifest as a no response in this test. + * A set of thread pairs runs for 10 seconds. Each pair has one thread repeatedly executing a SELECT statement + * and one thread repeatedly cancelling execution of that statement. Nothing is done to validate whether any + * particular call to cancel had any affect on the statement. Liveness issues typically would manifest as a no + * response in this test. * - * In order to maximize the likelihood of this test finding bugs, it should run on a multi-proc machine with the -server flag specified to the - * JVM. Also, the debugging println statements are commented out deliberately to minimize the impact to the test from the diagnostics, which - * may artificially synchronize execution. + * In order to maximize the likelihood of this test finding bugs, it should run on a multi-proc machine with the + * -server flag specified to the JVM. Also, the debugging println statements are commented out deliberately to + * minimize the impact to the test from the diagnostics, which may artificially synchronize execution. */ @Test public void testHammerCancel() throws Exception { @@ -762,9 +741,7 @@ class Hammer { final ScheduledExecutorService cancelScheduler = Executors.newSingleThreadScheduledExecutor(); - Hammer(int id, - int startDelay, - int maxCancels) { + Hammer(int id, int startDelay, int maxCancels) { this.id = id; this.startDelay = startDelay; this.cancelInterval = RUN_TIME_MILLIS / maxCancels; @@ -774,8 +751,7 @@ void start(final Connection con) { try { newStmt = con.createStatement(); - } - catch (SQLException e) { + } catch (SQLException e) { fail(id + " " + e.getMessage()); } @@ -790,14 +766,12 @@ public void run() { while (rs.next()) ++numExecuteSuccesses; - } - catch (SQLException e) { + } catch (SQLException e) { // "Statement cancelled" (SQLState "HY008") exceptions // are to be expected, of course... if (e.getSQLState().equals("HY008")) { ++numCancellations; - } - else { + } else { log.fine(id + ": execute/next threw: " + e.getSQLState() + " " + e.getMessage()); ++numExecuteExceptions; } @@ -812,18 +786,18 @@ public void run() { log.fine(id + " cancelling " + numCancelTries); stmt.cancel(); ++numCancelSuccesses; - } - catch (SQLException e) { + } catch (SQLException e) { ++numCancelExceptions; log.fine(id + ": cancel threw: " + e.getMessage()); } } }; - final ScheduledFuture runnerHandle = executionScheduler.scheduleAtFixedRate(runner, startDelay, 1, TimeUnit.MILLISECONDS); + final ScheduledFuture runnerHandle = executionScheduler.scheduleAtFixedRate(runner, startDelay, + 1, TimeUnit.MILLISECONDS); - final ScheduledFuture cancelHandle = cancelScheduler.scheduleAtFixedRate(canceller, cancelInterval, cancelInterval, - TimeUnit.MILLISECONDS); + final ScheduledFuture cancelHandle = cancelScheduler.scheduleAtFixedRate(canceller, + cancelInterval, cancelInterval, TimeUnit.MILLISECONDS); } void stop() { @@ -834,25 +808,24 @@ void stop() { while (!cancelScheduler.isTerminated()) { try { cancelScheduler.awaitTermination(5, TimeUnit.SECONDS); - } - catch (InterruptedException e) { - log.fine(id + " ignoring interrupted exception while waiting for shutdown: " + e.getMessage()); + } catch (InterruptedException e) { + log.fine(id + " ignoring interrupted exception while waiting for shutdown: " + + e.getMessage()); } } while (!executionScheduler.isTerminated()) { try { executionScheduler.awaitTermination(5, TimeUnit.SECONDS); - } - catch (InterruptedException e) { - log.fine(id + " ignoring interrupted exception while waiting for shutdown: " + e.getMessage()); + } catch (InterruptedException e) { + log.fine(id + " ignoring interrupted exception while waiting for shutdown: " + + e.getMessage()); } } try { newStmt.close(); - } - catch (SQLException e) { + } catch (SQLException e) { log.fine(id + ": close threw: " + e.getMessage()); ++numCloseExceptions; } @@ -921,8 +894,7 @@ public void testIsCloseOnCompletion() throws Exception { boolean result = false; try { result = ps.isCloseOnCompletion(); - } - catch (Exception e) { + } catch (Exception e) { throw new SQLException(TestResource.getResource("R_unexpectedException") + ": ", e); @@ -943,8 +915,7 @@ public void testCloseOnCompletion() throws Exception { // enable isCloseOnCompletion try { ps.closeOnCompletion(); - } - catch (Exception e) { + } catch (Exception e) { throw new SQLException(TestResource.getResource("R_unexpectedException") + ": ", e); } @@ -953,8 +924,7 @@ public void testCloseOnCompletion() throws Exception { try { rs = ps.executeQuery(); rs.close(); - } - catch (SQLException e) { + } catch (SQLException e) { log.fine("testIsCloseOnCompletion threw: " + e.getMessage()); } @@ -986,14 +956,14 @@ public void testIsCloseOnCompletion() throws Exception { // enable isCloseOnCompletion try { stmt.closeOnCompletion(); - } - catch (Exception e) { + } catch (Exception e) { throw new SQLException(TestResource.getResource("R_unexpectedException") + ": ", e); } - assertEquals(true, stmt.isCloseOnCompletion(), "isCloseOnCompletion " + TestResource.getResource("R_shouldBeEnabled")); + assertEquals(true, stmt.isCloseOnCompletion(), + "isCloseOnCompletion " + TestResource.getResource("R_shouldBeEnabled")); stmt.close(); con.close(); @@ -1010,8 +980,7 @@ public void testCloseOnCompletion() throws Exception { // enable isCloseOnCompletion try { stmt.closeOnCompletion(); - } - catch (Exception e) { + } catch (Exception e) { throw new SQLException(TestResource.getResource("R_unexpectedException") + ": ", e); @@ -1044,21 +1013,16 @@ public void testConsecutiveQueries() throws Exception { try { stmt.closeOnCompletion(); - } - catch (Exception e) { + } catch (Exception e) { throw new SQLException(TestResource.getResource("R_unexpectedException") + ": ", e); } try { Utils.dropTableIfExists(table1Name, stmt); - } - catch (SQLException e) { - } + } catch (SQLException e) {} try { Utils.dropTableIfExists(table2Name, stmt); - } - catch (SQLException e) { - } + } catch (SQLException e) {} stmt.executeUpdate("CREATE TABLE " + table1Name + " (col1 INT PRIMARY KEY)"); stmt.executeUpdate("CREATE TABLE " + table2Name + " (col1 INT PRIMARY KEY)"); @@ -1067,8 +1031,7 @@ public void testConsecutiveQueries() throws Exception { try { ResultSet rs2 = stmt.executeQuery("SELECT * FROM " + table2Name); - } - catch (Exception e) { + } catch (Exception e) { assertEquals(stmt.isClosed(), true, TestResource.getResource("R_statementShouldBeClosed")); } @@ -1076,13 +1039,15 @@ public void testConsecutiveQueries() throws Exception { } /** - * TestJDBCVersion.value < 42 getLargeMaxRows / setLargeMaxRows should throw exception for version before sqljdbc42 + * TestJDBCVersion.value < 42 getLargeMaxRows / setLargeMaxRows should throw exception for version before + * sqljdbc42 * * @throws Exception */ @Test public void testLargeMaxRowsJDBC41() throws Exception { - assumeTrue("JDBC41".equals(Utils.getConfiguredProperty("JDBC_Version")), TestResource.getResource("R_incompatJDBC")); + assumeTrue("JDBC41".equals(Utils.getConfiguredProperty("JDBC_Version")), + TestResource.getResource("R_incompatJDBC")); Connection con = DriverManager.getConnection(connectionString); SQLServerStatement stmt = (SQLServerStatement) con.createStatement(); @@ -1092,8 +1057,7 @@ public void testLargeMaxRowsJDBC41() throws Exception { stmt.getLargeMaxRows(); throw new SQLException(TestResource.getResource("R_unexpectedException")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.getMessage()); } @@ -1101,8 +1065,7 @@ public void testLargeMaxRowsJDBC41() throws Exception { try { stmt.setLargeMaxRows(2015); throw new SQLException(TestResource.getResource("R_unexpectedException")); - } - catch (Exception e) { + } catch (Exception e) { fail(e.getMessage()); } @@ -1121,7 +1084,8 @@ public void testLargeMaxRowsJDBC41() throws Exception { */ @Test public void testLargeMaxRowsJDBC42() throws Exception { - assumeTrue("JDBC42".equals(Utils.getConfiguredProperty("JDBC_Version")), TestResource.getResource("R_incompatJDBC")); + assumeTrue("JDBC42".equals(Utils.getConfiguredProperty("JDBC_Version")), + TestResource.getResource("R_incompatJDBC")); Connection dbcon = DriverManager.getConnection(connectionString); Statement dbstmt = dbcon.createStatement(); @@ -1142,8 +1106,7 @@ public void testLargeMaxRowsJDBC42() throws Exception { newValue = (long) Integer.MAX_VALUE + 1; dbstmt.setLargeMaxRows(newValue); throw new SQLException("setLargeMaxRows(): Long values should not be set"); - } - catch (Exception e) { + } catch (Exception e) { assertEquals( ("calling setLargeMaxRows failed : java.lang.UnsupportedOperationException: " + "The supported maximum row count for a result set is Integer.MAX_VALUE or less."), @@ -1154,8 +1117,7 @@ public void testLargeMaxRowsJDBC42() throws Exception { try { dbstmt.setLargeMaxRows(-2012L); throw new SQLException("setLargeMaxRows(): Negative value not allowed"); - } - catch (Exception e) { + } catch (Exception e) { assertEquals( "calling setLargeMaxRows failed : com.microsoft.sqlserver.jdbc.SQLServerException: " + "The maximum row count -2,012 for a result set must be non-negative.", @@ -1172,13 +1134,12 @@ public void testLargeMaxRowsJDBC42() throws Exception { @AfterEach public void terminate() throws Exception { - try (Connection con = DriverManager.getConnection(connectionString); Statement stmt = con.createStatement();) { + try (Connection con = DriverManager.getConnection(connectionString); + Statement stmt = con.createStatement();) { try { Utils.dropTableIfExists(table1Name, stmt); Utils.dropTableIfExists(table2Name, stmt); - } - catch (SQLException e) { - } + } catch (SQLException e) {} } } } @@ -1200,23 +1161,27 @@ public void testJdbc41CallableStatementMethods() throws Exception { try (Connection conn = DriverManager.getConnection(connectionString); Statement stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE)) { - String query = "create procedure " + procName + " @col1Value varchar(512) OUTPUT," + " @col2Value int OUTPUT," - + " @col3Value float OUTPUT," + " @col4Value decimal(10,5) OUTPUT," + " @col5Value uniqueidentifier OUTPUT," - + " @col6Value xml OUTPUT," + " @col7Value varbinary(max) OUTPUT," + " @col8Value text OUTPUT," + " @col9Value ntext OUTPUT," - + " @col10Value varbinary(max) OUTPUT," + " @col11Value date OUTPUT," + " @col12Value time OUTPUT," - + " @col13Value datetime2 OUTPUT," + " @col14Value datetimeoffset OUTPUT," + " @col15Value decimal(10,10) OUTPUT," + " @col16Value decimal(38,38) OUTPUT" - + " AS BEGIN " + " SET @col1Value = 'hello'" + String query = "create procedure " + procName + " @col1Value varchar(512) OUTPUT," + + " @col2Value int OUTPUT," + " @col3Value float OUTPUT," + " @col4Value decimal(10,5) OUTPUT," + + " @col5Value uniqueidentifier OUTPUT," + " @col6Value xml OUTPUT," + + " @col7Value varbinary(max) OUTPUT," + " @col8Value text OUTPUT," + + " @col9Value ntext OUTPUT," + " @col10Value varbinary(max) OUTPUT," + + " @col11Value date OUTPUT," + " @col12Value time OUTPUT," + " @col13Value datetime2 OUTPUT," + + " @col14Value datetimeoffset OUTPUT," + " @col15Value decimal(10,10) OUTPUT," + + " @col16Value decimal(38,38) OUTPUT" + " AS BEGIN " + " SET @col1Value = 'hello'" + " SET @col2Value = 1" + " SET @col3Value = 2.0" + " SET @col4Value = 123.45" + " SET @col5Value = '6F9619FF-8B86-D011-B42D-00C04FC964FF'" + " SET @col6Value = ''" - + " SET @col7Value = 0x63C34D6BCAD555EB64BF7E848D02C376" + " SET @col8Value = 'text'" + " SET @col9Value = 'ntext'" - + " SET @col10Value = 0x63C34D6BCAD555EB64BF7E848D02C376" + " SET @col11Value = '2017-05-19'" - + " SET @col12Value = '10:47:15.1234567'" + " SET @col13Value = '2017-05-19T10:47:15.1234567'" + + " SET @col7Value = 0x63C34D6BCAD555EB64BF7E848D02C376" + " SET @col8Value = 'text'" + + " SET @col9Value = 'ntext'" + " SET @col10Value = 0x63C34D6BCAD555EB64BF7E848D02C376" + + " SET @col11Value = '2017-05-19'" + " SET @col12Value = '10:47:15.1234567'" + + " SET @col13Value = '2017-05-19T10:47:15.1234567'" + " SET @col14Value = '2017-05-19T10:47:15.1234567+02:00'" + " SET @col15Value = 0.123456789" + " SET @col16Value = 0.1234567890123456789012345678901234567" + " END"; stmt.execute(query); // Test JDBC 4.1 methods for CallableStatement - try (CallableStatement cstmt = conn.prepareCall("{call " + procName + "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)}")) { + try (CallableStatement cstmt = conn + .prepareCall("{call " + procName + "(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)}")) { cstmt.registerOutParameter(1, java.sql.Types.VARCHAR); cstmt.registerOutParameter(2, java.sql.Types.INTEGER); cstmt.registerOutParameter(3, java.sql.Types.FLOAT); @@ -1250,25 +1215,27 @@ public void testJdbc41CallableStatementMethods() throws Exception { assertEquals(0, cstmt.getObject(4, BigDecimal.class).compareTo(new BigDecimal("123.45"))); assertEquals(0, cstmt.getObject("col4Value", BigDecimal.class).compareTo(new BigDecimal("123.45"))); - assertEquals(UUID.fromString("6F9619FF-8B86-D011-B42D-00C04FC964FF"), cstmt.getObject(5, UUID.class)); - assertEquals(UUID.fromString("6F9619FF-8B86-D011-B42D-00C04FC964FF"), cstmt.getObject("col5Value", UUID.class)); + assertEquals(UUID.fromString("6F9619FF-8B86-D011-B42D-00C04FC964FF"), + cstmt.getObject(5, UUID.class)); + assertEquals(UUID.fromString("6F9619FF-8B86-D011-B42D-00C04FC964FF"), + cstmt.getObject("col5Value", UUID.class)); SQLXML sqlXml; sqlXml = cstmt.getObject(6, SQLXML.class); try { assertEquals("", sqlXml.getString()); - } - finally { + } finally { sqlXml.free(); } Blob blob; blob = cstmt.getObject(7, Blob.class); try { - assertArrayEquals(new byte[] {0x63, (byte) 0xC3, 0x4D, 0x6B, (byte) 0xCA, (byte) 0xD5, 0x55, (byte) 0xEB, 0x64, (byte) 0xBF, - 0x7E, (byte) 0x84, (byte) 0x8D, 0x02, (byte) 0xC3, 0x76}, blob.getBytes(1, 16)); - } - finally { + assertArrayEquals( + new byte[] {0x63, (byte) 0xC3, 0x4D, 0x6B, (byte) 0xCA, (byte) 0xD5, 0x55, (byte) 0xEB, + 0x64, (byte) 0xBF, 0x7E, (byte) 0x84, (byte) 0x8D, 0x02, (byte) 0xC3, 0x76}, + blob.getBytes(1, 16)); + } finally { blob.free(); } @@ -1276,8 +1243,7 @@ public void testJdbc41CallableStatementMethods() throws Exception { clob = cstmt.getObject(8, Clob.class); try { assertEquals("text", clob.getSubString(1, 4)); - } - finally { + } finally { clob.free(); } @@ -1285,43 +1251,52 @@ public void testJdbc41CallableStatementMethods() throws Exception { nclob = cstmt.getObject(9, NClob.class); try { assertEquals("ntext", nclob.getSubString(1, 5)); - } - finally { + } finally { nclob.free(); } - assertArrayEquals(new byte[] {0x63, (byte) 0xC3, 0x4D, 0x6B, (byte) 0xCA, (byte) 0xD5, 0x55, (byte) 0xEB, 0x64, (byte) 0xBF, 0x7E, - (byte) 0x84, (byte) 0x8D, 0x02, (byte) 0xC3, 0x76}, cstmt.getObject(10, byte[].class)); + assertArrayEquals( + new byte[] {0x63, (byte) 0xC3, 0x4D, 0x6B, (byte) 0xCA, (byte) 0xD5, 0x55, (byte) 0xEB, + 0x64, (byte) 0xBF, 0x7E, (byte) 0x84, (byte) 0x8D, 0x02, (byte) 0xC3, 0x76}, + cstmt.getObject(10, byte[].class)); assertEquals(java.sql.Date.valueOf("2017-05-19"), cstmt.getObject(11, java.sql.Date.class)); - assertEquals(java.sql.Date.valueOf("2017-05-19"), cstmt.getObject("col11Value", java.sql.Date.class)); + assertEquals(java.sql.Date.valueOf("2017-05-19"), + cstmt.getObject("col11Value", java.sql.Date.class)); java.sql.Time expectedTime = new java.sql.Time(java.sql.Time.valueOf("10:47:15").getTime() + 123L); assertEquals(expectedTime, cstmt.getObject(12, java.sql.Time.class)); assertEquals(expectedTime, cstmt.getObject("col12Value", java.sql.Time.class)); - assertEquals(java.sql.Timestamp.valueOf("2017-05-19 10:47:15.1234567"), cstmt.getObject(13, java.sql.Timestamp.class)); - assertEquals(java.sql.Timestamp.valueOf("2017-05-19 10:47:15.1234567"), cstmt.getObject("col13Value", java.sql.Timestamp.class)); + assertEquals(java.sql.Timestamp.valueOf("2017-05-19 10:47:15.1234567"), + cstmt.getObject(13, java.sql.Timestamp.class)); + assertEquals(java.sql.Timestamp.valueOf("2017-05-19 10:47:15.1234567"), + cstmt.getObject("col13Value", java.sql.Timestamp.class)); + + assertEquals("2017-05-19 10:47:15.1234567 +02:00", + cstmt.getObject(14, microsoft.sql.DateTimeOffset.class).toString()); + assertEquals("2017-05-19 10:47:15.1234567 +02:00", + cstmt.getObject("col14Value", microsoft.sql.DateTimeOffset.class).toString()); - assertEquals("2017-05-19 10:47:15.1234567 +02:00", cstmt.getObject(14, microsoft.sql.DateTimeOffset.class).toString()); - assertEquals("2017-05-19 10:47:15.1234567 +02:00", cstmt.getObject("col14Value", microsoft.sql.DateTimeOffset.class).toString()); - - // BigDecimal#equals considers the number of decimal places (OutParams always return 4 decimal digits rounded up) + // BigDecimal#equals considers the number of decimal places (OutParams always return 4 decimal + // digits rounded up) assertEquals(0, cstmt.getObject(15, BigDecimal.class).compareTo(new BigDecimal("0.1235"))); - assertEquals(0, cstmt.getObject("col15Value", BigDecimal.class).compareTo(new BigDecimal("0.1235"))); - + assertEquals(0, + cstmt.getObject("col15Value", BigDecimal.class).compareTo(new BigDecimal("0.1235"))); + assertEquals(0, cstmt.getObject(16, BigDecimal.class).compareTo(new BigDecimal("0.1235"))); - assertEquals(0, cstmt.getObject("col16Value", BigDecimal.class).compareTo(new BigDecimal("0.1235"))); + assertEquals(0, + cstmt.getObject("col16Value", BigDecimal.class).compareTo(new BigDecimal("0.1235"))); } } } @AfterEach public void terminate() throws Exception { - try (Connection con = DriverManager.getConnection(connectionString); Statement stmt = con.createStatement()) { + try (Connection con = DriverManager.getConnection(connectionString); + Statement stmt = con.createStatement()) { try { Utils.dropProcedureIfExists(procName, stmt); - } - catch (SQLException e) { + } catch (SQLException e) { fail(e.toString()); } } @@ -1349,8 +1324,7 @@ public void testStatementOutParamGetsTwice() throws Exception { // enable isCloseOnCompletion try { stmt.closeOnCompletion(); - } - catch (Exception e) { + } catch (Exception e) { log.fine("testStatementOutParamGetsTwice threw: " + e.getMessage()); } @@ -1361,8 +1335,7 @@ public void testStatementOutParamGetsTwice() throws Exception { if (rs != null) { rs.close(); assertEquals(stmt.isClosed(), true, TestResource.getResource("R_statementShouldBeClosed")); - } - else { + } else { assertEquals(stmt.isClosed(), false, TestResource.getResource("R_statementShouldBeOpened")); } CallableStatement cstmt = con.prepareCall("{ ? = CALL " + procNameTemp + " (?,?)}"); @@ -1381,8 +1354,7 @@ public void testStatementOutParamGetsTwice() throws Exception { if (rs != null) { rs.close(); assertEquals(stmt.isClosed(), true, TestResource.getResource("R_statementShouldBeClosed")); - } - else { + } else { assertEquals(stmt.isClosed(), false, TestResource.getResource("R_statementShouldBeOpened")); } } @@ -1453,10 +1425,12 @@ public void testResultSetParams() throws Exception { Connection conn = DriverManager.getConnection(connectionString); Statement stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); - stmt.executeUpdate("create table " + tableName + " (col1 int, col2 text, col3 int identity(1,1) primary key)"); + stmt.executeUpdate( + "create table " + tableName + " (col1 int, col2 text, col3 int identity(1,1) primary key)"); stmt.executeUpdate("Insert into " + tableName + " values(0, 'hello')"); stmt.executeUpdate("Insert into " + tableName + " values(0, 'hi')"); - String query = "create procedure " + procName + " @col1Value int, @col2Value varchar(512) OUTPUT AS BEGIN SELECT * from " + tableName + String query = "create procedure " + procName + + " @col1Value int, @col2Value varchar(512) OUTPUT AS BEGIN SELECT * from " + tableName + " where col1=@col1Value SET @col2Value='hi' END"; stmt.execute(query); @@ -1480,10 +1454,12 @@ public void testResultSetNullParams() throws Exception { Connection conn = DriverManager.getConnection(connectionString); Statement stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); - stmt.executeUpdate("create table " + tableName + " (col1 int, col2 text, col3 int identity(1,1) primary key)"); + stmt.executeUpdate( + "create table " + tableName + " (col1 int, col2 text, col3 int identity(1,1) primary key)"); stmt.executeUpdate("Insert into " + tableName + " values(0, 'hello')"); stmt.executeUpdate("Insert into " + tableName + " values(0, 'hi')"); - String query = "create procedure " + procName + " @col1Value int, @col2Value varchar(512) OUTPUT AS BEGIN SELECT * from " + tableName + String query = "create procedure " + procName + + " @col1Value int, @col2Value varchar(512) OUTPUT AS BEGIN SELECT * from " + tableName + " where col1=@col1Value SET @col2Value='hi' END"; stmt.execute(query); @@ -1491,12 +1467,10 @@ public void testResultSetNullParams() throws Exception { cstmt.setInt(1, 0); try { cstmt.getInt(2); - } - catch (Exception ex) { + } catch (Exception ex) { if (!ex.getMessage().equalsIgnoreCase("The output parameter 2 was not registered for output.")) throw ex; - } - ; + } ; } /** @@ -1514,21 +1488,18 @@ public void testFailedToResumeTransaction() throws Exception { stmt.executeUpdate("Insert into " + tableName + " values(1)"); stmt.executeUpdate("Insert into " + tableName + " values(2)"); stmt.executeUpdate("Insert into " + tableName + " values(3)"); - PreparedStatement ps = conn.prepareStatement("BEGIN TRAN " + "Insert into " + tableName + " values(4) " + "ROLLBACK"); + PreparedStatement ps = conn + .prepareStatement("BEGIN TRAN " + "Insert into " + tableName + " values(4) " + "ROLLBACK"); conn.setAutoCommit(false); PreparedStatement ps2 = conn.prepareStatement("Insert into " + tableName + " values('a')"); try { ps2.execute(); - } - catch (SQLException e) { - } + } catch (SQLException e) {} try { stmt.executeUpdate("Insert into " + tableName + " values(4)"); - } - catch (SQLException ex) { - } + } catch (SQLException ex) {} conn.close(); } @@ -1542,7 +1513,8 @@ public void testResultSetErrors() throws Exception { Connection conn = DriverManager.getConnection(connectionString); Statement stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); - stmt.executeUpdate("create table " + tableName + " (col1 int, col2 text, col3 int identity(1,1) primary key)"); + stmt.executeUpdate( + "create table " + tableName + " (col1 int, col2 text, col3 int identity(1,1) primary key)"); stmt.executeUpdate("Insert into " + tableName + " values(0, 'hello')"); stmt.executeUpdate("Insert into " + tableName + " values(0, 'hi')"); String query = "create procedure " + procName @@ -1555,10 +1527,7 @@ public void testResultSetErrors() throws Exception { try { ResultSet rs = cstmt.executeQuery(); - } - catch (Exception ex) { - } - ; + } catch (Exception ex) {} ; assertEquals(null, cstmt.getString(2), TestResource.getResource("R_valueNotMatch")); } @@ -1580,8 +1549,8 @@ public void testRowError() throws Exception { stmt.executeUpdate("insert into " + tableName + " values(0)"); stmt.executeUpdate("insert into " + tableName + " values(1)"); stmt.executeUpdate("insert into " + tableName + " values(2)"); - stmt.execute("create procedure " + procName + " @col1Value int AS " + " BEGIN " + " SELECT col1 FROM " + tableName - + " WITH (UPDLOCK) WHERE (col1 = @col1Value) " + " END"); + stmt.execute("create procedure " + procName + " @col1Value int AS " + " BEGIN " + " SELECT col1 FROM " + + tableName + " WITH (UPDLOCK) WHERE (col1 = @col1Value) " + " END"); // For the test, lock each row in the table, one by one, for update // on one connection and, on another connection, verify that the @@ -1603,8 +1572,7 @@ public void testRowError() throws Exception { // enable isCloseOnCompletion try { cstmt.closeOnCompletion(); - } - catch (Exception e) { + } catch (Exception e) { throw new SQLException(TestResource.getResource("R_unexpectedException")); } @@ -1638,9 +1606,9 @@ public void testRowError() throws Exception { for (int i = 0; i < 2; i++) { try { rs.next(); - assertEquals(false, true, "lock timeout" + TestResource.getResource("R_expectedExceptionNotThrown")); - } - catch (SQLException e) { + assertEquals(false, true, + "lock timeout" + TestResource.getResource("R_expectedExceptionNotThrown")); + } catch (SQLException e) { assertEquals(1222, // lock timeout e.getErrorCode(), TestResource.getResource("R_unexpectedException") + e.getMessage()); } @@ -1666,12 +1634,12 @@ public void testRowError() throws Exception { @AfterEach public void terminate() throws Exception { - try (Connection con = DriverManager.getConnection(connectionString); Statement stmt = con.createStatement()) { + try (Connection con = DriverManager.getConnection(connectionString); + Statement stmt = con.createStatement()) { try { Utils.dropTableIfExists(tableName, stmt); Utils.dropProcedureIfExists(procName, stmt); - } - catch (SQLException e) { + } catch (SQLException e) { fail(e.toString()); } } @@ -1704,11 +1672,11 @@ private Connection createConnectionAndPopulateData() throws Exception { @AfterEach public void terminate() throws Exception { - try (Connection con = DriverManager.getConnection(connectionString); Statement stmt = con.createStatement()) { + try (Connection con = DriverManager.getConnection(connectionString); + Statement stmt = con.createStatement()) { try { Utils.dropTableIfExists(tableName, stmt); - } - catch (SQLException e) { + } catch (SQLException e) { fail(e.toString()); } } @@ -1741,15 +1709,15 @@ public void testNBCROWNullsForLOBs() throws Exception { assertEquals(value, null, "expected null:" + value); } } - } - finally { + } finally { terminate(); } } /** - * Tests the following a) isSparseColumnSet returns true for column set b) isSparseColumnSet returns false for non column set column + * Tests the following a) isSparseColumnSet returns true for column set b) isSparseColumnSet returns false for + * non column set column * * @throws Exception */ @@ -1778,13 +1746,11 @@ public void testSparseColumnSetValues() throws Exception { if (i == 5) { // this is the only sparse column set assertEquals(isSparseColumnSet, true, "Incorrect value " + isSparseColumnSet); - } - else { + } else { assertEquals(isSparseColumnSet, false, "Incorrect value " + isSparseColumnSet); } } - } - finally { + } finally { terminate(); } } @@ -1815,26 +1781,21 @@ public void testSparseColumnSetIndex() throws Exception { // test that an exception is thrown when invalid index(lower limit) is used rsmd.isSparseColumnSet(0); assertEquals(true, false, "Using index as 0 should have thrown an exception"); - } - catch (ArrayIndexOutOfBoundsException e) { - } + } catch (ArrayIndexOutOfBoundsException e) {} try { // test that an exception is thrown when invalid index(upper limit) is used rsmd.isSparseColumnSet(8); assertEquals(true, false, "Using index as 8 should have thrown an exception"); - } - catch (ArrayIndexOutOfBoundsException e) { - } - } - finally { + } catch (ArrayIndexOutOfBoundsException e) {} + } finally { terminate(); } } /** - * Tests the following for isSparseColumnSet api a) Metadata is available when result set is closed b) Metadata is available when statement - * is closed c) Metadata is available when connection is closed + * Tests the following for isSparseColumnSet api a) Metadata is available when result set is closed b) Metadata + * is available when statement is closed c) Metadata is available when connection is closed * * @throws Exception */ @@ -1890,9 +1851,7 @@ public void testNBCRowForAllNulls() throws Exception { Statement stmt = con.createStatement(); try { Utils.dropTableIfExists(tableName, stmt); - } - catch (SQLException e) { - } + } catch (SQLException e) {} String createTableQuery = "CREATE TABLE " + tableName + "(col1 int PRIMARY KEY IDENTITY(1,1)"; @@ -1912,8 +1871,7 @@ public void testNBCRowForAllNulls() throws Exception { assertEquals(value, null, "expected null:" + value); } - } - finally { + } finally { terminate(); } } @@ -1939,9 +1897,7 @@ public void testNBCROWWithRandomAccess() throws Exception { Statement stmt = con.createStatement(); try { Utils.dropTableIfExists(tableName, stmt); - } - catch (SQLException e) { - } + } catch (SQLException e) {} // construct a query to create a table with 100 columns String createTableQuery = "CREATE TABLE " + tableName + "(col1 int PRIMARY KEY IDENTITY(1,1)"; @@ -1979,8 +1935,7 @@ public void testNBCROWWithRandomAccess() throws Exception { if (i == nonNullColumns.size() - 1) { insertQuery += ")"; values += ")"; - } - else { + } else { insertQuery += ","; values += ","; } @@ -2012,14 +1967,12 @@ public void testNBCROWWithRandomAccess() throws Exception { String value = rs.getString(columnNo);// get a particular column value if (nonNullColumns.contains(columnNo)) { assertTrue(value != null, "value should not be null"); - } - else { + } else { assertTrue(value == null, "value should be null:" + value); } } } - } - finally { + } finally { terminate(); } @@ -2038,15 +1991,13 @@ public void testActiveStatement() throws Exception { // enable isCloseOnCompletion try { stmt.closeOnCompletion(); - } - catch (Exception e) { + } catch (Exception e) { log.fine("testCloseOnCompletion threw: " + e.getMessage()); } try { assertEquals(stmt.isClosed(), false, "Wrong return value from Statement.isClosed"); - } - catch (UnsupportedOperationException e) { + } catch (UnsupportedOperationException e) { assertEquals(e.getMessage(), TestResource.getResource("R_unexpectedException"), e.getMessage()); } @@ -2070,8 +2021,7 @@ public void testClosedStatement() throws Exception { try { assertEquals(stmt.isClosed(), true, "Wrong return value from Statement.isClosed"); - } - catch (UnsupportedOperationException e) { + } catch (UnsupportedOperationException e) { assertEquals(e.getMessage(), TestResource.getResource("R_unexpectedException"), e.getMessage()); } @@ -2093,8 +2043,7 @@ public void testClosedConnection() throws Exception { try { assertEquals(stmt.isClosed(), true, "Wrong return value from Statement.isClosed"); - } - catch (UnsupportedOperationException e) { + } catch (UnsupportedOperationException e) { assertEquals(e.getMessage(), TestResource.getResource("R_unexpectedException"), e.getMessage()); } } @@ -2117,8 +2066,7 @@ public void testActiveResultSet() throws Exception { // enable isCloseOnCompletion try { stmt.closeOnCompletion(); - } - catch (Exception e) { + } catch (Exception e) { throw new SQLException(TestResource.getResource("R_unexpectedException")); } @@ -2126,8 +2074,7 @@ public void testActiveResultSet() throws Exception { try { assertEquals(rs.isClosed(), false, "Wrong return value from ResultSet.isClosed"); - } - catch (UnsupportedOperationException e) { + } catch (UnsupportedOperationException e) { assertEquals(e.getMessage(), TestResource.getResource("R_unexpectedException"), e.getMessage()); } @@ -2152,8 +2099,7 @@ public void testClosedResultSet() throws Exception { // enable isCloseOnCompletion try { stmt.closeOnCompletion(); - } - catch (Exception e) { + } catch (Exception e) { throw new SQLException(TestResource.getResource("R_unexpectedException")); } @@ -2162,8 +2108,7 @@ public void testClosedResultSet() throws Exception { try { assertEquals(rs.isClosed(), true, "Wrong return value from ResultSet.isClosed"); - } - catch (UnsupportedOperationException e) { + } catch (UnsupportedOperationException e) { assertEquals(e.getMessage(), TestResource.getResource("R_unexpectedException"), e.getMessage()); } assertEquals(stmt.isClosed(), true, TestResource.getResource("R_statementShouldBeClosed")); @@ -2187,8 +2132,7 @@ public void testClosedStatement() throws Exception { try { assertEquals(rs.isClosed(), true, "Wrong return value from ResultSet.isClosed"); - } - catch (UnsupportedOperationException e) { + } catch (UnsupportedOperationException e) { assertEquals(e.getMessage(), TestResource.getResource("R_unexpectedException"), e.getMessage()); } @@ -2212,8 +2156,7 @@ public void testClosedConnection() throws Exception { try { assertEquals(rs.isClosed(), true, "Wrong return value from ResultSet.isClosed"); - } - catch (UnsupportedOperationException e) { + } catch (UnsupportedOperationException e) { assertEquals(e.getMessage(), TestResource.getResource("R_unexpectedException"), e.getMessage()); } } @@ -2229,22 +2172,23 @@ public class TCUpdateCountWithTriggers { private final String triggerName = "[TCUpdateCountWithTriggersTrigger]"; @BeforeEach - private void setup() throws Exception { + public void setup() throws Exception { Connection con = DriverManager.getConnection(connectionString); con.setAutoCommit(false); Statement stmt = con.createStatement(); try { - stmt.executeUpdate("if EXISTS (SELECT * FROM sys.triggers where name = '" + triggerName + "') drop trigger " + triggerName); - } - catch (SQLException e) { + stmt.executeUpdate("if EXISTS (SELECT * FROM sys.triggers where name = '" + triggerName + + "') drop trigger " + triggerName); + } catch (SQLException e) { throw new SQLException(e); } stmt.executeUpdate("CREATE TABLE " + tableName + " (col1 INT PRIMARY KEY)"); for (int i = 0; i < NUM_ROWS; i++) stmt.executeUpdate("INSERT INTO " + tableName + " (col1) VALUES (" + i + ")"); - stmt.executeUpdate("CREATE TABLE " + table2Name + " (NAME VARCHAR(100), col2 int identity(1,1) primary key)"); + stmt.executeUpdate( + "CREATE TABLE " + table2Name + " (NAME VARCHAR(100), col2 int identity(1,1) primary key)"); stmt.executeUpdate("INSERT INTO " + table2Name + " (NAME) VALUES ('BLAH')"); stmt.executeUpdate("INSERT INTO " + table2Name + " (NAME) VALUES ('FNORD')"); stmt.executeUpdate("INSERT INTO " + table2Name + " (NAME) VALUES ('EEEP')"); @@ -2252,8 +2196,9 @@ private void setup() throws Exception { stmt.executeUpdate("Create Procedure " + sprocName + " AS " + "Begin " + " Update " + table2Name + " SET " + " NAME = 'Update' Where NAME = 'TEST' " + "Return 0 " + "End"); - stmt.executeUpdate("CREATE Trigger " + triggerName + " ON " + tableName + " FOR DELETE AS " + "Begin " + "Declare @l_retstat Integer " - + "Execute @l_retstat = " + sprocName + " " + "If (@l_retstat <> 0) " + "Begin " + " Rollback Transaction " + "End " + "End"); + stmt.executeUpdate("CREATE Trigger " + triggerName + " ON " + tableName + " FOR DELETE AS " + "Begin " + + "Declare @l_retstat Integer " + "Execute @l_retstat = " + sprocName + " " + + "If (@l_retstat <> 0) " + "Begin " + " Rollback Transaction " + "End " + "End"); stmt.close(); con.commit(); @@ -2309,8 +2254,8 @@ public void testLastUpdateCountFalse() throws Exception { public void testPreparedStatementInsertExecInsert() throws Exception { Connection con = DriverManager.getConnection(connectionString + ";lastUpdateCount=true"); - PreparedStatement ps = con.prepareStatement("INSERT INTO " + tableName + " (col1) VALUES (" + (NUM_ROWS + 1) + "); " + "EXEC " + sprocName - + "; " + "UPDATE " + table2Name + " SET NAME = 'FISH'"); + PreparedStatement ps = con.prepareStatement("INSERT INTO " + tableName + " (col1) VALUES (" + (NUM_ROWS + 1) + + "); " + "EXEC " + sprocName + "; " + "UPDATE " + table2Name + " SET NAME = 'FISH'"); int updateCount = ps.executeUpdate(); ps.close(); @@ -2330,8 +2275,9 @@ public void testPreparedStatementInsertExecInsert() throws Exception { public void testStatementInsertExecInsert() throws Exception { Connection con = DriverManager.getConnection(connectionString + ";lastUpdateCount=true"); - int updateCount = con.createStatement().executeUpdate("INSERT INTO " + tableName + " (col1) VALUES (" + (NUM_ROWS + 1) + "); " + "EXEC " - + sprocName + "; " + "UPDATE " + table2Name + " SET NAME = 'FISH'"); + int updateCount = con.createStatement() + .executeUpdate("INSERT INTO " + tableName + " (col1) VALUES (" + (NUM_ROWS + 1) + "); " + "EXEC " + + sprocName + "; " + "UPDATE " + table2Name + " SET NAME = 'FISH'"); con.close(); @@ -2342,13 +2288,13 @@ public void testStatementInsertExecInsert() throws Exception { @AfterEach public void terminate() throws Exception { - try (Connection con = DriverManager.getConnection(connectionString); Statement stmt = con.createStatement();) { + try (Connection con = DriverManager.getConnection(connectionString); + Statement stmt = con.createStatement();) { try { Utils.dropTableIfExists(tableName, stmt); Utils.dropTableIfExists(table2Name, stmt); Utils.dropProcedureIfExists(sprocName, stmt); - } - catch (SQLException e) { + } catch (SQLException e) { fail(e.toString()); } } @@ -2364,37 +2310,35 @@ public class TCUpdateCountAfterRaiseError { private final String errorMessage50001InSqlAzure = "Error 50001, severity 17, state 1 was raised, but no message with that error number was found in sys.messages. If error is larger than 50000, make sure the user-defined message is added using sp_addmessage."; @BeforeEach - private void setup() throws Exception { + public void setup() throws Exception { Connection con = DriverManager.getConnection(connectionString); con.setAutoCommit(false); Statement stmt = con.createStatement(); try { - stmt.executeUpdate("if EXISTS (SELECT * FROM sys.triggers where name = '" + triggerName + "') drop trigger " + triggerName); - } - catch (SQLException e) { + stmt.executeUpdate("if EXISTS (SELECT * FROM sys.triggers where name = '" + triggerName + + "') drop trigger " + triggerName); + } catch (SQLException e) { System.out.println(e.toString()); } stmt.executeUpdate("CREATE TABLE " + tableName + " (col1 INT primary key)"); for (int i = 0; i < NUM_ROWS; i++) stmt.executeUpdate("INSERT INTO " + tableName + " (col1) VALUES (" + i + ")"); - // Skip adding message for 50001 if the target server is SQL Azure, because SQL Azure does not support sp_addmessage. + // Skip adding message for 50001 if the target server is SQL Azure, because SQL Azure does not support + // sp_addmessage. Connection dbConn = DriverManager.getConnection(connectionString); if (DBConnection.isSqlAzure(dbConn)) { log.fine("Because SQL Azure does not support sp_addmessage, 'EXEC sp_addmessage ...' is skipped."); - } - else { + } else { try { stmt.executeUpdate("EXEC sp_addmessage @msgnum=50001, @severity=11, @msgtext='MyError'"); - } - catch (SQLException e) { - } + } catch (SQLException e) {} } dbConn.close(); - stmt.executeUpdate("CREATE TRIGGER " + triggerName + " ON " + tableName + " FOR INSERT AS BEGIN DELETE FROM " + tableName - + " WHERE col1 = 1 RAISERROR(50001, 17, 1) END"); + stmt.executeUpdate("CREATE TRIGGER " + triggerName + " ON " + tableName + + " FOR INSERT AS BEGIN DELETE FROM " + tableName + " WHERE col1 = 1 RAISERROR(50001, 17, 1) END"); stmt.close(); con.commit(); con.close(); @@ -2409,14 +2353,13 @@ private void setup() throws Exception { public void testUpdateCountAfterRaiseError() throws Exception { Connection con = DriverManager.getConnection(connectionString); - PreparedStatement pstmt = con - .prepareStatement("UPDATE " + tableName + " SET col1 = 5 WHERE col1 = 2 RAISERROR(50001, 17, 1) SELECT * FROM " + tableName); + PreparedStatement pstmt = con.prepareStatement("UPDATE " + tableName + + " SET col1 = 5 WHERE col1 = 2 RAISERROR(50001, 17, 1) SELECT * FROM " + tableName); // enable isCloseOnCompletion try { pstmt.closeOnCompletion(); - } - catch (Exception e) { + } catch (Exception e) { throw new SQLException(TestResource.getResource("R_unexpectedException")); } @@ -2428,15 +2371,13 @@ public void testUpdateCountAfterRaiseError() throws Exception { try { result = pstmt.getMoreResults(); assertEquals(true, false, TestResource.getResource("R_expectedExceptionNotThrown")); - } - catch (SQLException e) { + } catch (SQLException e) { String expectedMessage; // SQL Azure does not support sp_addmessage, so the user-defined message cannot be added. - if (DBConnection.isSqlAzure(con)) // SQL Azure + if (DBConnection.isSqlAzure(con)) // SQL Azure { expectedMessage = errorMessage50001InSqlAzure; - } - else // SQL Server + } else // SQL Server { expectedMessage = "MyError"; } @@ -2477,15 +2418,13 @@ public void testUpdateCountAfterErrorInTriggerLastUpdateCountFalse() throws Exce try { result = pstmt.getMoreResults(); assertEquals(true, false, TestResource.getResource("R_expectedExceptionNotThrown")); - } - catch (SQLException e) { + } catch (SQLException e) { String expectedMessage; // SQL Azure does not support sp_addmessage, so the user-defined message cannot be added. - if (DBConnection.isSqlAzure(con)) // SQL Azure + if (DBConnection.isSqlAzure(con)) // SQL Azure { expectedMessage = errorMessage50001InSqlAzure; - } - else // SQL Server + } else // SQL Server { expectedMessage = "MyError"; } @@ -2500,8 +2439,7 @@ public void testUpdateCountAfterErrorInTriggerLastUpdateCountFalse() throws Exce while (rs.next()) ++rowCount; assertEquals(rowCount, NUM_ROWS, "Wrong number of rows in table"); - assertEquals(pstmt.isClosed(), false, - TestResource.getResource("R_statementShouldBeOpened")); + assertEquals(pstmt.isClosed(), false, TestResource.getResource("R_statementShouldBeOpened")); rs.close(); pstmt.close(); @@ -2522,15 +2460,13 @@ public void testUpdateCountAfterErrorInTriggerLastUpdateCountTrue() throws Excep try { pstmt.executeUpdate(); assertEquals(true, false, TestResource.getResource("R_expectedExceptionNotThrown")); - } - catch (SQLException e) { + } catch (SQLException e) { String expectedMessage; // SQL Azure does not support sp_addmessage, so the user-defined message cannot be added. - if (DBConnection.isSqlAzure(con)) // SQL Azure + if (DBConnection.isSqlAzure(con)) // SQL Azure { expectedMessage = errorMessage50001InSqlAzure; - } - else // SQL Server + } else // SQL Server { expectedMessage = "MyError"; } @@ -2555,11 +2491,11 @@ public void testUpdateCountAfterErrorInTriggerLastUpdateCountTrue() throws Excep @AfterEach public void terminate() throws Exception { - try (Connection con = DriverManager.getConnection(connectionString); Statement stmt = con.createStatement();) { + try (Connection con = DriverManager.getConnection(connectionString); + Statement stmt = con.createStatement();) { try { Utils.dropTableIfExists(tableName, stmt); - } - catch (SQLException e) { + } catch (SQLException e) { fail(e.toString()); } } @@ -2574,7 +2510,7 @@ public class TCNocount { private static final int NUM_ROWS = 3; @BeforeEach - private void setup() throws Exception { + public void setup() throws Exception { Connection con = DriverManager.getConnection(connectionString); con.setAutoCommit(false); Statement stmt = con.createStatement(); @@ -2582,8 +2518,7 @@ private void setup() throws Exception { // enable isCloseOnCompletion try { stmt.closeOnCompletion(); - } - catch (Exception e) { + } catch (Exception e) { throw new SQLException(TestResource.getResource("R_unexpectedException"), e); } stmt.executeUpdate("CREATE TABLE " + tableName + " (col1 INT primary key)"); @@ -2607,14 +2542,14 @@ public void testNoCountWithExecute() throws Exception { try (Connection con = DriverManager.getConnection(connectionString + ";lastUpdateCount = true"); Statement stmt = con.createStatement();) { - boolean isResultSet = stmt - .execute("set nocount on\n" + "insert into " + tableName + "(col1) values(" + (NUM_ROWS + 1) + ")\n" + "select 1"); + boolean isResultSet = stmt.execute("set nocount on\n" + "insert into " + tableName + "(col1) values(" + + (NUM_ROWS + 1) + ")\n" + "select 1"); assertEquals(true, isResultSet, "execute() said first result was an update count"); ResultSet rs = stmt.getResultSet(); while (rs.next()); - rs.close(); + rs.close(); boolean moreResults = stmt.getMoreResults(); assertEquals(false, moreResults, "next result is a ResultSet?"); @@ -2626,11 +2561,11 @@ public void testNoCountWithExecute() throws Exception { @AfterEach public void terminate() throws Exception { - try (Connection con = DriverManager.getConnection(connectionString); Statement stmt = con.createStatement()) { + try (Connection con = DriverManager.getConnection(connectionString); + Statement stmt = con.createStatement()) { try { Utils.dropTableIfExists(tableName, stmt); - } - catch (SQLException e) { + } catch (SQLException e) { fail(e.toString()); } } diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/WrapperTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/WrapperTest.java index 8109eb551..e8f44c66f 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/WrapperTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/unit/statement/WrapperTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.jdbc.unit.statement; @@ -28,15 +25,17 @@ import com.microsoft.sqlserver.testframework.AbstractTest; import com.microsoft.sqlserver.testframework.DBConnection; + /** - * Tests isWrapperFor methods + * Tests isWrapperFor methods * */ @RunWith(JUnitPlatform.class) public class WrapperTest extends AbstractTest { /** - * Wrapper tests + * Wrapper tests + * * @throws Exception */ @Test @@ -47,34 +46,43 @@ public void wrapTest() throws Exception { try { // First make sure that a statement can be unwrapped - boolean isWrapper = ((SQLServerStatement) stmt).isWrapperFor(Class.forName("com.microsoft.sqlserver.jdbc.SQLServerStatement")); + boolean isWrapper = ((SQLServerStatement) stmt) + .isWrapperFor(Class.forName("com.microsoft.sqlserver.jdbc.SQLServerStatement")); MessageFormat form = new MessageFormat(TestResource.getResource("R_shouldBeWrapper")); MessageFormat form2 = new MessageFormat(TestResource.getResource("R_shouldNotBeWrapper")); - Object[][] msgArgs = {{"SQLStatement", "self"}, {"SQLServerStatement", "ISQLServerStatement"}, {"SQLServerCallableStatement", "SQLServerStatement"}, {"SQLServerCallableStatement", "SQLServerStatement"}}; + Object[][] msgArgs = {{"SQLStatement", "self"}, {"SQLServerStatement", "ISQLServerStatement"}, + {"SQLServerCallableStatement", "SQLServerStatement"}, + {"SQLServerCallableStatement", "SQLServerStatement"}}; assertEquals(isWrapper, true, form.format(msgArgs[0])); - isWrapper = ((SQLServerStatement) stmt).isWrapperFor(Class.forName("com.microsoft.sqlserver.jdbc.ISQLServerStatement")); + isWrapper = ((SQLServerStatement) stmt) + .isWrapperFor(Class.forName("com.microsoft.sqlserver.jdbc.ISQLServerStatement")); assertEquals(isWrapper, true, form.format(msgArgs[1])); - isWrapper = ((SQLServerStatement) stmt).isWrapperFor(Class.forName("com.microsoft.sqlserver.jdbc.SQLServerConnection")); + isWrapper = ((SQLServerStatement) stmt) + .isWrapperFor(Class.forName("com.microsoft.sqlserver.jdbc.SQLServerConnection")); assertEquals(isWrapper, false, form2.format(msgArgs[1])); // Now make sure that we can unwrap a SQLServerCallableStatement to a SQLServerStatement CallableStatement cs = con.prepareCall("{ ? = CALL " + "ProcName" + " (?, ?, ?, ?) }"); // Test the class first - isWrapper = ((SQLServerCallableStatement) cs).isWrapperFor(Class.forName("com.microsoft.sqlserver.jdbc.SQLServerStatement")); + isWrapper = ((SQLServerCallableStatement) cs) + .isWrapperFor(Class.forName("com.microsoft.sqlserver.jdbc.SQLServerStatement")); assertEquals(isWrapper, true, form.format(msgArgs[2])); - // Now unwrap the Callable to a statement and call a SQLServerStatement specific function and make sure it succeeds. + // Now unwrap the Callable to a statement and call a SQLServerStatement specific function and make sure it + // succeeds. SQLServerStatement stmt2 = (SQLServerStatement) ((SQLServerCallableStatement) cs) .unwrap(Class.forName("com.microsoft.sqlserver.jdbc.SQLServerStatement")); stmt2.setResponseBuffering("adaptive"); // now test the interface - isWrapper = ((SQLServerCallableStatement) cs).isWrapperFor(Class.forName("com.microsoft.sqlserver.jdbc.ISQLServerCallableStatement")); + isWrapper = ((SQLServerCallableStatement) cs) + .isWrapperFor(Class.forName("com.microsoft.sqlserver.jdbc.ISQLServerCallableStatement")); assertEquals(isWrapper, true, form.format(msgArgs[1])); - // Now unwrap the Callable to a statement and call a SQLServerStatement specific function and make sure it succeeds. + // Now unwrap the Callable to a statement and call a SQLServerStatement specific function and make sure it + // succeeds. ISQLServerPreparedStatement stmt4 = (ISQLServerPreparedStatement) ((SQLServerCallableStatement) cs) .unwrap(Class.forName("com.microsoft.sqlserver.jdbc.ISQLServerPreparedStatement")); stmt4.setResponseBuffering("adaptive"); @@ -83,9 +91,11 @@ public void wrapTest() throws Exception { stmt4.setDateTimeOffset(1, null); // Try Unwrapping CallableStatement to a callableStatement - isWrapper = ((SQLServerCallableStatement) cs).isWrapperFor(Class.forName("com.microsoft.sqlserver.jdbc.SQLServerCallableStatement")); + isWrapper = ((SQLServerCallableStatement) cs) + .isWrapperFor(Class.forName("com.microsoft.sqlserver.jdbc.SQLServerCallableStatement")); assertEquals(isWrapper, true, form.format(msgArgs[3])); - // Now unwrap the Callable to a SQLServerCallableStatement and call a SQLServerStatement specific function and make sure it succeeds. + // Now unwrap the Callable to a SQLServerCallableStatement and call a SQLServerStatement specific function + // and make sure it succeeds. SQLServerCallableStatement stmt3 = (SQLServerCallableStatement) ((SQLServerCallableStatement) cs) .unwrap(Class.forName("com.microsoft.sqlserver.jdbc.SQLServerCallableStatement")); stmt3.setResponseBuffering("adaptive"); @@ -99,12 +109,12 @@ public void wrapTest() throws Exception { cs.close(); } - } - catch (UnsupportedOperationException e) { - assertEquals(System.getProperty("java.specification.version"), "1.5", "isWrapperFor " + TestResource.getResource("R_shouldBeSupported")); - assertTrue(e.getMessage().equalsIgnoreCase("This operation is not supported."), TestResource.getResource("R_unexpectedExceptionContent")); - } - finally { + } catch (UnsupportedOperationException e) { + assertEquals(System.getProperty("java.specification.version"), "1.5", + "isWrapperFor " + TestResource.getResource("R_shouldBeSupported")); + assertTrue(e.getMessage().equalsIgnoreCase("This operation is not supported."), + TestResource.getResource("R_unexpectedExceptionContent")); + } finally { if (null != stmt) { stmt.close(); } @@ -117,6 +127,7 @@ public void wrapTest() throws Exception { /** * Tests expected unwrapper failures + * * @throws Exception */ @Test @@ -132,17 +143,16 @@ public void unWrapFailureTest() throws Exception { assertEquals(isWrapper, false, "SQLServerStatement should not be a wrapper for string"); stmt.unwrap(Class.forName(str)); assertTrue(false, TestResource.getResource("R_exceptionNotThrown")); - } - catch (SQLException ex) { + } catch (SQLException ex) { Throwable t = ex.getCause(); Class exceptionClass = Class.forName("java.lang.ClassCastException"); assertEquals(t.getClass(), exceptionClass, "The cause in the exception class does not match"); - } - catch (UnsupportedOperationException e) { - assertEquals(System.getProperty("java.specification.version"), "1.5", "isWrapperFor " + TestResource.getResource("R_shouldBeSupported")); - assertEquals(e.getMessage(), "This operation is not supported.", TestResource.getResource("R_unexpectedExceptionContent")); - } - finally { + } catch (UnsupportedOperationException e) { + assertEquals(System.getProperty("java.specification.version"), "1.5", + "isWrapperFor " + TestResource.getResource("R_shouldBeSupported")); + assertEquals(e.getMessage(), "This operation is not supported.", + TestResource.getResource("R_unexpectedExceptionContent")); + } finally { if (null != stmt) { stmt.close(); } diff --git a/src/test/java/com/microsoft/sqlserver/testframework/AbstractParentWrapper.java b/src/test/java/com/microsoft/sqlserver/testframework/AbstractParentWrapper.java index 35967c574..de22f6c48 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/AbstractParentWrapper.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/AbstractParentWrapper.java @@ -1,40 +1,36 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework; - -/** - * Stores the parent class. For connection parent is null; for Statement, Connection is parent; for ResultSet, Statement is parent - */ -public abstract class AbstractParentWrapper { - static final int ENGINE_EDITION_FOR_SQL_AZURE = 5; - - AbstractParentWrapper parent = null; - Object internal = null; - String name = null; - - AbstractParentWrapper(AbstractParentWrapper parent, - Object internal, - String name) { - this.parent = parent; - this.internal = internal; - this.name = name; - } - - void setInternal(Object internal) { - this.internal = internal; - } - - public Object product() { - return internal; - } - - public AbstractParentWrapper parent() { - return parent; - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework; + +/** + * Stores the parent class. For connection parent is null; for Statement, Connection is parent; for ResultSet, Statement + * is parent + */ +public abstract class AbstractParentWrapper { + static final int ENGINE_EDITION_FOR_SQL_AZURE = 5; + + AbstractParentWrapper parent = null; + Object internal = null; + String name = null; + + AbstractParentWrapper(AbstractParentWrapper parent, Object internal, String name) { + this.parent = parent; + this.internal = internal; + this.name = name; + } + + void setInternal(Object internal) { + this.internal = internal; + } + + public Object product() { + return internal; + } + + public AbstractParentWrapper parent() { + return parent; + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/AbstractSQLGenerator.java b/src/test/java/com/microsoft/sqlserver/testframework/AbstractSQLGenerator.java index e10ad94e0..8a771953d 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/AbstractSQLGenerator.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/AbstractSQLGenerator.java @@ -1,91 +1,87 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework; - -/** - * Common methods needed for any implementation for {@link SQLGeneratorIF} - */ -public abstract class AbstractSQLGenerator {// implements ISQLGenerator { - - protected static final String CREATE_TABLE = "CREATE TABLE"; - protected static final String SPACE_CHAR = " "; - protected static final String OPEN_BRACKET = "("; - protected static final String CLOSE_BRACKET = ")"; - protected static final String NOT = "NOT"; - protected static final String NULL = "NULL"; - protected static final String PRIMARY_KEY = "PRIMARY KEY"; - protected static final String DEFAULT = "DEFAULT"; - protected static final String COMMA = ","; - protected static final String QUESTION_MARK = "?"; - - // FIXME: Find good word for '. Better replaced by wrapIdentifier. - protected static final String TICK = "'"; - - protected static final String defaultWrapIdentifier = "\'"; - - protected static String wrapIdentifier = defaultWrapIdentifier; - - protected static String openEscapeIdentifier = "["; - - protected static String closeEscapeIdentifier = "]"; - - /** - * @return the wrapIdentifier - */ - public static String getWrapIdentifier() { - return wrapIdentifier; - } - - /** - * @param wrapIdentifier - * the wrapIdentifier to set - */ - public static void setWrapIdentifier(String wrapIdentifier) { - AbstractSQLGenerator.wrapIdentifier = wrapIdentifier; - } - - // TODO: should provide more detail to distinguish between wrap and escape - // identifier - /** - * It will wrap provided string with wrap identifier. - * - * @param name - * @return - */ - public String wrapName(String name) { - StringBuffer wrap = new StringBuffer(); - wrap.append(getWrapIdentifier()); - wrap.append(name); - wrap.append(getWrapIdentifier()); - return wrap.toString(); - } - - /** - * Variable used to escape the Identifiers - * - * @param openIdentifier - * @param closeIdentifier - */ - public static void setEscapeIdentifier(String openIdentifier, - String closeIdentifier) { - AbstractSQLGenerator.openEscapeIdentifier = openIdentifier; - AbstractSQLGenerator.closeEscapeIdentifier = closeIdentifier; - } - - /** - * - * @param value - * to escape - * @return escaped literal - */ - public static String escapeIdentifier(String value) { - return openEscapeIdentifier + value + closeEscapeIdentifier; - } - -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework; + +/** + * Common methods needed for any implementation for {@link SQLGeneratorIF} + */ +public abstract class AbstractSQLGenerator {// implements ISQLGenerator { + + protected static final String CREATE_TABLE = "CREATE TABLE"; + protected static final String SPACE_CHAR = " "; + protected static final String OPEN_BRACKET = "("; + protected static final String CLOSE_BRACKET = ")"; + protected static final String NOT = "NOT"; + protected static final String NULL = "NULL"; + protected static final String PRIMARY_KEY = "PRIMARY KEY"; + protected static final String DEFAULT = "DEFAULT"; + protected static final String COMMA = ","; + protected static final String QUESTION_MARK = "?"; + + // FIXME: Find good word for '. Better replaced by wrapIdentifier. + protected static final String TICK = "'"; + + protected static final String defaultWrapIdentifier = "\'"; + + protected static String wrapIdentifier = defaultWrapIdentifier; + + protected static String openEscapeIdentifier = "["; + + protected static String closeEscapeIdentifier = "]"; + + /** + * @return the wrapIdentifier + */ + public static String getWrapIdentifier() { + return wrapIdentifier; + } + + /** + * @param wrapIdentifier + * the wrapIdentifier to set + */ + public static void setWrapIdentifier(String wrapIdentifier) { + AbstractSQLGenerator.wrapIdentifier = wrapIdentifier; + } + + // TODO: should provide more detail to distinguish between wrap and escape + // identifier + /** + * It will wrap provided string with wrap identifier. + * + * @param name + * @return + */ + public String wrapName(String name) { + StringBuffer wrap = new StringBuffer(); + wrap.append(getWrapIdentifier()); + wrap.append(name); + wrap.append(getWrapIdentifier()); + return wrap.toString(); + } + + /** + * Variable used to escape the Identifiers + * + * @param openIdentifier + * @param closeIdentifier + */ + public static void setEscapeIdentifier(String openIdentifier, String closeIdentifier) { + AbstractSQLGenerator.openEscapeIdentifier = openIdentifier; + AbstractSQLGenerator.closeEscapeIdentifier = closeIdentifier; + } + + /** + * + * @param value + * to escape + * @return escaped literal + */ + public static String escapeIdentifier(String value) { + return openEscapeIdentifier + value + closeEscapeIdentifier; + } + +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/AbstractTest.java b/src/test/java/com/microsoft/sqlserver/testframework/AbstractTest.java index 3df03ef53..e1e451df0 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/AbstractTest.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/AbstractTest.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) 2016 Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) 2016 Microsoft Corporation All rights reserved. This program is + * made available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.testframework; @@ -23,6 +20,7 @@ import com.microsoft.sqlserver.jdbc.SQLServerConnection; + /** * Think about following things: *
  • Connection pool @@ -86,8 +84,7 @@ public static void setup() throws Exception { Assertions.assertNotNull(connectionString, "Connection String should not be null"); connection = PrepUtil.getConnection(connectionString, info); - } - catch (Exception e) { + } catch (Exception e) { throw e; } } @@ -112,11 +109,9 @@ public static void teardown() throws Exception { if (connection != null && !connection.isClosed()) { connection.close(); } - } - catch (Exception e) { + } catch (Exception e) { connection.close(); - } - finally { + } finally { connection = null; } } @@ -137,8 +132,7 @@ public static String getConfiguredProperty(String key) { * @param key * @return Value */ - public static String getConfiguredProperty(String key, - String defaultValue) { + public static String getConfiguredProperty(String key, String defaultValue) { return Utils.getConfiguredProperty(key, defaultValue); } @@ -161,8 +155,7 @@ public static void invokeLogging() { // handler = new FileHandler("Driver.log"); if ("console".equalsIgnoreCase(loggingHandler)) { handler = new ConsoleHandler(); - } - else if ("file".equalsIgnoreCase(loggingHandler)) { + } else if ("file".equalsIgnoreCase(loggingHandler)) { handler = new FileHandler("Driver.log"); System.out.println("Look for Driver.log file in your classpath for detail logs"); } @@ -173,11 +166,11 @@ else if ("file".equalsIgnoreCase(loggingHandler)) { Logger.getLogger("").addHandler(handler); } // By default, Loggers also send their output to their parent logger.   - // Typically the root Logger is configured with a set of Handlers that essentially act as default handlers for all loggers.  + // Typically the root Logger is configured with a set of Handlers that essentially act as default handlers + // for all loggers.  Logger logger = Logger.getLogger("com.microsoft.sqlserver.jdbc"); logger.setLevel(Level.FINEST); - } - catch (Exception e) { + } catch (Exception e) { System.err.println("Some how could not invoke logging: " + e.getMessage()); } } diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBCallableStatement.java b/src/test/java/com/microsoft/sqlserver/testframework/DBCallableStatement.java index b17c98563..adff2fa7f 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBCallableStatement.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBCallableStatement.java @@ -1,73 +1,67 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) 2016 Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ -package com.microsoft.sqlserver.testframework; - -import java.sql.CallableStatement; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.SQLException; - -/** - * Wrapper class CallableStatement - * - */ -public class DBCallableStatement extends AbstractParentWrapper{ - - PreparedStatement cstmt = null; - - /** - * - */ - public DBCallableStatement(DBConnection dbconnection) { - super(dbconnection, null, "preparedStatement"); - } - - /** - * @param parent - * @param internal - * @param name - */ - DBCallableStatement(AbstractParentWrapper parent, - Object internal, - String name) { - super(parent, internal, name); - // TODO Auto-generated constructor stub - } - - DBCallableStatement prepareCall(String query) throws SQLException { - cstmt = ((Connection) parent().product()).prepareCall(query); - setInternal(cstmt); - return this; - } - - /** - * - * @param x - * @param y - * @param z - * @throws SQLException - */ - public void registerOutParameter(String x, int y, int z) throws SQLException - { - //product - ((CallableStatement)product()).registerOutParameter(x, y, z); - } - - /** - * - * @param index - * @param sqltype - * @throws SQLException - */ - public void registerOutParameter(int index, int sqltype) throws SQLException - { - ((CallableStatement)product()).registerOutParameter(index, sqltype); - - } - -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) 2016 Microsoft Corporation All rights reserved. This program is + * made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package com.microsoft.sqlserver.testframework; + +import java.sql.CallableStatement; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; + + +/** + * Wrapper class CallableStatement + * + */ +public class DBCallableStatement extends AbstractParentWrapper { + + PreparedStatement cstmt = null; + + /** + * + */ + public DBCallableStatement(DBConnection dbconnection) { + super(dbconnection, null, "preparedStatement"); + } + + /** + * @param parent + * @param internal + * @param name + */ + DBCallableStatement(AbstractParentWrapper parent, Object internal, String name) { + super(parent, internal, name); + // TODO Auto-generated constructor stub + } + + DBCallableStatement prepareCall(String query) throws SQLException { + cstmt = ((Connection) parent().product()).prepareCall(query); + setInternal(cstmt); + return this; + } + + /** + * + * @param x + * @param y + * @param z + * @throws SQLException + */ + public void registerOutParameter(String x, int y, int z) throws SQLException { + // product + ((CallableStatement) product()).registerOutParameter(x, y, z); + } + + /** + * + * @param index + * @param sqltype + * @throws SQLException + */ + public void registerOutParameter(int index, int sqltype) throws SQLException { + ((CallableStatement) product()).registerOutParameter(index, sqltype); + + } + +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBCoercion.java b/src/test/java/com/microsoft/sqlserver/testframework/DBCoercion.java index e367a94b8..c0c673478 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBCoercion.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBCoercion.java @@ -1,65 +1,63 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) 2016 Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ -package com.microsoft.sqlserver.testframework; - -import java.util.BitSet; - -public class DBCoercion { - Class type = null; - protected BitSet flags = new BitSet(); - protected String name = null; - // Flags - - public static final int GET = 1; - public static final int UPDATE = 2; - public static final int SET = 3; - public static final int SETOBJECT = 4; - public static final int REG = 5; - public static final int GETPARAM = 6; - public static final int UPDATEOBJECT = 7; - public static final int ALL = 8; - - public static final int STREAM = 9; - public static final int CHAR = 10; - public static final int NCHAR = 11; - public static final int ASCII = 12; - - /** - * - * @param type - */ - public DBCoercion(Class type) { - this(type, new int[] {GET}); - } - - /** - * - * @param type - * @param tempflags - */ - public DBCoercion(Class type, - int[] tempflags) { - name = type.toString(); - this.type = type; - for (int tempflag : tempflags) flags.set(tempflag); - } - - /** - * @return type - */ - public Class type() { - return type; - } - - /** - * @return - */ - public BitSet flags() { - return flags; - } -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) 2016 Microsoft Corporation All rights reserved. This program is + * made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package com.microsoft.sqlserver.testframework; + +import java.util.BitSet; + + +public class DBCoercion { + Class type = null; + protected BitSet flags = new BitSet(); + protected String name = null; + // Flags + + public static final int GET = 1; + public static final int UPDATE = 2; + public static final int SET = 3; + public static final int SETOBJECT = 4; + public static final int REG = 5; + public static final int GETPARAM = 6; + public static final int UPDATEOBJECT = 7; + public static final int ALL = 8; + + public static final int STREAM = 9; + public static final int CHAR = 10; + public static final int NCHAR = 11; + public static final int ASCII = 12; + + /** + * + * @param type + */ + public DBCoercion(Class type) { + this(type, new int[] {GET}); + } + + /** + * + * @param type + * @param tempflags + */ + public DBCoercion(Class type, int[] tempflags) { + name = type.toString(); + this.type = type; + for (int tempflag : tempflags) + flags.set(tempflag); + } + + /** + * @return type + */ + public Class type() { + return type; + } + + /** + * @return + */ + public BitSet flags() { + return flags; + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBCoercions.java b/src/test/java/com/microsoft/sqlserver/testframework/DBCoercions.java index ff8e03f8f..2005b590c 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBCoercions.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBCoercions.java @@ -1,29 +1,27 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) 2016 Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ -package com.microsoft.sqlserver.testframework; - -import java.util.ArrayList; - -/** - * DBCoercions - * - */ -public class DBCoercions extends DBItems { - - /** - * constructor - */ - public DBCoercions() { - coercionsList = new ArrayList<>(); - } - - public DBCoercions(DBCoercion coercion) { - this.add(coercion); - } - -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) 2016 Microsoft Corporation All rights reserved. This program is + * made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package com.microsoft.sqlserver.testframework; + +import java.util.ArrayList; + + +/** + * DBCoercions + * + */ +public class DBCoercions extends DBItems { + + /** + * constructor + */ + public DBCoercions() { + coercionsList = new ArrayList<>(); + } + + public DBCoercions(DBCoercion coercion) { + this.add(coercion); + } + +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBColumn.java b/src/test/java/com/microsoft/sqlserver/testframework/DBColumn.java index f44744983..067d0b01a 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBColumn.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBColumn.java @@ -1,96 +1,93 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework; - -import java.sql.JDBCType; -import java.util.ArrayList; -import java.util.List; - -import com.microsoft.sqlserver.testframework.sqlType.SqlType; - -/** - * This class holds data for Column. Think about encrypted columns. createCMK code should not add here. - */ -public class DBColumn { - - /* - * TODO: add nullable, defaultValue, alwaysEncrypted - */ - private String columnName; - private SqlType sqlType; - private List columnValues; - - DBColumn(String columnName, - SqlType sqlType) { - this.columnName = columnName; - this.sqlType = sqlType; - } - - /** - * @return the columnName - */ - public String getColumnName() { - return columnName; - } - - /** - * @param columnName - * the columnName to set - */ - void setColumnName(String columnName) { - this.columnName = columnName; - } - - /** - * - * @return SqlType for the column - */ - public SqlType getSqlType() { - return sqlType; - } - - /** - * - * @return JDBCType for the column - */ - JDBCType getJdbctype() { - return sqlType.getJdbctype(); - } - - /** - * - * @param sqlType - */ - void setSqlType(SqlType sqlType) { - this.sqlType = sqlType; - } - - /** - * generate value for the column - * - * @param rows - * number of rows - */ - void populateValues(int rows) { - columnValues = new ArrayList<>(); - for (int i = 0; i < rows; i++) - columnValues.add(sqlType.createdata()); - } - - /** - * - * @param row - * @return the value populated for the column - */ - Object getRowValue(int row) { - // handle exceptions - return columnValues.get(row); - } - -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework; + +import java.sql.JDBCType; +import java.util.ArrayList; +import java.util.List; + +import com.microsoft.sqlserver.testframework.sqlType.SqlType; + + +/** + * This class holds data for Column. Think about encrypted columns. createCMK code should not add here. + */ +public class DBColumn { + + /* + * TODO: add nullable, defaultValue, alwaysEncrypted + */ + private String columnName; + private SqlType sqlType; + private List columnValues; + + DBColumn(String columnName, SqlType sqlType) { + this.columnName = columnName; + this.sqlType = sqlType; + } + + /** + * @return the columnName + */ + public String getColumnName() { + return columnName; + } + + /** + * @param columnName + * the columnName to set + */ + void setColumnName(String columnName) { + this.columnName = columnName; + } + + /** + * + * @return SqlType for the column + */ + public SqlType getSqlType() { + return sqlType; + } + + /** + * + * @return JDBCType for the column + */ + JDBCType getJdbctype() { + return sqlType.getJdbctype(); + } + + /** + * + * @param sqlType + */ + void setSqlType(SqlType sqlType) { + this.sqlType = sqlType; + } + + /** + * generate value for the column + * + * @param rows + * number of rows + */ + void populateValues(int rows) { + columnValues = new ArrayList<>(); + for (int i = 0; i < rows; i++) + columnValues.add(sqlType.createdata()); + } + + /** + * + * @param row + * @return the value populated for the column + */ + Object getRowValue(int row) { + // handle exceptions + return columnValues.get(row); + } + +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBConnection.java b/src/test/java/com/microsoft/sqlserver/testframework/DBConnection.java index 65ea02934..03e70faa7 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBConnection.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBConnection.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.testframework; @@ -17,6 +14,7 @@ import com.microsoft.sqlserver.jdbc.SQLServerConnection; + /* * Wrapper class for SQLServerConnection */ @@ -49,11 +47,9 @@ void getConnection(String connectionString) { try { connection = PrepUtil.getConnection(connectionString); setInternal(connection); - } - catch (SQLException ex) { + } catch (SQLException ex) { fail(ex.getMessage()); - } - catch (ClassNotFoundException ex) { + } catch (ClassNotFoundException ex) { fail(ex.getMessage()); } } @@ -71,8 +67,7 @@ public DBStatement createStatement() { try { DBStatement dbstatement = new DBStatement(this); return dbstatement.createStatement(); - } - catch (SQLException ex) { + } catch (SQLException ex) { fail(ex.getMessage()); } return null; @@ -85,8 +80,7 @@ public DBStatement createStatement() { * @return * @throws SQLException */ - public DBStatement createStatement(int type, - int concurrency) throws SQLException { + public DBStatement createStatement(int type, int concurrency) throws SQLException { DBStatement dbstatement = new DBStatement(this); return dbstatement.createStatement(type, concurrency); @@ -122,9 +116,7 @@ public DBPreparedStatement prepareStatement(String query) throws SQLException { * @return * @throws SQLException */ - public DBPreparedStatement prepareStatement(String query, - int type, - int concurrency) throws SQLException { + public DBPreparedStatement prepareStatement(String query, int type, int concurrency) throws SQLException { // Static for fast-forward, limited settings if ((type == ResultSet.TYPE_FORWARD_ONLY || type == ResultSet.TYPE_SCROLL_INSENSITIVE)) concurrency = ResultSet.CONCUR_READ_ONLY; @@ -140,8 +132,7 @@ public DBPreparedStatement prepareStatement(String query, public void close() { try { connection.close(); - } - catch (SQLException ex) { + } catch (SQLException ex) { fail(ex.getMessage()); } } @@ -156,8 +147,7 @@ public boolean isClosed() { boolean current = false; try { current = connection.isClosed(); - } - catch (SQLException ex) { + } catch (SQLException ex) { fail(ex.getMessage()); } return current; @@ -227,16 +217,13 @@ public double getServerVersion() throws Exception { int secondDot = version.indexOf('.', (firstDot + 1)); try { serverversion = Double.parseDouble(version.substring((firstDot - 2), secondDot)); - } - catch (NumberFormatException ex) { + } catch (NumberFormatException ex) { // for CTP version parsed as P2.3) - 13 throws number format exception serverversion = 16; } - } - catch (Exception e) { + } catch (Exception e) { throw new Exception("Unable to get dbms major version", e); - } - finally { + } finally { rs.close(); stmt.close(); } @@ -244,4 +231,4 @@ public double getServerVersion() throws Exception { return serverversion; } -} \ No newline at end of file +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBInvalidUtil.java b/src/test/java/com/microsoft/sqlserver/testframework/DBInvalidUtil.java index 3642c1ddb..948519026 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBInvalidUtil.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBInvalidUtil.java @@ -1,409 +1,386 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework; - -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.Reader; -import java.io.Writer; -import java.sql.Blob; -import java.sql.Clob; -import java.sql.SQLException; -import java.util.concurrent.ThreadLocalRandom; -import java.util.logging.Logger; - -import com.microsoft.sqlserver.testframework.Utils.DBBinaryStream; -import com.microsoft.sqlserver.testframework.Utils.DBCharacterStream; - -/** - * Prepared invalid stream types - */ -public class DBInvalidUtil { - public static final Logger log = Logger.getLogger("DBInvalidUtils"); - - /** - * - * InvalidClob : stream with invalid behavior 1) getCharacterStream returns InvalidCharacterStream 2) length returns invalid lengths - * - */ - public class InvalidClob implements Clob { - final int diff = 5; - - Object expected = null; - public long length; - private long actualLength; - private long invalidLength = -1; - private boolean returnValid = false; - public InvalidCharacterStream stream = null; // keep a handle on any stream - - /** - * Constructor - * - * @param expected - * @param returnValid - */ - public InvalidClob(Object expected, - boolean returnValid) { - this.expected = expected; - actualLength = this.value().length(); - this.returnValid = returnValid; - } - - protected String value() { - return ((String) expected); - } - - /** - * return length - */ - public long length() throws SQLException { - long ret = actualLength; - long actual = ret; - if (invalidLength == -1) { - int choose = ThreadLocalRandom.current().nextInt(5); - int randomInt = 1 + ThreadLocalRandom.current().nextInt(diff); - - switch (choose) { - case 0: // more than ret - actual = ret + randomInt; - break; - case 1: // less than ret - actual = ret - randomInt; - break; - case 2: // 0 - actual = 0; - break; - case 3: // return > SQL Server Limit - actual = Long.MAX_VALUE; - break; - default: // always < -1 - actual = -1 - randomInt; - } - invalidLength = actual; - length = actual; - returnValid = true; - } - - log.fine("invalidClob.length(): Actual chars=" + actualLength + " Returned chars=" + length); - return length; - } - - public Reader getCharacterStream() throws SQLException { - stream = new InvalidCharacterStream(this.value(), returnValid); - return stream; - } - - @Override - public String getSubString(long pos, - int length) throws SQLException { - assertTrue(false, "Not implemented"); - return null; - } - - @Override - public InputStream getAsciiStream() throws SQLException { - assertTrue(false, "Not implemented"); - return null; - } - - @Override - public long position(String searchstr, - long start) throws SQLException { - assertTrue(false, "Not implemented"); - return 0; - } - - @Override - public long position(Clob searchstr, - long start) throws SQLException { - assertTrue(false, "Not implemented"); - return 0; - } - - @Override - public int setString(long pos, - String str) throws SQLException { - assertTrue(false, "Not implemented"); - return 0; - } - - @Override - public int setString(long pos, - String str, - int offset, - int len) throws SQLException { - assertTrue(false, "Not implemented"); - return 0; - } - - @Override - public OutputStream setAsciiStream(long pos) throws SQLException { - assertTrue(false, "Not implemented"); - return null; - } - - @Override - public Writer setCharacterStream(long pos) throws SQLException { - assertTrue(false, "Not implemented"); - return null; - } - - @Override - public void truncate(long len) throws SQLException { - assertTrue(false, "Not implemented"); - - } - - @Override - public void free() throws SQLException { - assertTrue(false, "Not implemented"); - - } - - @Override - public Reader getCharacterStream(long pos, - long length) throws SQLException { - assertTrue(false, "Not implemented"); - return null; - } - } - - /** - * - * invalidCharacterStream : stream with invalid behavior 1) Read can throw IOException 2) Read can return data length > or < than actual - */ - public class InvalidCharacterStream extends DBCharacterStream { - final int diff = 5; - - private boolean returnValid = false; // Perfom invalid actions at most once - public boolean threwException = false; - public static final String IOExceptionMsg = "invalidCharacterStream.read() throws IOException"; - - // Constructor - public InvalidCharacterStream(String value, - boolean returnValid) { - super(value); - this.returnValid = returnValid; - } - - public int read(char[] cbuf, - int off, - int len) throws IOException { - int ret = super.read(cbuf, off, len); - int actual = ret; - if (!returnValid) { - int choose = ThreadLocalRandom.current().nextInt(5); - int randomInt = 1 + ThreadLocalRandom.current().nextInt(diff); - - switch (choose) { - case 0: // more than ret - actual = ret + randomInt; - break; - case 1: // less than ret - actual = ret - randomInt; - break; - case 2: // 0 - actual = 0; - break; - case 3: // always < -1 - actual = -1 - randomInt; - break; - default: - log.fine(IOExceptionMsg); - threwException = true; - throw new IOException(IOExceptionMsg); - } - returnValid = true; - } - log.fine("invalidCharacterStream.read(): Actual bytes=" + ret + " Returned bytes=" + actual); - return actual; - } - } - - /** - * InvalidBlob : stream with invalid behavior 1) getBinaryStream returns InvalidBinaryStream 2) Length returns invalid lengths - */ - public class InvalidBlob implements Blob { - final int diff = 5; - - private Object expected = null; - public long length; - private long actualLength; - private long invalidLength = -1; - private boolean returnValid = false; - private InvalidBinaryStream stream = null; // keep a handle on any stream - - // Constructor - public InvalidBlob(Object expected, - boolean returnValid) { - this.expected = expected; - actualLength = this.value().length; - this.returnValid = returnValid; - } - - protected byte[] value() { - return ((byte[]) expected); - } - - @Override - public long length() throws SQLException { - long ret = actualLength; - long actual = ret; - if (invalidLength == -1) { - int choose = ThreadLocalRandom.current().nextInt(5); - int randomInt = 1 + ThreadLocalRandom.current().nextInt(diff); - - switch (choose) { - case 0: // more than ret - actual = ret + randomInt; - break; - case 1: // less than ret - actual = ret - randomInt; - break; - case 2: // 0 - actual = 0; - break; - case 3: // return > SQL Server Limit - actual = Long.MAX_VALUE; - break; - default: // always < -1 - actual = -1 - randomInt; - } - invalidLength = actual; - length = actual; - returnValid = true; - } - - log.fine("invalidBlob.length(): Actual bytes=" + actualLength + " Returned bytes=" + length); - return length; - } - - @Override - public InputStream getBinaryStream() throws SQLException { - stream = new InvalidBinaryStream(this.value(), returnValid); - return stream; - } - - @Override - public byte[] getBytes(long pos, - int length) throws SQLException { - // TODO Auto-generated method stub - return null; - } - - @Override - public long position(byte[] pattern, - long start) throws SQLException { - assertTrue(false, "Not implemented"); - return 0; - } - - @Override - public long position(Blob pattern, - long start) throws SQLException { - assertTrue(false, "Not implemented"); - return 0; - } - - @Override - public int setBytes(long pos, - byte[] bytes) throws SQLException { - assertTrue(false, "Not implemented"); - return 0; - } - - @Override - public int setBytes(long pos, - byte[] bytes, - int offset, - int len) throws SQLException { - assertTrue(false, "Not implemented"); - return 0; - } - - @Override - public OutputStream setBinaryStream(long pos) throws SQLException { - assertTrue(false, "Not implemented"); - return null; - } - - @Override - public void truncate(long len) throws SQLException { - assertTrue(false, "Not implemented"); - } - - @Override - public void free() throws SQLException { - assertTrue(false, "Not implemented"); - - } - - @Override - public InputStream getBinaryStream(long pos, - long length) throws SQLException { - assertTrue(false, "Not implemented"); - return null; - } - - } - - /** - * invalidBinaryStream : stream with invalid behavior Read can return data length > or < than actual - * - */ - public class InvalidBinaryStream extends DBBinaryStream { - final int diff = 5; - private boolean _returnValid = false; // Perfom invalid actions at most once - - /** - * Constructor - * - * @param value - * @param returnValid - */ - public InvalidBinaryStream(byte[] value, - boolean returnValid) { - super(value); - _returnValid = returnValid; - } - - @Override - public int read(byte[] bytes, - int off, - int len) { - int ret = super.read(bytes, off, len); - int actual = ret; - if (!_returnValid) { - int choose = ThreadLocalRandom.current().nextInt(4); - int randomInt = 1 + ThreadLocalRandom.current().nextInt(diff); - switch (choose) { - case 0: // greater than ret - actual = ret + randomInt; - break; - case 1: // less than ret - actual = ret - randomInt; - break; - case 2: // always < -1 - actual = -1 - randomInt; - break; - default: // 0 - actual = 0; - } - // Return invalid only once per stream - _returnValid = true; - } - log.fine("invalidBinaryStream.read(): Actual bytes=" + ret + " Returned bytes=" + actual); - return actual; - } - } - -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; +import java.sql.Blob; +import java.sql.Clob; +import java.sql.SQLException; +import java.util.concurrent.ThreadLocalRandom; +import java.util.logging.Logger; + +import com.microsoft.sqlserver.testframework.Utils.DBBinaryStream; +import com.microsoft.sqlserver.testframework.Utils.DBCharacterStream; + + +/** + * Prepared invalid stream types + */ +public class DBInvalidUtil { + public static final Logger log = Logger.getLogger("DBInvalidUtils"); + + /** + * + * InvalidClob : stream with invalid behavior 1) getCharacterStream returns InvalidCharacterStream 2) length returns + * invalid lengths + * + */ + public class InvalidClob implements Clob { + final int diff = 5; + + Object expected = null; + public long length; + private long actualLength; + private long invalidLength = -1; + private boolean returnValid = false; + public InvalidCharacterStream stream = null; // keep a handle on any stream + + /** + * Constructor + * + * @param expected + * @param returnValid + */ + public InvalidClob(Object expected, boolean returnValid) { + this.expected = expected; + actualLength = this.value().length(); + this.returnValid = returnValid; + } + + protected String value() { + return ((String) expected); + } + + /** + * return length + */ + public long length() throws SQLException { + long ret = actualLength; + long actual = ret; + if (invalidLength == -1) { + int choose = ThreadLocalRandom.current().nextInt(5); + int randomInt = 1 + ThreadLocalRandom.current().nextInt(diff); + + switch (choose) { + case 0: // more than ret + actual = ret + randomInt; + break; + case 1: // less than ret + actual = ret - randomInt; + break; + case 2: // 0 + actual = 0; + break; + case 3: // return > SQL Server Limit + actual = Long.MAX_VALUE; + break; + default: // always < -1 + actual = -1 - randomInt; + } + invalidLength = actual; + length = actual; + returnValid = true; + } + + log.fine("invalidClob.length(): Actual chars=" + actualLength + " Returned chars=" + length); + return length; + } + + public Reader getCharacterStream() throws SQLException { + stream = new InvalidCharacterStream(this.value(), returnValid); + return stream; + } + + @Override + public String getSubString(long pos, int length) throws SQLException { + assertTrue(false, "Not implemented"); + return null; + } + + @Override + public InputStream getAsciiStream() throws SQLException { + assertTrue(false, "Not implemented"); + return null; + } + + @Override + public long position(String searchstr, long start) throws SQLException { + assertTrue(false, "Not implemented"); + return 0; + } + + @Override + public long position(Clob searchstr, long start) throws SQLException { + assertTrue(false, "Not implemented"); + return 0; + } + + @Override + public int setString(long pos, String str) throws SQLException { + assertTrue(false, "Not implemented"); + return 0; + } + + @Override + public int setString(long pos, String str, int offset, int len) throws SQLException { + assertTrue(false, "Not implemented"); + return 0; + } + + @Override + public OutputStream setAsciiStream(long pos) throws SQLException { + assertTrue(false, "Not implemented"); + return null; + } + + @Override + public Writer setCharacterStream(long pos) throws SQLException { + assertTrue(false, "Not implemented"); + return null; + } + + @Override + public void truncate(long len) throws SQLException { + assertTrue(false, "Not implemented"); + + } + + @Override + public void free() throws SQLException { + assertTrue(false, "Not implemented"); + + } + + @Override + public Reader getCharacterStream(long pos, long length) throws SQLException { + assertTrue(false, "Not implemented"); + return null; + } + } + + /** + * + * invalidCharacterStream : stream with invalid behavior 1) Read can throw IOException 2) Read can return data + * length > or < than actual + */ + public class InvalidCharacterStream extends DBCharacterStream { + final int diff = 5; + + private boolean returnValid = false; // Perfom invalid actions at most once + public boolean threwException = false; + public static final String IOExceptionMsg = "invalidCharacterStream.read() throws IOException"; + + // Constructor + public InvalidCharacterStream(String value, boolean returnValid) { + super(value); + this.returnValid = returnValid; + } + + public int read(char[] cbuf, int off, int len) throws IOException { + int ret = super.read(cbuf, off, len); + int actual = ret; + if (!returnValid) { + int choose = ThreadLocalRandom.current().nextInt(5); + int randomInt = 1 + ThreadLocalRandom.current().nextInt(diff); + + switch (choose) { + case 0: // more than ret + actual = ret + randomInt; + break; + case 1: // less than ret + actual = ret - randomInt; + break; + case 2: // 0 + actual = 0; + break; + case 3: // always < -1 + actual = -1 - randomInt; + break; + default: + log.fine(IOExceptionMsg); + threwException = true; + throw new IOException(IOExceptionMsg); + } + returnValid = true; + } + log.fine("invalidCharacterStream.read(): Actual bytes=" + ret + " Returned bytes=" + actual); + return actual; + } + } + + /** + * InvalidBlob : stream with invalid behavior 1) getBinaryStream returns InvalidBinaryStream 2) Length returns + * invalid lengths + */ + public class InvalidBlob implements Blob { + final int diff = 5; + + private Object expected = null; + public long length; + private long actualLength; + private long invalidLength = -1; + private boolean returnValid = false; + private InvalidBinaryStream stream = null; // keep a handle on any stream + + // Constructor + public InvalidBlob(Object expected, boolean returnValid) { + this.expected = expected; + actualLength = this.value().length; + this.returnValid = returnValid; + } + + protected byte[] value() { + return ((byte[]) expected); + } + + @Override + public long length() throws SQLException { + long ret = actualLength; + long actual = ret; + if (invalidLength == -1) { + int choose = ThreadLocalRandom.current().nextInt(5); + int randomInt = 1 + ThreadLocalRandom.current().nextInt(diff); + + switch (choose) { + case 0: // more than ret + actual = ret + randomInt; + break; + case 1: // less than ret + actual = ret - randomInt; + break; + case 2: // 0 + actual = 0; + break; + case 3: // return > SQL Server Limit + actual = Long.MAX_VALUE; + break; + default: // always < -1 + actual = -1 - randomInt; + } + invalidLength = actual; + length = actual; + returnValid = true; + } + + log.fine("invalidBlob.length(): Actual bytes=" + actualLength + " Returned bytes=" + length); + return length; + } + + @Override + public InputStream getBinaryStream() throws SQLException { + stream = new InvalidBinaryStream(this.value(), returnValid); + return stream; + } + + @Override + public byte[] getBytes(long pos, int length) throws SQLException { + // TODO Auto-generated method stub + return null; + } + + @Override + public long position(byte[] pattern, long start) throws SQLException { + assertTrue(false, "Not implemented"); + return 0; + } + + @Override + public long position(Blob pattern, long start) throws SQLException { + assertTrue(false, "Not implemented"); + return 0; + } + + @Override + public int setBytes(long pos, byte[] bytes) throws SQLException { + assertTrue(false, "Not implemented"); + return 0; + } + + @Override + public int setBytes(long pos, byte[] bytes, int offset, int len) throws SQLException { + assertTrue(false, "Not implemented"); + return 0; + } + + @Override + public OutputStream setBinaryStream(long pos) throws SQLException { + assertTrue(false, "Not implemented"); + return null; + } + + @Override + public void truncate(long len) throws SQLException { + assertTrue(false, "Not implemented"); + } + + @Override + public void free() throws SQLException { + assertTrue(false, "Not implemented"); + + } + + @Override + public InputStream getBinaryStream(long pos, long length) throws SQLException { + assertTrue(false, "Not implemented"); + return null; + } + + } + + /** + * invalidBinaryStream : stream with invalid behavior Read can return data length > or < than actual + * + */ + public class InvalidBinaryStream extends DBBinaryStream { + final int diff = 5; + private boolean _returnValid = false; // Perfom invalid actions at most once + + /** + * Constructor + * + * @param value + * @param returnValid + */ + public InvalidBinaryStream(byte[] value, boolean returnValid) { + super(value); + _returnValid = returnValid; + } + + @Override + public int read(byte[] bytes, int off, int len) { + int ret = super.read(bytes, off, len); + int actual = ret; + if (!_returnValid) { + int choose = ThreadLocalRandom.current().nextInt(4); + int randomInt = 1 + ThreadLocalRandom.current().nextInt(diff); + switch (choose) { + case 0: // greater than ret + actual = ret + randomInt; + break; + case 1: // less than ret + actual = ret - randomInt; + break; + case 2: // always < -1 + actual = -1 - randomInt; + break; + default: // 0 + actual = 0; + } + // Return invalid only once per stream + _returnValid = true; + } + log.fine("invalidBinaryStream.read(): Actual bytes=" + ret + " Returned bytes=" + actual); + return actual; + } + } + +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBItems.java b/src/test/java/com/microsoft/sqlserver/testframework/DBItems.java index be2999a1b..0eb5ec6a7 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBItems.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBItems.java @@ -1,40 +1,38 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework; - -import java.util.ArrayList; - -/** - * Each sqlType has a list of coercions associate with it - * - */ -public class DBItems { - protected ArrayList coercionsList; - - public DBItems() { - - } - - public DBCoercion find(Class type) { - for (DBCoercion item : coercionsList) { - if (item.type() == type) - return item; - } - return null; - } - - /** - * - * @param item - * @return - */ - public boolean add(DBCoercion item) { - return coercionsList.add(item); - } -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework; + +import java.util.ArrayList; + + +/** + * Each sqlType has a list of coercions associate with it + * + */ +public class DBItems { + protected ArrayList coercionsList; + + public DBItems() { + + } + + public DBCoercion find(Class type) { + for (DBCoercion item : coercionsList) { + if (item.type() == type) + return item; + } + return null; + } + + /** + * + * @param item + * @return + */ + public boolean add(DBCoercion item) { + return coercionsList.add(item); + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBPreparedStatement.java b/src/test/java/com/microsoft/sqlserver/testframework/DBPreparedStatement.java index 99d9c5ab3..796c2a114 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBPreparedStatement.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBPreparedStatement.java @@ -1,109 +1,105 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; - -/** - * - * Wrapper class PreparedStatement - */ -public class DBPreparedStatement extends DBStatement { - - PreparedStatement pstmt = null; - DBResultSet dbresultSet = null; - - /** - * - */ - public DBPreparedStatement(DBConnection dbconnection) { - super(dbconnection); - } - - /** - * set up internal PreparedStatement with query - * - * @param query - * @return - * @throws SQLException - * - */ - DBPreparedStatement prepareStatement(String query) throws SQLException { - pstmt = ((Connection) parent().product()).prepareStatement(query); - setInternal(pstmt); - return this; - } - - /** - * - * @param query - * @param resultSetType - * @param resultSetConcurrency - * @return - * @throws SQLException - */ - DBPreparedStatement prepareStatement(String query, - int resultSetType, - int resultSetConcurrency) throws SQLException { - pstmt = ((Connection) parent().product()).prepareStatement(query, resultSetType, resultSetConcurrency); - setInternal(pstmt); - return this; - } - - @Override - void setInternal(Object internal) { - this.internal = internal; - } - - /** - * - * @param parameterIndex - * @param targetObject - * @throws SQLException - */ - public void setObject(int parameterIndex, - Object targetObject) throws SQLException { - - ((PreparedStatement) product()).setObject(parameterIndex, targetObject); - } - - /** - * - * @return - * @throws SQLException - */ - public DBResultSet executeQuery() throws SQLException { - ResultSet rs = null; - rs = pstmt.executeQuery(); - dbresultSet = new DBResultSet(this, rs); - return dbresultSet; - } - - /** - * populate table with values using prepared statement - * - * @param table - * @return true if table is populated - */ - public boolean populateTable(DBTable table) { - return table.populateTableWithPreparedStatement(this); - } - - /** - * - * @return - * @throws SQLException - */ - public boolean execute() throws SQLException { - return pstmt.execute(); - } -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework; + +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + + +/** + * + * Wrapper class PreparedStatement + */ +public class DBPreparedStatement extends DBStatement { + + PreparedStatement pstmt = null; + DBResultSet dbresultSet = null; + + /** + * + */ + public DBPreparedStatement(DBConnection dbconnection) { + super(dbconnection); + } + + /** + * set up internal PreparedStatement with query + * + * @param query + * @return + * @throws SQLException + * + */ + DBPreparedStatement prepareStatement(String query) throws SQLException { + pstmt = ((Connection) parent().product()).prepareStatement(query); + setInternal(pstmt); + return this; + } + + /** + * + * @param query + * @param resultSetType + * @param resultSetConcurrency + * @return + * @throws SQLException + */ + DBPreparedStatement prepareStatement(String query, int resultSetType, + int resultSetConcurrency) throws SQLException { + pstmt = ((Connection) parent().product()).prepareStatement(query, resultSetType, resultSetConcurrency); + setInternal(pstmt); + return this; + } + + @Override + void setInternal(Object internal) { + this.internal = internal; + } + + /** + * + * @param parameterIndex + * @param targetObject + * @throws SQLException + */ + public void setObject(int parameterIndex, Object targetObject) throws SQLException { + + ((PreparedStatement) product()).setObject(parameterIndex, targetObject); + } + + /** + * + * @return + * @throws SQLException + */ + public DBResultSet executeQuery() throws SQLException { + ResultSet rs = null; + rs = pstmt.executeQuery(); + dbresultSet = new DBResultSet(this, rs); + return dbresultSet; + } + + /** + * populate table with values using prepared statement + * + * @param table + * @return true if table is populated + */ + public boolean populateTable(DBTable table) { + return table.populateTableWithPreparedStatement(this); + } + + /** + * + * @return + * @throws SQLException + */ + public boolean execute() throws SQLException { + return pstmt.execute(); + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java index f9bd04e91..9a4ce2f42 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSet.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.testframework; @@ -26,6 +23,7 @@ import com.microsoft.sqlserver.testframework.Utils.DBBinaryStream; import com.microsoft.sqlserver.testframework.Utils.DBCharacterStream; + /** * wrapper class for ResultSet * @@ -51,27 +49,23 @@ public class DBResultSet extends AbstractParentWrapper implements AutoCloseable public static final int TYPE_DIRECT_FORWARDONLY = ResultSet.TYPE_FORWARD_ONLY + 1000; protected DBTable currentTable; - public int _currentrow = -1; // The row this rowset is currently pointing to + public int _currentrow = -1; // The row this rowset is currently pointing to ResultSet resultSet = null; DBResultSetMetaData metaData; - DBResultSet(DBStatement dbstatement, - ResultSet internal) { + DBResultSet(DBStatement dbstatement, ResultSet internal) { super(dbstatement, internal, "resultSet"); resultSet = internal; } - DBResultSet(DBStatement dbstatement, - ResultSet internal, - DBTable table) { + DBResultSet(DBStatement dbstatement, ResultSet internal, DBTable table) { super(dbstatement, internal, "resultSet"); resultSet = internal; currentTable = table; } - DBResultSet(DBPreparedStatement dbpstmt, - ResultSet internal) { + DBResultSet(DBPreparedStatement dbpstmt, ResultSet internal) { super(dbpstmt, internal, "resultSet"); resultSet = internal; } @@ -201,8 +195,7 @@ public void verifyCurrentRow(DBTable table) throws SQLException { * @throws SQLException * @throws Exception */ - public void verifydata(int ordinal, - Class coercion) throws SQLException { + public void verifydata(int ordinal, Class coercion) throws SQLException { Object expectedData = currentTable.columns.get(ordinal).getRowValue(_currentrow); // getXXX - default mapping @@ -221,26 +214,26 @@ public void verifydata(int ordinal, * @param retrieved * @throws SQLException */ - public void verifydata(int ordinal, - Class coercion, - Object expectedData, - Object retrieved) throws SQLException { + public void verifydata(int ordinal, Class coercion, Object expectedData, Object retrieved) throws SQLException { metaData = this.getMetaData(); switch (metaData.getColumnType(ordinal + 1)) { case java.sql.Types.BIGINT: assertTrue((((Long) expectedData).longValue() == ((Long) retrieved).longValue()), - "Unexpected bigint value, expected: " + (Long) expectedData + " .Retrieved: " + (Long) retrieved); + "Unexpected bigint value, expected: " + (Long) expectedData + " .Retrieved: " + + (Long) retrieved); break; case java.sql.Types.INTEGER: - assertTrue((((Integer) expectedData).intValue() == ((Integer) retrieved).intValue()), "Unexpected int value, expected : " - + (Integer) expectedData + " ,received: " + (Integer) retrieved); + assertTrue((((Integer) expectedData).intValue() == ((Integer) retrieved).intValue()), + "Unexpected int value, expected : " + (Integer) expectedData + " ,received: " + + (Integer) retrieved); break; case java.sql.Types.SMALLINT: case java.sql.Types.TINYINT: - assertTrue((((Short) expectedData).shortValue() == ((Short) retrieved).shortValue()), "Unexpected smallint/tinyint value, expected: " - + " " + (Short) expectedData + " received: " + (Short) retrieved); + assertTrue((((Short) expectedData).shortValue() == ((Short) retrieved).shortValue()), + "Unexpected smallint/tinyint value, expected: " + " " + (Short) expectedData + " received: " + + (Short) retrieved); break; case java.sql.Types.BIT: @@ -248,19 +241,22 @@ public void verifydata(int ordinal, expectedData = true; else expectedData = false; - assertTrue((((Boolean) expectedData).booleanValue() == ((Boolean) retrieved).booleanValue()), "Unexpected bit value, expected: " - + (Boolean) expectedData + " ,received: " + (Boolean) retrieved); + assertTrue((((Boolean) expectedData).booleanValue() == ((Boolean) retrieved).booleanValue()), + "Unexpected bit value, expected: " + (Boolean) expectedData + " ,received: " + + (Boolean) retrieved); break; case java.sql.Types.DECIMAL: case java.sql.Types.NUMERIC: - assertTrue(0 == (((BigDecimal) expectedData).compareTo((BigDecimal) retrieved)), "Unexpected decimal/numeric/money/smallmoney value " - + ",expected: " + (BigDecimal) expectedData + " received: " + (BigDecimal) retrieved); + assertTrue(0 == (((BigDecimal) expectedData).compareTo((BigDecimal) retrieved)), + "Unexpected decimal/numeric/money/smallmoney value " + ",expected: " + (BigDecimal) expectedData + + " received: " + (BigDecimal) retrieved); break; case java.sql.Types.DOUBLE: - assertTrue((((Double) expectedData).doubleValue() == ((Double) retrieved).doubleValue()), "Unexpected float value, expected: " - + (Double) expectedData + " received: " + (Double) retrieved); + assertTrue((((Double) expectedData).doubleValue() == ((Double) retrieved).doubleValue()), + "Unexpected float value, expected: " + (Double) expectedData + " received: " + + (Double) retrieved); break; case java.sql.Types.REAL: @@ -273,38 +269,43 @@ public void verifydata(int ordinal, case java.sql.Types.VARCHAR: case java.sql.Types.NVARCHAR: - assertTrue((((String) expectedData).trim().equalsIgnoreCase(((String) retrieved).trim())), "Unexpected varchar/nvarchar value, " - + "expected: " + ((String) expectedData).trim() + " ,received: " + ((String) retrieved).trim()); + assertTrue((((String) expectedData).trim().equalsIgnoreCase(((String) retrieved).trim())), + "Unexpected varchar/nvarchar value, " + "expected: " + ((String) expectedData).trim() + + " ,received: " + ((String) retrieved).trim()); break; case java.sql.Types.CHAR: case java.sql.Types.NCHAR: - assertTrue((((String) expectedData).trim().equalsIgnoreCase(((String) retrieved).trim())), "Unexpected char/nchar value, " - + "expected: " + ((String) expectedData).trim() + " ,received: " + ((String) retrieved).trim()); + assertTrue((((String) expectedData).trim().equalsIgnoreCase(((String) retrieved).trim())), + "Unexpected char/nchar value, " + "expected: " + ((String) expectedData).trim() + + " ,received: " + ((String) retrieved).trim()); break; case java.sql.Types.TIMESTAMP: if (metaData.getColumnTypeName(ordinal + 1).equalsIgnoreCase("datetime")) { - assertTrue((((Timestamp) roundDatetimeValue(expectedData)).getTime() == (((Timestamp) retrieved).getTime())), - "Unexpected datetime value, expected: " + ((Timestamp) roundDatetimeValue(expectedData)).getTime() + " , received: " + assertTrue( + (((Timestamp) roundDatetimeValue(expectedData)) + .getTime() == (((Timestamp) retrieved).getTime())), + "Unexpected datetime value, expected: " + + ((Timestamp) roundDatetimeValue(expectedData)).getTime() + " , received: " + (((Timestamp) retrieved).getTime())); break; - } - else if (metaData.getColumnTypeName(ordinal + 1).equalsIgnoreCase("smalldatetime")) { - assertTrue((((Timestamp) roundSmallDateTimeValue(expectedData)).getTime() == (((Timestamp) retrieved).getTime())), - "Unexpected smalldatetime value, expected: " + ((Timestamp) roundSmallDateTimeValue(expectedData)).getTime() - + " ,received: " + (((Timestamp) retrieved).getTime())); + } else if (metaData.getColumnTypeName(ordinal + 1).equalsIgnoreCase("smalldatetime")) { + assertTrue( + (((Timestamp) roundSmallDateTimeValue(expectedData)) + .getTime() == (((Timestamp) retrieved).getTime())), + "Unexpected smalldatetime value, expected: " + + ((Timestamp) roundSmallDateTimeValue(expectedData)).getTime() + " ,received: " + + (((Timestamp) retrieved).getTime())); break; - } - else { + } else { String retrievedTimestamp = retrieved.toString(); - String expectedTimestamp = expectedData.toString().substring(0,retrievedTimestamp.length()); - assertTrue(expectedTimestamp.equalsIgnoreCase(retrievedTimestamp), "Unexpected datetime2 value, " + "expected: " - + expectedTimestamp + " ,received: " + retrievedTimestamp); - break; + String expectedTimestamp = expectedData.toString().substring(0, retrievedTimestamp.length()); + assertTrue(expectedTimestamp.equalsIgnoreCase(retrievedTimestamp), "Unexpected datetime2 value, " + + "expected: " + expectedTimestamp + " ,received: " + retrievedTimestamp); + break; } - case java.sql.Types.DATE: assertTrue((("" + expectedData).equalsIgnoreCase("" + retrieved)), "Unexpected date value, expected: " + expectedData + " ,received: " + retrieved); @@ -312,7 +313,7 @@ else if (metaData.getColumnTypeName(ordinal + 1).equalsIgnoreCase("smalldatetime case java.sql.Types.TIME: String retrievedTime = retrieved.toString(); - String expectedTime = expectedData.toString().substring(0,retrievedTime.length()); + String expectedTime = expectedData.toString().substring(0, retrievedTime.length()); assertTrue(expectedTime.equalsIgnoreCase(retrievedTime), "Unexpected time value, expected: " + expectedTime + " ,received: " + retrievedTime); break; @@ -344,38 +345,31 @@ else if (metaData.getColumnTypeName(ordinal + 1).equalsIgnoreCase("smalldatetime * @return * @throws SQLException */ - public Object getXXX(Object idx, - Class coercion) throws SQLException { + public Object getXXX(Object idx, Class coercion) throws SQLException { int intOrdinal = 0; String strOrdinal = ""; boolean isInteger = false; if (idx == null) { strOrdinal = null; - } - else if (idx instanceof Integer) { + } else if (idx instanceof Integer) { isInteger = true; intOrdinal = (Integer) idx; - } - else { + } else { // Otherwise throw new SQLException("Unhandled ordinal type: " + idx.getClass()); } if (coercion == Object.class) { return this.getObject(intOrdinal); - } - else if (coercion == DBBinaryStream.class) { + } else if (coercion == DBBinaryStream.class) { return isInteger ? this.getBinaryStream(intOrdinal) : this.getBinaryStream(strOrdinal); - } - else if (coercion == DBCharacterStream.class) { + } else if (coercion == DBCharacterStream.class) { return isInteger ? this.getCharacterStream(intOrdinal) : this.getCharacterStream(strOrdinal); - } - else { + } else { if (log.isLoggable(Level.FINE)) { log.fine("coercion not supported! "); - } - else { + } else { log.fine("coercion + " + coercion.toString() + " is not supported!"); } } @@ -449,8 +443,7 @@ private static Object roundSmallDateTimeValue(Object value) { if (value instanceof Calendar) { cal = (Calendar) value; - } - else { + } else { ts = Timestamp.valueOf((String) value); cal = Calendar.getInstance(); cal.setTimeInMillis(ts.getTime()); @@ -458,7 +451,8 @@ private static Object roundSmallDateTimeValue(Object value) { } // round to the nearest minute - double seconds = cal.get(Calendar.SECOND) + (nanos == -1 ? ((double) cal.get(Calendar.MILLISECOND) / 1000) : ((double) nanos / 1000000000)); + 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); } @@ -472,8 +466,7 @@ private static Object roundSmallDateTimeValue(Object value) { // return appropriate value if (value instanceof Calendar) { return cal; - } - else { + } else { ts.setTime(cal.getTimeInMillis()); ts.setNanos(nanos); return ts; @@ -483,7 +476,8 @@ private static Object roundSmallDateTimeValue(Object value) { private static Object roundDatetimeValue(Object value) { if (value == null) return null; - Timestamp ts = value instanceof Timestamp ? (Timestamp) value : new Timestamp(((Calendar) value).getTimeInMillis()); + Timestamp ts = value instanceof Timestamp ? (Timestamp) value + : new Timestamp(((Calendar) value).getTimeInMillis()); int millis = ts.getNanos() / 1000000; int lastDigit = (int) (millis % 10); switch (lastDigit) { diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetMetaData.java b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetMetaData.java index 321ffb65a..7cf5b15e5 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetMetaData.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetMetaData.java @@ -1,193 +1,189 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework; - -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.SQLException; - -import com.microsoft.sqlserver.jdbc.SQLServerResultSetMetaData; - -/** - * - * Wrapper class for ResultSetMetaData - */ -public class DBResultSetMetaData extends AbstractParentWrapper { - - DBResultSetMetaData dbresultSetMetaData = null; - ResultSetMetaData resultSetMetaData = null; - - /** - * @param parent - * @param internal - * @param name - */ - DBResultSetMetaData(AbstractParentWrapper parent, - Object internal, - String name) { - super(parent, internal, name); - // TODO Auto-generated constructor stub - } - - /** - * - */ - public DBResultSetMetaData(DBResultSet dbresultset) { - super(dbresultset, null, "dbresultset"); - } - - DBResultSetMetaData resultSetMetaData() { - return this; - } - - /** - * - * @return - * @throws SQLException - */ - public DBResultSetMetaData getMetaData() throws SQLException { - resultSetMetaData = ((ResultSet) parent().product()).getMetaData(); - setInternal(resultSetMetaData); - return this; - } - - /** - * - * @throws SQLException - */ - public void verify() throws SQLException { - // getColumnCount - int columns = this.getColumnCount(); - - // Loop through the columns - for (int i = 1; i <= columns; i++) { - // Note: Just calling these performs the verification, in each method - this.getColumnName(i); - this.getColumnType(i); - this.getColumnTypeName(i); - this.getScale(i); - this.isCaseSensitive(i); - this.isAutoIncrement(i); - this.isCurrency(i); - this.isNullable(i); - this.isSigned(i); - } - } - - /** - * - * @return - * @throws SQLException - */ - public int getColumnCount() throws SQLException { - return ((SQLServerResultSetMetaData) product()).getColumnCount(); - } - - /** - * - * @param index - * @return - * @throws SQLException - */ - public String getColumnName(int index) throws SQLException { - return ((SQLServerResultSetMetaData) product()).getColumnName(index); - } - - /** - * - * @param index - * @return - * @throws SQLException - */ - public int getColumnType(int index) throws SQLException { - return ((SQLServerResultSetMetaData) product()).getColumnType(index); - } - - /** - * - * @param index - * @return - * @throws SQLException - */ - public String getColumnTypeName(int index) throws SQLException { - return ((SQLServerResultSetMetaData) product()).getColumnTypeName(index); - } - - /** - * - * @param x - * @return - * @throws SQLException - */ - public int getPrecision(int x) throws SQLException { - return ((SQLServerResultSetMetaData) product()).getPrecision(x); - } - - /** - * - * @param x - * @return - * @throws SQLException - */ - public int getScale(int x) throws SQLException { - return ((SQLServerResultSetMetaData) product()).getScale(x); - } - - /** - * - * @param x - * @return - * @throws SQLException - */ - public boolean isCaseSensitive(int x) throws SQLException { - return ((SQLServerResultSetMetaData) product()).isCaseSensitive(x); - - } - - /** - * - * @param x - * @return - * @throws SQLException - */ - public boolean isCurrency(int x) throws SQLException { - return ((SQLServerResultSetMetaData) product()).isCurrency(x); - } - - /** - * - * @param x - * @return - * @throws SQLException - */ - public boolean isAutoIncrement(int x) throws SQLException { - return ((SQLServerResultSetMetaData) product()).isAutoIncrement(x); - } - - /** - * - * @param x - * @return - * @throws SQLException - */ - public int isNullable(int x) throws SQLException { - return ((SQLServerResultSetMetaData) product()).isNullable(x); - } - - /** - * - * @param x - * @return - * @throws SQLException - */ - public boolean isSigned(int x) throws SQLException { - return ((SQLServerResultSetMetaData) product()).isSigned(x); - } - -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework; + +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; + +import com.microsoft.sqlserver.jdbc.SQLServerResultSetMetaData; + + +/** + * + * Wrapper class for ResultSetMetaData + */ +public class DBResultSetMetaData extends AbstractParentWrapper { + + DBResultSetMetaData dbresultSetMetaData = null; + ResultSetMetaData resultSetMetaData = null; + + /** + * @param parent + * @param internal + * @param name + */ + DBResultSetMetaData(AbstractParentWrapper parent, Object internal, String name) { + super(parent, internal, name); + // TODO Auto-generated constructor stub + } + + /** + * + */ + public DBResultSetMetaData(DBResultSet dbresultset) { + super(dbresultset, null, "dbresultset"); + } + + DBResultSetMetaData resultSetMetaData() { + return this; + } + + /** + * + * @return + * @throws SQLException + */ + public DBResultSetMetaData getMetaData() throws SQLException { + resultSetMetaData = ((ResultSet) parent().product()).getMetaData(); + setInternal(resultSetMetaData); + return this; + } + + /** + * + * @throws SQLException + */ + public void verify() throws SQLException { + // getColumnCount + int columns = this.getColumnCount(); + + // Loop through the columns + for (int i = 1; i <= columns; i++) { + // Note: Just calling these performs the verification, in each method + this.getColumnName(i); + this.getColumnType(i); + this.getColumnTypeName(i); + this.getScale(i); + this.isCaseSensitive(i); + this.isAutoIncrement(i); + this.isCurrency(i); + this.isNullable(i); + this.isSigned(i); + } + } + + /** + * + * @return + * @throws SQLException + */ + public int getColumnCount() throws SQLException { + return ((SQLServerResultSetMetaData) product()).getColumnCount(); + } + + /** + * + * @param index + * @return + * @throws SQLException + */ + public String getColumnName(int index) throws SQLException { + return ((SQLServerResultSetMetaData) product()).getColumnName(index); + } + + /** + * + * @param index + * @return + * @throws SQLException + */ + public int getColumnType(int index) throws SQLException { + return ((SQLServerResultSetMetaData) product()).getColumnType(index); + } + + /** + * + * @param index + * @return + * @throws SQLException + */ + public String getColumnTypeName(int index) throws SQLException { + return ((SQLServerResultSetMetaData) product()).getColumnTypeName(index); + } + + /** + * + * @param x + * @return + * @throws SQLException + */ + public int getPrecision(int x) throws SQLException { + return ((SQLServerResultSetMetaData) product()).getPrecision(x); + } + + /** + * + * @param x + * @return + * @throws SQLException + */ + public int getScale(int x) throws SQLException { + return ((SQLServerResultSetMetaData) product()).getScale(x); + } + + /** + * + * @param x + * @return + * @throws SQLException + */ + public boolean isCaseSensitive(int x) throws SQLException { + return ((SQLServerResultSetMetaData) product()).isCaseSensitive(x); + + } + + /** + * + * @param x + * @return + * @throws SQLException + */ + public boolean isCurrency(int x) throws SQLException { + return ((SQLServerResultSetMetaData) product()).isCurrency(x); + } + + /** + * + * @param x + * @return + * @throws SQLException + */ + public boolean isAutoIncrement(int x) throws SQLException { + return ((SQLServerResultSetMetaData) product()).isAutoIncrement(x); + } + + /** + * + * @param x + * @return + * @throws SQLException + */ + public int isNullable(int x) throws SQLException { + return ((SQLServerResultSetMetaData) product()).isNullable(x); + } + + /** + * + * @param x + * @return + * @throws SQLException + */ + public boolean isSigned(int x) throws SQLException { + return ((SQLServerResultSetMetaData) product()).isSigned(x); + } + +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetTypes.java b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetTypes.java index 6fe491b94..0a76bfa50 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetTypes.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBResultSetTypes.java @@ -1,34 +1,30 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ -package com.microsoft.sqlserver.testframework; - -/** - * @author Microsoft - * - */ - -public enum DBResultSetTypes { - - TYPE_FORWARD_ONLY_CONCUR_READ_ONLY(DBResultSet.TYPE_FORWARD_ONLY, DBResultSet.CONCUR_READ_ONLY), - TYPE_SCROLL_INSENSITIVE_CONCUR_READ_ONLY(DBResultSet.TYPE_SCROLL_INSENSITIVE, DBResultSet.CONCUR_READ_ONLY), - TYPE_SCROLL_SENSITIVE_CONCUR_READ_ONLY(DBResultSet.TYPE_SCROLL_SENSITIVE, DBResultSet.CONCUR_READ_ONLY), - TYPE_FORWARD_ONLY_CONCUR_UPDATABLE(DBResultSet.TYPE_FORWARD_ONLY, DBResultSet.CONCUR_UPDATABLE), - TYPE_SCROLL_SENSITIVE_CONCUR_UPDATABLE(DBResultSet.TYPE_SCROLL_SENSITIVE, DBResultSet.CONCUR_UPDATABLE), - TYPE_DYNAMIC_CONCUR_OPTIMISTIC(DBResultSet.TYPE_DYNAMIC, DBResultSet.CONCUR_OPTIMISTIC), - TYPE_CURSOR_FORWARDONLY_CONCUR_UPDATABLE(DBResultSet.TYPE_CURSOR_FORWARDONLY, DBResultSet.CONCUR_READ_ONLY),; - - public int resultsetCursor; - public int resultSetConcurrency; - - DBResultSetTypes(int resultSetCursor, - int resultSetConcurrency) { - this.resultsetCursor = resultSetCursor; - this.resultSetConcurrency = resultSetConcurrency; - } - -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package com.microsoft.sqlserver.testframework; + +/** + * @author Microsoft + * + */ + +public enum DBResultSetTypes { + + TYPE_FORWARD_ONLY_CONCUR_READ_ONLY(DBResultSet.TYPE_FORWARD_ONLY, DBResultSet.CONCUR_READ_ONLY), + TYPE_SCROLL_INSENSITIVE_CONCUR_READ_ONLY(DBResultSet.TYPE_SCROLL_INSENSITIVE, DBResultSet.CONCUR_READ_ONLY), + TYPE_SCROLL_SENSITIVE_CONCUR_READ_ONLY(DBResultSet.TYPE_SCROLL_SENSITIVE, DBResultSet.CONCUR_READ_ONLY), + TYPE_FORWARD_ONLY_CONCUR_UPDATABLE(DBResultSet.TYPE_FORWARD_ONLY, DBResultSet.CONCUR_UPDATABLE), + TYPE_SCROLL_SENSITIVE_CONCUR_UPDATABLE(DBResultSet.TYPE_SCROLL_SENSITIVE, DBResultSet.CONCUR_UPDATABLE), + TYPE_DYNAMIC_CONCUR_OPTIMISTIC(DBResultSet.TYPE_DYNAMIC, DBResultSet.CONCUR_OPTIMISTIC), + TYPE_CURSOR_FORWARDONLY_CONCUR_UPDATABLE(DBResultSet.TYPE_CURSOR_FORWARDONLY, DBResultSet.CONCUR_READ_ONLY),; + + public int resultsetCursor; + public int resultSetConcurrency; + + DBResultSetTypes(int resultSetCursor, int resultSetConcurrency) { + this.resultsetCursor = resultSetCursor; + this.resultSetConcurrency = resultSetConcurrency; + } + +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBSchema.java b/src/test/java/com/microsoft/sqlserver/testframework/DBSchema.java index e08995346..24b205092 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBSchema.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBSchema.java @@ -1,129 +1,126 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import com.microsoft.sqlserver.testframework.sqlType.SqlBigInt; -import com.microsoft.sqlserver.testframework.sqlType.SqlBinary; -import com.microsoft.sqlserver.testframework.sqlType.SqlBit; -import com.microsoft.sqlserver.testframework.sqlType.SqlChar; -import com.microsoft.sqlserver.testframework.sqlType.SqlDate; -import com.microsoft.sqlserver.testframework.sqlType.SqlDateTime; -import com.microsoft.sqlserver.testframework.sqlType.SqlDateTime2; -import com.microsoft.sqlserver.testframework.sqlType.SqlDateTimeOffset; -import com.microsoft.sqlserver.testframework.sqlType.SqlDecimal; -import com.microsoft.sqlserver.testframework.sqlType.SqlFloat; -import com.microsoft.sqlserver.testframework.sqlType.SqlInt; -import com.microsoft.sqlserver.testframework.sqlType.SqlMoney; -import com.microsoft.sqlserver.testframework.sqlType.SqlNChar; -import com.microsoft.sqlserver.testframework.sqlType.SqlNVarChar; -import com.microsoft.sqlserver.testframework.sqlType.SqlNumeric; -import com.microsoft.sqlserver.testframework.sqlType.SqlReal; -import com.microsoft.sqlserver.testframework.sqlType.SqlSmallDateTime; -import com.microsoft.sqlserver.testframework.sqlType.SqlSmallInt; -import com.microsoft.sqlserver.testframework.sqlType.SqlSmallMoney; -import com.microsoft.sqlserver.testframework.sqlType.SqlTime; -import com.microsoft.sqlserver.testframework.sqlType.SqlTinyInt; -import com.microsoft.sqlserver.testframework.sqlType.SqlType; -import com.microsoft.sqlserver.testframework.sqlType.SqlVarBinary; -import com.microsoft.sqlserver.testframework.sqlType.SqlVarChar; - -/** - * Collection of SqlType used to create table in {@link DBTable} - * - * @author Microsoft - * - */ -public class DBSchema { - - private List sqlTypes; - - /** - * - * @param autoGenerateSchema - */ - DBSchema(boolean autoGenerateSchema) { - sqlTypes = new ArrayList<>(); - if (autoGenerateSchema) { - // Exact Numeric - sqlTypes.add(new SqlBigInt()); - sqlTypes.add(new SqlInt()); - sqlTypes.add(new SqlSmallInt()); - sqlTypes.add(new SqlTinyInt()); - sqlTypes.add(new SqlBit()); - sqlTypes.add(new SqlDecimal()); - sqlTypes.add(new SqlNumeric()); - sqlTypes.add(new SqlMoney()); - sqlTypes.add(new SqlSmallMoney()); - // Appx Numeric - sqlTypes.add(new SqlFloat()); - sqlTypes.add(new SqlReal()); - // Character - sqlTypes.add(new SqlChar()); - sqlTypes.add(new SqlVarChar()); - // Unicode - sqlTypes.add(new SqlNChar()); - sqlTypes.add(new SqlNVarChar()); - // Temporal - sqlTypes.add(new SqlDateTime()); - sqlTypes.add(new SqlDate()); - sqlTypes.add(new SqlTime()); - sqlTypes.add(new SqlSmallDateTime()); - sqlTypes.add(new SqlDateTime2()); - sqlTypes.add(new SqlDateTimeOffset()); - // Binary - sqlTypes.add(new SqlBinary()); - sqlTypes.add(new SqlVarBinary()); - - // TODO: - // Other types - } - } - - /** - * - * @param autoGenerateSchema - * @param alternateSchema - */ - DBSchema(boolean autoGenerateSchema, - boolean alternateSchema) { - this(autoGenerateSchema); - if (alternateSchema) { - Collections.shuffle(this.sqlTypes); - } - } - - /** - * - * @param index - * @return - */ - SqlType getSqlType(int index) { - return sqlTypes.get(index); - } - - /** - * - * @param sqlType - */ - void addSqlTpe(SqlType sqlType) { - sqlTypes.add(sqlType); - } - - /** - * - * @return number of sqlTypes in the schema object - */ - int getNumberOfSqlTypes() { - return sqlTypes.size(); - } -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +import com.microsoft.sqlserver.testframework.sqlType.SqlBigInt; +import com.microsoft.sqlserver.testframework.sqlType.SqlBinary; +import com.microsoft.sqlserver.testframework.sqlType.SqlBit; +import com.microsoft.sqlserver.testframework.sqlType.SqlChar; +import com.microsoft.sqlserver.testframework.sqlType.SqlDate; +import com.microsoft.sqlserver.testframework.sqlType.SqlDateTime; +import com.microsoft.sqlserver.testframework.sqlType.SqlDateTime2; +import com.microsoft.sqlserver.testframework.sqlType.SqlDateTimeOffset; +import com.microsoft.sqlserver.testframework.sqlType.SqlDecimal; +import com.microsoft.sqlserver.testframework.sqlType.SqlFloat; +import com.microsoft.sqlserver.testframework.sqlType.SqlInt; +import com.microsoft.sqlserver.testframework.sqlType.SqlMoney; +import com.microsoft.sqlserver.testframework.sqlType.SqlNChar; +import com.microsoft.sqlserver.testframework.sqlType.SqlNVarChar; +import com.microsoft.sqlserver.testframework.sqlType.SqlNumeric; +import com.microsoft.sqlserver.testframework.sqlType.SqlReal; +import com.microsoft.sqlserver.testframework.sqlType.SqlSmallDateTime; +import com.microsoft.sqlserver.testframework.sqlType.SqlSmallInt; +import com.microsoft.sqlserver.testframework.sqlType.SqlSmallMoney; +import com.microsoft.sqlserver.testframework.sqlType.SqlTime; +import com.microsoft.sqlserver.testframework.sqlType.SqlTinyInt; +import com.microsoft.sqlserver.testframework.sqlType.SqlType; +import com.microsoft.sqlserver.testframework.sqlType.SqlVarBinary; +import com.microsoft.sqlserver.testframework.sqlType.SqlVarChar; + + +/** + * Collection of SqlType used to create table in {@link DBTable} + * + * @author Microsoft + * + */ +public class DBSchema { + + private List sqlTypes; + + /** + * + * @param autoGenerateSchema + */ + DBSchema(boolean autoGenerateSchema) { + sqlTypes = new ArrayList<>(); + if (autoGenerateSchema) { + // Exact Numeric + sqlTypes.add(new SqlBigInt()); + sqlTypes.add(new SqlInt()); + sqlTypes.add(new SqlSmallInt()); + sqlTypes.add(new SqlTinyInt()); + sqlTypes.add(new SqlBit()); + sqlTypes.add(new SqlDecimal()); + sqlTypes.add(new SqlNumeric()); + sqlTypes.add(new SqlMoney()); + sqlTypes.add(new SqlSmallMoney()); + // Appx Numeric + sqlTypes.add(new SqlFloat()); + sqlTypes.add(new SqlReal()); + // Character + sqlTypes.add(new SqlChar()); + sqlTypes.add(new SqlVarChar()); + // Unicode + sqlTypes.add(new SqlNChar()); + sqlTypes.add(new SqlNVarChar()); + // Temporal + sqlTypes.add(new SqlDateTime()); + sqlTypes.add(new SqlDate()); + sqlTypes.add(new SqlTime()); + sqlTypes.add(new SqlSmallDateTime()); + sqlTypes.add(new SqlDateTime2()); + sqlTypes.add(new SqlDateTimeOffset()); + // Binary + sqlTypes.add(new SqlBinary()); + sqlTypes.add(new SqlVarBinary()); + + // TODO: + // Other types + } + } + + /** + * + * @param autoGenerateSchema + * @param alternateSchema + */ + DBSchema(boolean autoGenerateSchema, boolean alternateSchema) { + this(autoGenerateSchema); + if (alternateSchema) { + Collections.shuffle(this.sqlTypes); + } + } + + /** + * + * @param index + * @return + */ + SqlType getSqlType(int index) { + return sqlTypes.get(index); + } + + /** + * + * @param sqlType + */ + void addSqlTpe(SqlType sqlType) { + sqlTypes.add(sqlType); + } + + /** + * + * @return number of sqlTypes in the schema object + */ + int getNumberOfSqlTypes() { + return sqlTypes.size(); + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBStatement.java b/src/test/java/com/microsoft/sqlserver/testframework/DBStatement.java index d047ac873..0752d2de9 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBStatement.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBStatement.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.testframework; @@ -14,13 +11,14 @@ import com.microsoft.sqlserver.jdbc.SQLServerConnection; + /** * wrapper method for Statement object * * @author Microsoft * */ -public class DBStatement extends AbstractParentWrapper implements AutoCloseable{ +public class DBStatement extends AbstractParentWrapper implements AutoCloseable { // TODO: support PreparedStatement and CallableStatement // TODO: add stmt level holdability @@ -51,8 +49,7 @@ DBStatement createStatement() throws SQLException { return this; } - DBStatement createStatement(int type, - int concurrency) throws SQLException { + DBStatement createStatement(int type, int concurrency) throws SQLException { // TODO: add cursor and holdability statement = ((SQLServerConnection) parent().product()).createStatement(type, concurrency); setInternal(statement); @@ -62,7 +59,7 @@ DBStatement createStatement(int type, /** * * @param sql - * query to execute + * query to execute * @return DBResultSet * @throws SQLException */ @@ -90,7 +87,7 @@ public DBResultSet selectAll(DBTable table) throws SQLException { /** * * @param sql - * query to execute + * query to execute * @return true if ResultSet is returned * @throws SQLException */ @@ -119,7 +116,7 @@ public void close() throws SQLException { if ((null != dbresultSet) && null != ((ResultSet) dbresultSet.product())) { ((ResultSet) dbresultSet.product()).close(); } - //statement.close(); + // statement.close(); } /** @@ -183,4 +180,4 @@ public DBResultSet getResultSet() throws SQLException { ResultSet rs = ((Statement) product()).getResultSet(); return dbresultSet = new DBResultSet(this, rs); } -} \ No newline at end of file +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java b/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java index 4ec2b7974..a61b86096 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/DBTable.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.testframework; @@ -23,6 +20,7 @@ import com.microsoft.sqlserver.testframework.sqlType.VariableLengthType; import com.microsoft.sqlserver.testframework.util.RandomUtil; + /** * This class holds data for Table. */ @@ -41,7 +39,7 @@ public class DBTable extends AbstractSQLGenerator { * Initializes {@link DBTable} with tableName, schema, and {@link DBColumns} * * @param autoGenerateSchema - * true : generates schema with all available dataTypes in SqlType class + * true : generates schema with all available dataTypes in SqlType class */ public DBTable(boolean autoGenerateSchema) { this(autoGenerateSchema, false, false); @@ -51,12 +49,11 @@ public DBTable(boolean autoGenerateSchema) { * Initializes {@link DBTable} with tableName, schema, and {@link DBColumns} * * @param autoGenerateSchema - * true: generates schema with all available dataTypes in SqlType class + * true: generates schema with all available dataTypes in SqlType class * @param unicode - * true: sets unicode column names if autoGenerateSchema is also set to true + * true: sets unicode column names if autoGenerateSchema is also set to true */ - public DBTable(boolean autoGenerateSchema, - boolean unicode) { + public DBTable(boolean autoGenerateSchema, boolean unicode) { this(autoGenerateSchema, unicode, false); } @@ -64,15 +61,13 @@ public DBTable(boolean autoGenerateSchema, * Initializes {@link DBTable} with tableName, schema, and {@link DBColumns} * * @param autoGenerateSchema - * true: generates schema with all available dataTypes in SqlType class + * true: generates schema with all available dataTypes in SqlType class * @param unicode - * true: sets unicode column names if autoGenerateSchema is also set to true + * true: sets unicode column names if autoGenerateSchema is also set to true * @param alternateShcema - * true: creates table with alternate schema + * true: creates table with alternate schema */ - public DBTable(boolean autoGenerateSchema, - boolean unicode, - boolean alternateSchema) { + public DBTable(boolean autoGenerateSchema, boolean unicode, boolean alternateSchema) { this.tableName = RandomUtil.getIdentifier("table"); this.escapedTableName = escapeIdentifier(tableName); @@ -82,8 +77,7 @@ public DBTable(boolean autoGenerateSchema, addColumns(unicode); else addColumns(); - } - else { + } else { this.columns = new ArrayList<>(); } this.totalColumns = columns.size(); @@ -171,7 +165,7 @@ public int getTotalRows() { /** * * @param totalRows - * set the number of rows in table, default value is 3 + * set the number of rows in table, default value is 3 */ public void setTotalRows(int totalRows) { this.totalRows = totalRows; @@ -187,8 +181,7 @@ boolean createTable(DBStatement dbstatement) { dropTable(dbstatement); String sql = createTableSql(); return dbstatement.execute(sql); - } - catch (SQLException ex) { + } catch (SQLException ex) { fail(ex.getMessage()); } return false; @@ -211,15 +204,13 @@ String createTableSql() { sbDefinition.add(OPEN_BRACKET); sbDefinition.add("" + column.getSqlType().getPrecision()); sbDefinition.add(CLOSE_BRACKET); - } - else if (VariableLengthType.Scale == column.getSqlType().getVariableLengthType()) { + } else if (VariableLengthType.Scale == column.getSqlType().getVariableLengthType()) { sbDefinition.add(OPEN_BRACKET); sbDefinition.add("" + column.getSqlType().getPrecision()); sbDefinition.add(COMMA); sbDefinition.add("" + column.getSqlType().getScale()); sbDefinition.add(CLOSE_BRACKET); - } - else if (VariableLengthType.ScaleOnly == column.getSqlType().getVariableLengthType()) { + } else if (VariableLengthType.ScaleOnly == column.getSqlType().getVariableLengthType()) { sbDefinition.add(OPEN_BRACKET); sbDefinition.add("" + column.getSqlType().getScale()); sbDefinition.add(CLOSE_BRACKET); @@ -249,8 +240,7 @@ boolean populateTable(DBStatement dbstatement) { populateValues(); String sql = populateTableSql(); return dbstatement.execute(sql); - } - catch (SQLException ex) { + } catch (SQLException ex) { fail(ex.getMessage()); } return false; @@ -289,9 +279,9 @@ boolean populateTableWithPreparedStatement(DBPreparedStatement dbPStmt) { for (int i = 0; i < totalRows; i++) { for (int colNum = 0; colNum < totalColumns; colNum++) { if (passDataAsHex(colNum)) { - ((PreparedStatement) dbPStmt.product()).setBytes(colNum + 1, ((byte[]) (getColumn(colNum).getRowValue(i)))); - } - else { + ((PreparedStatement) dbPStmt.product()).setBytes(colNum + 1, + ((byte[]) (getColumn(colNum).getRowValue(i)))); + } else { dbPStmt.setObject(colNum + 1, String.valueOf(getColumn(colNum).getRowValue(i))); } } @@ -299,8 +289,7 @@ boolean populateTableWithPreparedStatement(DBPreparedStatement dbPStmt) { } return true; - } - catch (SQLException ex) { + } catch (SQLException ex) { fail(ex.getMessage()); } return false; @@ -358,11 +347,9 @@ String populateTableSql() { // TODO: consider how to enclose data in case of preparedStatemets if (passDataAsString(colNum)) { sb.add("'" + String.valueOf(getColumn(colNum).getRowValue(i)) + "'"); - } - else if (passDataAsHex(colNum)) { + } else if (passDataAsHex(colNum)) { sb.add("0X" + byteArrayToHex((byte[]) (getColumn(colNum).getRowValue(i)))); - } - else { + } else { sb.add(String.valueOf(getColumn(colNum).getRowValue(i))); } @@ -389,12 +376,10 @@ boolean dropTable(DBStatement dbstatement) { result = dbstatement.execute(sql); if (log.isLoggable(Level.FINE)) { log.fine("Table Deleted " + tableName); - } - else { + } else { log.fine("Table did not exist : " + tableName); } - } - catch (SQLException ex) { + } catch (SQLException ex) { fail(ex.getMessage()); } return result; @@ -444,8 +429,7 @@ DBColumn getColumn(int index) { * @param rowIndex * @return */ - public Object getRowData(int colIndex, - int rowIndex) { + public Object getRowData(int colIndex, int rowIndex) { return columns.get(colIndex).getRowValue(rowIndex); } @@ -471,11 +455,11 @@ boolean passDataAsHex(int colNum) { JDBCType jt = getColumn(colNum).getJdbctype(); return (JDBCType.BINARY == jt || JDBCType.VARBINARY == jt || JDBCType.LONGVARBINARY == jt); } - + private String byteArrayToHex(byte[] a) { StringBuilder sb = new StringBuilder(a.length * 2); - for(byte b: a) - sb.append(String.format("%02x", b)); + for (byte b : a) + sb.append(String.format("%02x", b)); return sb.toString(); - } -} \ No newline at end of file + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/PrepUtil.java b/src/test/java/com/microsoft/sqlserver/testframework/PrepUtil.java index 453b81dd9..02971234b 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/PrepUtil.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/PrepUtil.java @@ -1,57 +1,56 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) 2016 Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ -package com.microsoft.sqlserver.testframework; - -import java.sql.DriverManager; -import java.sql.SQLException; -import java.util.Properties; - -import com.microsoft.sqlserver.jdbc.SQLServerConnection; - -/** - * Utility Class for Tests. This will contains methods like Create Table, Drop Table, Initialize connection, create statement etc. logger settings - * etc. - * - * TODO : We can delete PrepUtil & move getConnection method in {@link DBEngine} - * - * @since 6.1.2 - */ -public class PrepUtil { - - private PrepUtil() { - // Just hide to restrict constructor invocation. - } - - /** - * It will create {@link SQLServerConnection} TODO : Think of AE functionality on off etc. - * - * @param connectionString - * @param info - * @return {@link SQLServerConnection} - * @throws SQLException - * @throws ClassNotFoundException - */ - public static SQLServerConnection getConnection(String connectionString, - Properties info) throws SQLException, ClassNotFoundException { - Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); - return (SQLServerConnection) DriverManager.getConnection(connectionString, info); - } - - /** - * It will create {@link SQLServerConnection} - * - * @param connectionString - * @return {@link SQLServerConnection} - * @throws SQLException - * @throws ClassNotFoundException - */ - public static SQLServerConnection getConnection(String connectionString) throws SQLException, ClassNotFoundException { - return getConnection(connectionString, null); - } - -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) 2016 Microsoft Corporation All rights reserved. This program is + * made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package com.microsoft.sqlserver.testframework; + +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Properties; + +import com.microsoft.sqlserver.jdbc.SQLServerConnection; + + +/** + * Utility Class for Tests. This will contains methods like Create Table, Drop Table, Initialize connection, create + * statement etc. logger settings etc. + * + * TODO : We can delete PrepUtil & move getConnection method in {@link DBEngine} + * + * @since 6.1.2 + */ +public class PrepUtil { + + private PrepUtil() { + // Just hide to restrict constructor invocation. + } + + /** + * It will create {@link SQLServerConnection} TODO : Think of AE functionality on off etc. + * + * @param connectionString + * @param info + * @return {@link SQLServerConnection} + * @throws SQLException + * @throws ClassNotFoundException + */ + public static SQLServerConnection getConnection(String connectionString, + Properties info) throws SQLException, ClassNotFoundException { + Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); + return (SQLServerConnection) DriverManager.getConnection(connectionString, info); + } + + /** + * It will create {@link SQLServerConnection} + * + * @param connectionString + * @return {@link SQLServerConnection} + * @throws SQLException + * @throws ClassNotFoundException + */ + public static SQLServerConnection getConnection( + String connectionString) throws SQLException, ClassNotFoundException { + return getConnection(connectionString, null); + } + +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/Utils.java b/src/test/java/com/microsoft/sqlserver/testframework/Utils.java index 56edd3f58..4b79735a5 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/Utils.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/Utils.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.testframework; @@ -51,6 +48,7 @@ import com.microsoft.sqlserver.testframework.sqlType.SqlVarChar; import com.microsoft.sqlserver.testframework.sqlType.SqlVarCharMax; + /** * Generic Utility class which we can access by test classes. * @@ -77,14 +75,11 @@ public static String getServerType() { if (null == serverTypeProperty) { // default to SQL Server serverType = SERVER_TYPE_SQL_SERVER; - } - else if (serverTypeProperty.equalsIgnoreCase(SERVER_TYPE_SQL_AZURE)) { + } else if (serverTypeProperty.equalsIgnoreCase(SERVER_TYPE_SQL_AZURE)) { serverType = SERVER_TYPE_SQL_AZURE; - } - else if (serverTypeProperty.equalsIgnoreCase(SERVER_TYPE_SQL_SERVER)) { + } else if (serverTypeProperty.equalsIgnoreCase(SERVER_TYPE_SQL_SERVER)) { serverType = SERVER_TYPE_SQL_SERVER; - } - else { + } else { if (log.isLoggable(Level.FINE)) { log.fine("Server.type '" + serverTypeProperty + "' is not supported yet. Default to SQL Server"); } @@ -115,8 +110,7 @@ public static String getConfiguredProperty(String key) { * @param key * @return Value */ - public static String getConfiguredProperty(String key, - String defaultValue) { + public static String getConfiguredProperty(String key, String defaultValue) { String value = getConfiguredProperty(key); if (value == null) { @@ -253,20 +247,19 @@ public DBNCharacterStream(String value) { super(value); } } - + /** * * @return location of resource file */ public static String getCurrentClassPath() { try { - String className = new Object() { - }.getClass().getEnclosingClass().getName(); - String location = Class.forName(className).getProtectionDomain().getCodeSource().getLocation().getPath() + "/"; + String className = new Object() {}.getClass().getEnclosingClass().getName(); + String location = Class.forName(className).getProtectionDomain().getCodeSource().getLocation().getPath() + + "/"; URI uri = new URI(location.toString()); return uri.getPath(); - } - catch (Exception e) { + } catch (Exception e) { fail("Failed to get CSV file path. " + e.getMessage()); } return null; @@ -286,54 +279,53 @@ public static void dropProcedureIfExists(String procName, java.sql.Statement stm dropObjectIfExists(procName, "IsProcedure", stmt); } - public static void dropDatabaseIfExists(String databaseName, - java.sql.Statement stmt) throws SQLException { - stmt.executeUpdate("USE MASTER; IF EXISTS(SELECT * from sys.databases WHERE name='" + databaseName + "') DROP DATABASE [" + databaseName + "]"); + public static void dropDatabaseIfExists(String databaseName, java.sql.Statement stmt) throws SQLException { + stmt.executeUpdate("USE MASTER; IF EXISTS(SELECT * from sys.databases WHERE name='" + databaseName + + "') DROP DATABASE [" + databaseName + "]"); } /** * actually perform the "DROP TABLE / PROCEDURE" */ - private static void dropObjectIfExists(String objectName, String objectProperty, java.sql.Statement stmt) throws SQLException { + private static void dropObjectIfExists(String objectName, String objectProperty, + java.sql.Statement stmt) throws SQLException { StringBuilder sb = new StringBuilder(); - if (!objectName.startsWith("[")) { sb.append("["); } + if (!objectName.startsWith("[")) { + sb.append("["); + } sb.append(objectName); - if (!objectName.endsWith("]")) { sb.append("]"); } + if (!objectName.endsWith("]")) { + sb.append("]"); + } String bracketedObjectName = sb.toString(); - String sql = String.format( - "IF EXISTS " + - "( " + - "SELECT * from sys.objects " + - "WHERE object_id = OBJECT_ID(N'%s') AND OBJECTPROPERTY(object_id, N'%s') = 1 " + - ") " + - "DROP %s %s ", - bracketedObjectName, - objectProperty, - "IsProcedure".equals(objectProperty) ? "PROCEDURE" : "TABLE", + String sql = String.format("IF EXISTS " + "( " + "SELECT * from sys.objects " + + "WHERE object_id = OBJECT_ID(N'%s') AND OBJECTPROPERTY(object_id, N'%s') = 1 " + ") " + "DROP %s %s ", + bracketedObjectName, objectProperty, "IsProcedure".equals(objectProperty) ? "PROCEDURE" : "TABLE", bracketedObjectName); stmt.executeUpdate(sql); } - public static boolean parseByte(byte[] expectedData, - byte[] retrieved) { - assertTrue(Arrays.equals(expectedData, Arrays.copyOf(retrieved, expectedData.length)), " unexpected BINARY value, expected"); + public static boolean parseByte(byte[] expectedData, byte[] retrieved) { + assertTrue(Arrays.equals(expectedData, Arrays.copyOf(retrieved, expectedData.length)), + " unexpected BINARY value, expected"); for (int i = expectedData.length; i < retrieved.length; i++) { assertTrue(0 == retrieved[i], "unexpected data BINARY"); } return true; } - - public static boolean isJDBC43OrGreater(Connection connection) throws SQLException{ + + public static boolean isJDBC43OrGreater(Connection connection) throws SQLException { return getJDBCVersion(connection) >= 4.3F; } public static float getJDBCVersion(Connection connection) throws SQLException { - return Float.valueOf(connection.getMetaData().getJDBCMajorVersion() + "." + connection.getMetaData().getJDBCMinorVersion()); + return Float.valueOf( + connection.getMetaData().getJDBCMajorVersion() + "." + connection.getMetaData().getJDBCMinorVersion()); } public static boolean serverSupportsUTF8(Connection connection) throws SQLException { - try (Statement stmt = connection.createStatement(); - ResultSet rs = stmt.executeQuery("SELECT name FROM sys.fn_helpcollations() WHERE name LIKE '%UTF8%'");) { + try (Statement stmt = connection.createStatement(); ResultSet rs = stmt + .executeQuery("SELECT name FROM sys.fn_helpcollations() WHERE name LIKE '%UTF8%'");) { return rs.isBeforeFirst(); } } diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlBigInt.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlBigInt.java index 84126f5da..6219cb84b 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlBigInt.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlBigInt.java @@ -1,27 +1,25 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework.sqlType; - -import java.sql.JDBCType; -import java.util.concurrent.ThreadLocalRandom; - -public class SqlBigInt extends SqlNumber { - - public SqlBigInt() { - super("bigint", JDBCType.BIGINT, 19, 0, SqlTypeValue.BIGINT.minValue, SqlTypeValue.BIGINT.maxValue, SqlTypeValue.BIGINT.nullValue, - VariableLengthType.Fixed, Long.class); - flags.set(PRIMITIVE); - - } - - public Object createdata() { - // TODO: include max value - return ThreadLocalRandom.current().nextLong(Long.MIN_VALUE, Long.MAX_VALUE); - } -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework.sqlType; + +import java.sql.JDBCType; +import java.util.concurrent.ThreadLocalRandom; + + +public class SqlBigInt extends SqlNumber { + + public SqlBigInt() { + super("bigint", JDBCType.BIGINT, 19, 0, SqlTypeValue.BIGINT.minValue, SqlTypeValue.BIGINT.maxValue, + SqlTypeValue.BIGINT.nullValue, VariableLengthType.Fixed, Long.class); + flags.set(PRIMITIVE); + + } + + public Object createdata() { + // TODO: include max value + return ThreadLocalRandom.current().nextLong(Long.MIN_VALUE, Long.MAX_VALUE); + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlBinary.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlBinary.java index 2041733bb..12fef8180 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlBinary.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlBinary.java @@ -1,51 +1,47 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework.sqlType; - -import java.sql.JDBCType; -import java.util.concurrent.ThreadLocalRandom; - -/** - * Contains name, jdbctype, precision, scale for binary data type - */ -public class SqlBinary extends SqlType { - - /** - * set JDBCType and precision for SqlBinary - */ - public SqlBinary() { - this("binary", JDBCType.BINARY, 2000); - } - - /** - * - * @param name - * binary or varbinary - * @param jdbctype - * @param precision - */ - SqlBinary(String name, - JDBCType jdbctype, - int precision) { - super(name, jdbctype, precision, 0, SqlTypeValue.BINARY.minValue, SqlTypeValue.BINARY.maxValue, SqlTypeValue.BINARY.nullValue, - VariableLengthType.Precision, byte[].class); - flags.set(FIXED); - generatePrecision(); - } - - /** - * create random data for binary and varbinary column - */ - public Object createdata() { - int dataLength = ThreadLocalRandom.current().nextInt(precision); - byte[] bytes = new byte[dataLength]; - ThreadLocalRandom.current().nextBytes(bytes); - return bytes; - } -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework.sqlType; + +import java.sql.JDBCType; +import java.util.concurrent.ThreadLocalRandom; + + +/** + * Contains name, jdbctype, precision, scale for binary data type + */ +public class SqlBinary extends SqlType { + + /** + * set JDBCType and precision for SqlBinary + */ + public SqlBinary() { + this("binary", JDBCType.BINARY, 2000); + } + + /** + * + * @param name + * binary or varbinary + * @param jdbctype + * @param precision + */ + SqlBinary(String name, JDBCType jdbctype, int precision) { + super(name, jdbctype, precision, 0, SqlTypeValue.BINARY.minValue, SqlTypeValue.BINARY.maxValue, + SqlTypeValue.BINARY.nullValue, VariableLengthType.Precision, byte[].class); + flags.set(FIXED); + generatePrecision(); + } + + /** + * create random data for binary and varbinary column + */ + public Object createdata() { + int dataLength = ThreadLocalRandom.current().nextInt(precision); + byte[] bytes = new byte[dataLength]; + ThreadLocalRandom.current().nextBytes(bytes); + return bytes; + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlBit.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlBit.java index 54cf4a6e5..a77fd578a 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlBit.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlBit.java @@ -1,24 +1,22 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework.sqlType; - -import java.sql.JDBCType; -import java.util.concurrent.ThreadLocalRandom; - -public class SqlBit extends SqlType { - - public SqlBit() { - super("bit", JDBCType.BIT, 1, 0, SqlTypeValue.BIT.minValue, SqlTypeValue.BIT.maxValue, SqlTypeValue.BIT.nullValue, VariableLengthType.Fixed, - Boolean.class); - } - - public Object createdata() { - return ((0 == ThreadLocalRandom.current().nextInt(2)) ? minvalue : maxvalue); - } -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework.sqlType; + +import java.sql.JDBCType; +import java.util.concurrent.ThreadLocalRandom; + + +public class SqlBit extends SqlType { + + public SqlBit() { + super("bit", JDBCType.BIT, 1, 0, SqlTypeValue.BIT.minValue, SqlTypeValue.BIT.maxValue, + SqlTypeValue.BIT.nullValue, VariableLengthType.Fixed, Boolean.class); + } + + public Object createdata() { + return ((0 == ThreadLocalRandom.current().nextInt(2)) ? minvalue : maxvalue); + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlChar.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlChar.java index 6e985e47e..3a0772c54 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlChar.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlChar.java @@ -1,81 +1,78 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework.sqlType; - -import java.sql.JDBCType; -import java.util.concurrent.ThreadLocalRandom; - -import com.microsoft.sqlserver.testframework.DBCoercion; -import com.microsoft.sqlserver.testframework.Utils; - -/* - * Restricting the size of char/binary to 2000 and nchar to 1000 to accommodate SQL Sever limitation of having of having maximum allowable table row - * size to 8060 - */ -public class SqlChar extends SqlType { - - private static String normalCharSet = "1234567890-=!@#$%^&*()_+qwertyuiop[]\\asdfghjkl;zxcvbnm,./QWERTYUIOP{}|ASDFGHJKL:\"ZXCVBNM<>?"; - - public SqlChar() { - this("char", JDBCType.CHAR, 2000); - } - - SqlChar(String name, - JDBCType jdbctype, - int precision) { - super(name, jdbctype, precision, 0, SqlTypeValue.CHAR.minValue, SqlTypeValue.CHAR.maxValue, SqlTypeValue.CHAR.nullValue, - VariableLengthType.Precision, String.class); - generatePrecision(); - coercions.add(new DBCoercion(Object.class, new int[] {DBCoercion.GET, DBCoercion.UPDATE, DBCoercion.UPDATEOBJECT, DBCoercion.SET, - DBCoercion.SETOBJECT, DBCoercion.GETPARAM, DBCoercion.REG})); - coercions.add(new DBCoercion(String.class, new int[] {DBCoercion.GET, DBCoercion.UPDATE, DBCoercion.UPDATEOBJECT, DBCoercion.SET, - DBCoercion.SETOBJECT, DBCoercion.GETPARAM, DBCoercion.REG, DBCoercion.CHAR})); - coercions.add(new DBCoercion(Utils.DBCharacterStream.class, new int[] {DBCoercion.GET, DBCoercion.UPDATE, DBCoercion.UPDATEOBJECT, - DBCoercion.SET, DBCoercion.SETOBJECT, DBCoercion.GETPARAM, DBCoercion.REG, DBCoercion.STREAM, DBCoercion.CHAR})); - } - - public Object createdata() { - int dataLength = ThreadLocalRandom.current().nextInt(precision); - return generateCharTypes(dataLength); - } - - private static String generateCharTypes(int columnLength) { - String charSet = normalCharSet; - return buildCharOrNChar(columnLength, charSet); - } - - /** - * generate char or nchar values - * - * @param columnLength - * @param charSet - * @return - */ - protected static String buildCharOrNChar(int columnLength, - String charSet) { - int columnLengthInt = columnLength; - return buildRandomString(columnLengthInt, charSet); - } - - private static String buildRandomString(int length, - String charSet) { - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < length; i++) { - char c = pickRandomChar(charSet); - sb.append(c); - } - return sb.toString(); - } - - private static char pickRandomChar(String charSet) { - int charSetLength = charSet.length(); - int randomIndex = ThreadLocalRandom.current().nextInt(charSetLength); - return charSet.charAt(randomIndex); - } -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework.sqlType; + +import java.sql.JDBCType; +import java.util.concurrent.ThreadLocalRandom; + +import com.microsoft.sqlserver.testframework.DBCoercion; +import com.microsoft.sqlserver.testframework.Utils; + + +/* + * Restricting the size of char/binary to 2000 and nchar to 1000 to accommodate SQL Sever limitation of having of having + * maximum allowable table row size to 8060 + */ +public class SqlChar extends SqlType { + + private static String normalCharSet = "1234567890-=!@#$%^&*()_+qwertyuiop[]\\asdfghjkl;zxcvbnm,./QWERTYUIOP{}|ASDFGHJKL:\"ZXCVBNM<>?"; + + public SqlChar() { + this("char", JDBCType.CHAR, 2000); + } + + SqlChar(String name, JDBCType jdbctype, int precision) { + super(name, jdbctype, precision, 0, SqlTypeValue.CHAR.minValue, SqlTypeValue.CHAR.maxValue, + SqlTypeValue.CHAR.nullValue, VariableLengthType.Precision, String.class); + generatePrecision(); + coercions.add(new DBCoercion(Object.class, new int[] {DBCoercion.GET, DBCoercion.UPDATE, + DBCoercion.UPDATEOBJECT, DBCoercion.SET, DBCoercion.SETOBJECT, DBCoercion.GETPARAM, DBCoercion.REG})); + coercions + .add(new DBCoercion(String.class, new int[] {DBCoercion.GET, DBCoercion.UPDATE, DBCoercion.UPDATEOBJECT, + DBCoercion.SET, DBCoercion.SETOBJECT, DBCoercion.GETPARAM, DBCoercion.REG, DBCoercion.CHAR})); + coercions.add(new DBCoercion(Utils.DBCharacterStream.class, + new int[] {DBCoercion.GET, DBCoercion.UPDATE, DBCoercion.UPDATEOBJECT, DBCoercion.SET, + DBCoercion.SETOBJECT, DBCoercion.GETPARAM, DBCoercion.REG, DBCoercion.STREAM, + DBCoercion.CHAR})); + } + + public Object createdata() { + int dataLength = ThreadLocalRandom.current().nextInt(precision); + return generateCharTypes(dataLength); + } + + private static String generateCharTypes(int columnLength) { + String charSet = normalCharSet; + return buildCharOrNChar(columnLength, charSet); + } + + /** + * generate char or nchar values + * + * @param columnLength + * @param charSet + * @return + */ + protected static String buildCharOrNChar(int columnLength, String charSet) { + int columnLengthInt = columnLength; + return buildRandomString(columnLengthInt, charSet); + } + + private static String buildRandomString(int length, String charSet) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < length; i++) { + char c = pickRandomChar(charSet); + sb.append(c); + } + return sb.toString(); + } + + private static char pickRandomChar(String charSet) { + int charSetLength = charSet.length(); + int randomIndex = ThreadLocalRandom.current().nextInt(charSetLength); + return charSet.charAt(randomIndex); + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlDate.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlDate.java index cf6755330..467672b04 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlDate.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlDate.java @@ -1,38 +1,35 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework.sqlType; - -import static org.junit.jupiter.api.Assertions.fail; - -import java.sql.Date; -import java.sql.JDBCType; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.concurrent.ThreadLocalRandom; - -public class SqlDate extends SqlDateTime { - - static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); - - public SqlDate() { - super("date", JDBCType.DATE, null, null); - type = java.sql.Date.class; - try { - minvalue = new Date(dateFormat.parse((String) SqlTypeValue.DATE.minValue).getTime()); - maxvalue = new Date(dateFormat.parse((String) SqlTypeValue.DATE.maxValue).getTime()); - } - catch (ParseException ex) { - fail(ex.getMessage()); - } - } - - public Object createdata() { - return new Date(ThreadLocalRandom.current().nextLong(((Date) minvalue).getTime(), ((Date) maxvalue).getTime())); - } -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework.sqlType; + +import static org.junit.jupiter.api.Assertions.fail; + +import java.sql.Date; +import java.sql.JDBCType; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.concurrent.ThreadLocalRandom; + + +public class SqlDate extends SqlDateTime { + + static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); + + public SqlDate() { + super("date", JDBCType.DATE, null, null); + type = java.sql.Date.class; + try { + minvalue = new Date(dateFormat.parse((String) SqlTypeValue.DATE.minValue).getTime()); + maxvalue = new Date(dateFormat.parse((String) SqlTypeValue.DATE.maxValue).getTime()); + } catch (ParseException ex) { + fail(ex.getMessage()); + } + } + + public Object createdata() { + return new Date(ThreadLocalRandom.current().nextLong(((Date) minvalue).getTime(), ((Date) maxvalue).getTime())); + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlDateTime.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlDateTime.java index dc5e79e2f..613feba9e 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlDateTime.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlDateTime.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.testframework.sqlType; @@ -17,6 +14,7 @@ import java.util.Random; import java.util.concurrent.ThreadLocalRandom; + public class SqlDateTime extends SqlType { static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss.SSS"); @@ -26,29 +24,28 @@ public SqlDateTime() { try { minvalue = new Timestamp(dateFormat.parse((String) SqlTypeValue.DATETIME.minValue).getTime()); maxvalue = new Timestamp(dateFormat.parse((String) SqlTypeValue.DATETIME.maxValue).getTime()); - } - catch (ParseException ex) { + } catch (ParseException ex) { fail(ex.getMessage()); } } - SqlDateTime(String name, - JDBCType jdbctype, - Object min, - Object max) { - super(name, jdbctype, 0, 0, min, max, SqlTypeValue.DATETIME.nullValue, VariableLengthType.Fixed, java.sql.Timestamp.class); + SqlDateTime(String name, JDBCType jdbctype, Object min, Object max) { + super(name, jdbctype, 0, 0, min, max, SqlTypeValue.DATETIME.nullValue, VariableLengthType.Fixed, + java.sql.Timestamp.class); } public Object createdata() { - return new Timestamp(ThreadLocalRandom.current().nextLong(((Timestamp) minvalue).getTime(), ((Timestamp) maxvalue).getTime())); + return new Timestamp(ThreadLocalRandom.current().nextLong(((Timestamp) minvalue).getTime(), + ((Timestamp) maxvalue).getTime())); } - + protected int generateRandomInt(int length) { Random rnd = new Random(); int power = (int) Math.pow(10, length - 1); - - //Example of how this works: - // if length is 3, then we add 100 + random number between 0~899, so that we get a random number between 100~999. + + // Example of how this works: + // if length is 3, then we add 100 + random number between 0~899, so that we get a random number between + // 100~999. int randomNumeric; if (length <= 0) { randomNumeric = 0; @@ -57,7 +54,7 @@ protected int generateRandomInt(int length) { } else { randomNumeric = power + rnd.nextInt((int) (9 * power)); } - + return randomNumeric; } -} \ No newline at end of file +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlDateTime2.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlDateTime2.java index d953a76da..d743047e1 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlDateTime2.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlDateTime2.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.testframework.sqlType; @@ -20,6 +17,7 @@ import java.time.temporal.ChronoField; import java.util.concurrent.ThreadLocalRandom; + public class SqlDateTime2 extends SqlDateTime { static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss.SSSSSSS"); @@ -31,25 +29,26 @@ public SqlDateTime2() { try { minvalue = new Timestamp(dateFormat.parse((String) SqlTypeValue.DATETIME2.minValue).getTime()); maxvalue = new Timestamp(dateFormat.parse((String) SqlTypeValue.DATETIME2.maxValue).getTime()); - } - catch (ParseException ex) { + } catch (ParseException ex) { fail(ex.getMessage()); } this.precision = 7; this.variableLengthType = VariableLengthType.Precision; generatePrecision(); - formatter = new DateTimeFormatterBuilder().appendPattern(basePattern).appendFraction(ChronoField.NANO_OF_SECOND, 0, this.precision, true) - .toFormatter(); + formatter = new DateTimeFormatterBuilder().appendPattern(basePattern) + .appendFraction(ChronoField.NANO_OF_SECOND, 0, this.precision, true).toFormatter(); formatter = formatter.withResolverStyle(ResolverStyle.STRICT); } public Object createdata() { - Timestamp temp = new Timestamp(ThreadLocalRandom.current().nextLong(((Timestamp) minvalue).getTime(), ((Timestamp) maxvalue).getTime())); + Timestamp temp = new Timestamp(ThreadLocalRandom.current().nextLong(((Timestamp) minvalue).getTime(), + ((Timestamp) maxvalue).getTime())); temp.setNanos(0); - String timeNano = temp.toString().substring(0, temp.toString().length() - 1) + generateRandomInt(this.precision); + String timeNano = temp.toString().substring(0, temp.toString().length() - 1) + + generateRandomInt(this.precision); return timeNano; // can pass string rather than converting to LocalDateTime, but leaving // it unchanged for now to handle prepared statements -// return LocalDateTime.parse(timeNano, formatter); + // return LocalDateTime.parse(timeNano, formatter); } -} \ No newline at end of file +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlDateTimeOffset.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlDateTimeOffset.java index 3820da540..560f1e061 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlDateTimeOffset.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlDateTimeOffset.java @@ -1,159 +1,150 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ -package com.microsoft.sqlserver.testframework.sqlType; - -import java.sql.JDBCType; -import java.sql.Timestamp; -import java.util.Calendar; -import java.util.concurrent.ThreadLocalRandom; - -import microsoft.sql.DateTimeOffset; - -public class SqlDateTimeOffset extends SqlDateTime { - public static boolean returnMinMax = (0 == ThreadLocalRandom.current().nextInt(5)); // 20% chance of return Min/Max value - private static String numberCharSet2 = "123456789"; - DateTimeOffset maxDTS; - DateTimeOffset minDTS; - long max; - long min; - - // TODO: datetiemoffset can extend SqlDateTime2 - // timezone is not supported in Timestamp so its useless to initialize - // min/max with offset - public SqlDateTimeOffset() { - super("datetimeoffset", JDBCType.TIMESTAMP /* microsoft.sql.Types.DATETIMEOFFSET */, null, null); - type = microsoft.sql.DateTimeOffset.class; - minvalue = Timestamp.valueOf((String) SqlTypeValue.DATETIMEOFFSET.minValue); - maxvalue = Timestamp.valueOf((String) SqlTypeValue.DATETIMEOFFSET.maxValue); - this.precision = 7; - this.variableLengthType = VariableLengthType.Precision; - generatePrecision(); - maxDTS = calculateDateTimeOffsetMinMax("max", precision, (String) SqlTypeValue.DATETIMEOFFSET.maxValue); - minDTS = calculateDateTimeOffsetMinMax("min", precision, (String) SqlTypeValue.DATETIMEOFFSET.minValue); - - max = maxDTS.getTimestamp().getTime(); - min = minDTS.getTimestamp().getTime(); - } - - /** - * create data - */ - public Object createdata() { - return generateDatetimeoffset(this.precision); - } - - /** - * - * @param precision - * @return - */ - public Object generateDatetimeoffset(Integer precision) { - if (null == precision) { - precision = 7; - } - - Timestamp ts = generateTimestamp(max, min); - - if (null == ts) { - return null; - } - - if (returnMinMax) { - if (ThreadLocalRandom.current().nextBoolean()) { - return maxDTS; - } - else { - return minDTS; - } - } - - int precisionDigits = buildPrecision(precision, numberCharSet2); - ts.setNanos(precisionDigits); - - int randomTimeZoneInMinutes = ThreadLocalRandom.current().nextInt(1681) - 840; - - return microsoft.sql.DateTimeOffset.valueOf(ts, randomTimeZoneInMinutes); - } - - private static DateTimeOffset calculateDateTimeOffsetMinMax(String maxOrMin, - Integer precision, - String tsMinMax) { - int providedTimeZoneInMinutes; - if (maxOrMin.toLowerCase().equals("max")) { - providedTimeZoneInMinutes = 840; - } - else { - providedTimeZoneInMinutes = -840; - } - - Timestamp tsMax = Timestamp.valueOf(tsMinMax); - - Calendar cal = Calendar.getInstance(); - long offset = cal.get(Calendar.ZONE_OFFSET); // in milliseconds - - // max Timestamp + difference of current time zone and GMT - provided time zone in milliseconds - tsMax = new Timestamp(tsMax.getTime() + offset - (providedTimeZoneInMinutes * 60 * 1000)); - - if (maxOrMin.toLowerCase().equals("max")) { - int precisionDigits = buildPrecision(precision, "9"); - tsMax.setNanos(precisionDigits); - } - - return microsoft.sql.DateTimeOffset.valueOf(tsMax, providedTimeZoneInMinutes); - } - - private static int buildPrecision(int precision, - String charSet) { - String stringValue = calculatePrecisionDigits(precision, charSet); - return Integer.parseInt(stringValue); - } - - // setNanos(999999900) gives 00:00:00.9999999 - // so, this value has to be 9 digits - private static String calculatePrecisionDigits(int precision, - String charSet) { - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < precision; i++) { - char c = pickRandomChar(charSet); - sb.append(c); - } - - for (int i = sb.length(); i < 9; i++) { - sb.append("0"); - } - - return sb.toString(); - } - - private static Timestamp generateTimestamp(long max, - long min) { - - if (returnMinMax) { - if (ThreadLocalRandom.current().nextBoolean()) { - return new Timestamp(max); - } - else { - return new Timestamp(min); - } - } - - while (true) { - long longValue = ThreadLocalRandom.current().nextLong(); - - if (longValue >= min && longValue <= max) { - return new Timestamp(longValue); - } - } - } - - private static char pickRandomChar(String charSet) { - int charSetLength = charSet.length(); - int randomIndex = ThreadLocalRandom.current().nextInt(charSetLength); - return charSet.charAt(randomIndex); - } -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package com.microsoft.sqlserver.testframework.sqlType; + +import java.sql.JDBCType; +import java.sql.Timestamp; +import java.util.Calendar; +import java.util.concurrent.ThreadLocalRandom; + +import microsoft.sql.DateTimeOffset; + + +public class SqlDateTimeOffset extends SqlDateTime { + public static boolean returnMinMax = (0 == ThreadLocalRandom.current().nextInt(5)); // 20% chance of return Min/Max + // value + private static String numberCharSet2 = "123456789"; + DateTimeOffset maxDTS; + DateTimeOffset minDTS; + long max; + long min; + + // TODO: datetiemoffset can extend SqlDateTime2 + // timezone is not supported in Timestamp so its useless to initialize + // min/max with offset + public SqlDateTimeOffset() { + super("datetimeoffset", JDBCType.TIMESTAMP /* microsoft.sql.Types.DATETIMEOFFSET */, null, null); + type = microsoft.sql.DateTimeOffset.class; + minvalue = Timestamp.valueOf((String) SqlTypeValue.DATETIMEOFFSET.minValue); + maxvalue = Timestamp.valueOf((String) SqlTypeValue.DATETIMEOFFSET.maxValue); + this.precision = 7; + this.variableLengthType = VariableLengthType.Precision; + generatePrecision(); + maxDTS = calculateDateTimeOffsetMinMax("max", precision, (String) SqlTypeValue.DATETIMEOFFSET.maxValue); + minDTS = calculateDateTimeOffsetMinMax("min", precision, (String) SqlTypeValue.DATETIMEOFFSET.minValue); + + max = maxDTS.getTimestamp().getTime(); + min = minDTS.getTimestamp().getTime(); + } + + /** + * create data + */ + public Object createdata() { + return generateDatetimeoffset(this.precision); + } + + /** + * + * @param precision + * @return + */ + public Object generateDatetimeoffset(Integer precision) { + if (null == precision) { + precision = 7; + } + + Timestamp ts = generateTimestamp(max, min); + + if (null == ts) { + return null; + } + + if (returnMinMax) { + if (ThreadLocalRandom.current().nextBoolean()) { + return maxDTS; + } else { + return minDTS; + } + } + + int precisionDigits = buildPrecision(precision, numberCharSet2); + ts.setNanos(precisionDigits); + + int randomTimeZoneInMinutes = ThreadLocalRandom.current().nextInt(1681) - 840; + + return microsoft.sql.DateTimeOffset.valueOf(ts, randomTimeZoneInMinutes); + } + + private static DateTimeOffset calculateDateTimeOffsetMinMax(String maxOrMin, Integer precision, String tsMinMax) { + int providedTimeZoneInMinutes; + if (maxOrMin.toLowerCase().equals("max")) { + providedTimeZoneInMinutes = 840; + } else { + providedTimeZoneInMinutes = -840; + } + + Timestamp tsMax = Timestamp.valueOf(tsMinMax); + + Calendar cal = Calendar.getInstance(); + long offset = cal.get(Calendar.ZONE_OFFSET); // in milliseconds + + // max Timestamp + difference of current time zone and GMT - provided time zone in milliseconds + tsMax = new Timestamp(tsMax.getTime() + offset - (providedTimeZoneInMinutes * 60 * 1000)); + + if (maxOrMin.toLowerCase().equals("max")) { + int precisionDigits = buildPrecision(precision, "9"); + tsMax.setNanos(precisionDigits); + } + + return microsoft.sql.DateTimeOffset.valueOf(tsMax, providedTimeZoneInMinutes); + } + + private static int buildPrecision(int precision, String charSet) { + String stringValue = calculatePrecisionDigits(precision, charSet); + return Integer.parseInt(stringValue); + } + + // setNanos(999999900) gives 00:00:00.9999999 + // so, this value has to be 9 digits + private static String calculatePrecisionDigits(int precision, String charSet) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < precision; i++) { + char c = pickRandomChar(charSet); + sb.append(c); + } + + for (int i = sb.length(); i < 9; i++) { + sb.append("0"); + } + + return sb.toString(); + } + + private static Timestamp generateTimestamp(long max, long min) { + + if (returnMinMax) { + if (ThreadLocalRandom.current().nextBoolean()) { + return new Timestamp(max); + } else { + return new Timestamp(min); + } + } + + while (true) { + long longValue = ThreadLocalRandom.current().nextLong(); + + if (longValue >= min && longValue <= max) { + return new Timestamp(longValue); + } + } + } + + private static char pickRandomChar(String charSet) { + int charSetLength = charSet.length(); + int randomIndex = ThreadLocalRandom.current().nextInt(charSetLength); + return charSet.charAt(randomIndex); + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlDecimal.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlDecimal.java index 74acf940f..ab240b6b4 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlDecimal.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlDecimal.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.testframework.sqlType; @@ -13,6 +10,7 @@ import java.sql.JDBCType; import java.util.concurrent.ThreadLocalRandom; + public class SqlDecimal extends SqlType { // TODO:add overloaded consturtcor to avoid resetting scale and preccision @@ -21,29 +19,20 @@ public SqlDecimal() { } // called for decimal and numeric type - SqlDecimal(String name, - JDBCType jdbctype) { - this(name, jdbctype, SqlTypeValue.MAX_DECIMAL_PRECISION, 0, SqlTypeValue.DECIMAL.minValue, SqlTypeValue.DECIMAL.maxValue, VariableLengthType.Scale); + SqlDecimal(String name, JDBCType jdbctype) { + this(name, jdbctype, SqlTypeValue.MAX_DECIMAL_PRECISION, 0, SqlTypeValue.DECIMAL.minValue, + SqlTypeValue.DECIMAL.maxValue, VariableLengthType.Scale); } // called from money/smallmoney - SqlDecimal(String name, - int precision, - int scale, - Object min, - Object max, - VariableLengthType variableLengthType) { + SqlDecimal(String name, int precision, int scale, Object min, Object max, VariableLengthType variableLengthType) { this(name, JDBCType.DECIMAL, precision, scale, min, max, variableLengthType); } - SqlDecimal(String name, - JDBCType jdbctype, - int precision, - int scale, - Object min, - Object max, + SqlDecimal(String name, JDBCType jdbctype, int precision, int scale, Object min, Object max, VariableLengthType variableLengthType) { - super(name, jdbctype, precision, scale, min, max, SqlTypeValue.DECIMAL.nullValue, variableLengthType, BigDecimal.class); + super(name, jdbctype, precision, scale, min, max, SqlTypeValue.DECIMAL.nullValue, variableLengthType, + BigDecimal.class); // update random precision and scale generatePrecision(); @@ -65,22 +54,23 @@ public Object createdata() { double lowerBound = 0; double upperBound = 1; /** - * value to add for Math.random() to include upperBound - to choose random value between 0 to 1 (inclusive of both) + * value to add for Math.random() to include upperBound - to choose random value between 0 to 1 (inclusive of + * both) */ double incrementValue = 0.1d; Boolean inValidData = true; BigDecimal randomValue = null; while (inValidData) { - randomValue = new BigDecimal(ThreadLocalRandom.current().nextDouble(lowerBound, upperBound + incrementValue)); + randomValue = new BigDecimal( + ThreadLocalRandom.current().nextDouble(lowerBound, upperBound + incrementValue)); Boolean isNegative = (0 == ThreadLocalRandom.current().nextInt(2)) ? true : false; // Restrict the BigInteger to the length of precision // i.e., if the precision is say 5, then get unscaledRandom%10^5 if (randomValue.compareTo(new BigDecimal("1")) >= 0) { randomValue = randomValue.movePointRight(precision - scale - 1); - } - else { + } else { randomValue = randomValue.movePointRight(precision - scale); } randomValue = randomValue.setScale(scale, RoundingMode.FLOOR); @@ -102,4 +92,4 @@ public Object createdata() { return randomValue; } -} \ No newline at end of file +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlFloat.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlFloat.java index a2216d0e9..f1881406f 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlFloat.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlFloat.java @@ -1,43 +1,38 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework.sqlType; - -import java.sql.JDBCType; -import java.util.concurrent.ThreadLocalRandom; - -public class SqlFloat extends SqlType { - - // called from real - SqlFloat(String name, - JDBCType jdbctype, - int precision, - Object min, - Object max, - Object nullvalue, - VariableLengthType variableLengthType, - Class type) { - super(name, jdbctype, precision, 0, min, max, nullvalue, variableLengthType, type); - generatePrecision(); - } - - public SqlFloat() { - super("float", JDBCType.DOUBLE, 53, 0, SqlTypeValue.FLOAT.minValue, SqlTypeValue.FLOAT.maxValue, SqlTypeValue.FLOAT.nullValue, - VariableLengthType.Precision, Double.class); - generatePrecision(); - } - - public Object createdata() { - // for float in SQL Server, any precision <=24 is considered as real so the value must be within SqlTypeValue.REAL.minValue/maxValue - if (precision > 24) - return Double.longBitsToDouble(ThreadLocalRandom.current().nextLong(((Double) minvalue).longValue(), ((Double) maxvalue).longValue())); - else { - return ThreadLocalRandom.current().nextDouble((Float) SqlTypeValue.REAL.minValue, (Float) SqlTypeValue.REAL.maxValue); - } - } -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework.sqlType; + +import java.sql.JDBCType; +import java.util.concurrent.ThreadLocalRandom; + + +public class SqlFloat extends SqlType { + + // called from real + SqlFloat(String name, JDBCType jdbctype, int precision, Object min, Object max, Object nullvalue, + VariableLengthType variableLengthType, Class type) { + super(name, jdbctype, precision, 0, min, max, nullvalue, variableLengthType, type); + generatePrecision(); + } + + public SqlFloat() { + super("float", JDBCType.DOUBLE, 53, 0, SqlTypeValue.FLOAT.minValue, SqlTypeValue.FLOAT.maxValue, + SqlTypeValue.FLOAT.nullValue, VariableLengthType.Precision, Double.class); + generatePrecision(); + } + + public Object createdata() { + // for float in SQL Server, any precision <=24 is considered as real so the value must be within + // SqlTypeValue.REAL.minValue/maxValue + if (precision > 24) + return Double.longBitsToDouble(ThreadLocalRandom.current().nextLong(((Double) minvalue).longValue(), + ((Double) maxvalue).longValue())); + else { + return ThreadLocalRandom.current().nextDouble((Float) SqlTypeValue.REAL.minValue, + (Float) SqlTypeValue.REAL.maxValue); + } + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlInt.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlInt.java index 2622f0745..20b1fb713 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlInt.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlInt.java @@ -1,26 +1,24 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework.sqlType; - -import java.sql.JDBCType; -import java.util.concurrent.ThreadLocalRandom;; - -public class SqlInt extends SqlNumber { - - public SqlInt() { - super("int", JDBCType.INTEGER, 10, 0, SqlTypeValue.INTEGER.minValue, SqlTypeValue.INTEGER.maxValue, SqlTypeValue.INTEGER.nullValue, - VariableLengthType.Fixed, Integer.class); - - } - - public Object createdata() { - // TODO: include max value - return ThreadLocalRandom.current().nextInt(Integer.MIN_VALUE, Integer.MAX_VALUE); - } -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework.sqlType; + +import java.sql.JDBCType; +import java.util.concurrent.ThreadLocalRandom;; + + +public class SqlInt extends SqlNumber { + + public SqlInt() { + super("int", JDBCType.INTEGER, 10, 0, SqlTypeValue.INTEGER.minValue, SqlTypeValue.INTEGER.maxValue, + SqlTypeValue.INTEGER.nullValue, VariableLengthType.Fixed, Integer.class); + + } + + public Object createdata() { + // TODO: include max value + return ThreadLocalRandom.current().nextInt(Integer.MIN_VALUE, Integer.MAX_VALUE); + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlMoney.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlMoney.java index c9e2bccc6..71ebf40ff 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlMoney.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlMoney.java @@ -1,16 +1,13 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework.sqlType; - -public class SqlMoney extends SqlDecimal { - - public SqlMoney() { - super("money", 19, 4, SqlTypeValue.MONEY.minValue, SqlTypeValue.MONEY.maxValue, VariableLengthType.Fixed); - } -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework.sqlType; + +public class SqlMoney extends SqlDecimal { + + public SqlMoney() { + super("money", 19, 4, SqlTypeValue.MONEY.minValue, SqlTypeValue.MONEY.maxValue, VariableLengthType.Fixed); + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNChar.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNChar.java index b156111c7..c7fc8fbdf 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNChar.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNChar.java @@ -1,36 +1,32 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework.sqlType; - -import java.sql.JDBCType; -import java.util.concurrent.ThreadLocalRandom; - -public class SqlNChar extends SqlChar { - private static String normalCharSet = "1234567890-=!@#$%^&*()_+qwertyuiop[]\\asdfghjkl;zxcvbnm,./QWERTYUIOP{}|ASDFGHJKL:\"ZXCVBNM<>?"; - - SqlNChar(String name, - JDBCType jdbctype, - int precision) { - super(name, jdbctype, precision); - } - - public SqlNChar() { - this("nchar", JDBCType.NCHAR, 1000); - } - - public Object createdata() { - int dataLength = ThreadLocalRandom.current().nextInt(precision); - return generateCharTypes(dataLength); - } - - private static String generateCharTypes(int columnLength) { - String charSet = normalCharSet; - return buildCharOrNChar(columnLength, charSet); - } -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework.sqlType; + +import java.sql.JDBCType; +import java.util.concurrent.ThreadLocalRandom; + + +public class SqlNChar extends SqlChar { + private static String normalCharSet = "1234567890-=!@#$%^&*()_+qwertyuiop[]\\asdfghjkl;zxcvbnm,./QWERTYUIOP{}|ASDFGHJKL:\"ZXCVBNM<>?"; + + SqlNChar(String name, JDBCType jdbctype, int precision) { + super(name, jdbctype, precision); + } + + public SqlNChar() { + this("nchar", JDBCType.NCHAR, 1000); + } + + public Object createdata() { + int dataLength = ThreadLocalRandom.current().nextInt(precision); + return generateCharTypes(dataLength); + } + + private static String generateCharTypes(int columnLength) { + String charSet = normalCharSet; + return buildCharOrNChar(columnLength, charSet); + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNVarChar.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNVarChar.java index 8a3314fb0..e0e174ee4 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNVarChar.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNVarChar.java @@ -1,18 +1,16 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework.sqlType; - -import java.sql.JDBCType; - -public class SqlNVarChar extends SqlNChar { - - public SqlNVarChar() { - super("nvarchar", JDBCType.NVARCHAR, 2000); - } -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework.sqlType; + +import java.sql.JDBCType; + + +public class SqlNVarChar extends SqlNChar { + + public SqlNVarChar() { + super("nvarchar", JDBCType.NVARCHAR, 2000); + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNVarCharMax.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNVarCharMax.java index 6adb456c3..f1eda908a 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNVarCharMax.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNVarCharMax.java @@ -1,32 +1,29 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ -package com.microsoft.sqlserver.testframework.sqlType; - -import java.sql.Clob; -import java.sql.JDBCType; -import java.sql.NClob; - -import com.microsoft.sqlserver.testframework.DBCoercion; - - -public class SqlNVarCharMax extends SqlNVarChar { - - public SqlNVarCharMax() { - super(); - name = "nvarchar(max)"; - jdbctype = JDBCType.LONGNVARCHAR; - variableLengthType = variableLengthType.Variable; - - coercions.add(new DBCoercion(Clob.class, new int[] {DBCoercion.GET, DBCoercion.UPDATE, DBCoercion.UPDATEOBJECT, DBCoercion.SET, - DBCoercion.SETOBJECT, DBCoercion.GETPARAM, DBCoercion.REG, DBCoercion.CHAR})); - coercions.add(new DBCoercion(NClob.class, new int[] {DBCoercion.GET, DBCoercion.UPDATE, DBCoercion.UPDATEOBJECT, DBCoercion.SET, - DBCoercion.SETOBJECT, DBCoercion.GETPARAM, DBCoercion.REG, DBCoercion.NCHAR})); - - } - -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package com.microsoft.sqlserver.testframework.sqlType; + +import java.sql.Clob; +import java.sql.JDBCType; +import java.sql.NClob; + +import com.microsoft.sqlserver.testframework.DBCoercion; + + +public class SqlNVarCharMax extends SqlNVarChar { + + public SqlNVarCharMax() { + super(); + name = "nvarchar(max)"; + jdbctype = JDBCType.LONGNVARCHAR; + variableLengthType = variableLengthType.Variable; + + coercions.add(new DBCoercion(Clob.class, new int[] {DBCoercion.GET, DBCoercion.UPDATE, DBCoercion.UPDATEOBJECT, + DBCoercion.SET, DBCoercion.SETOBJECT, DBCoercion.GETPARAM, DBCoercion.REG, DBCoercion.CHAR})); + coercions.add(new DBCoercion(NClob.class, new int[] {DBCoercion.GET, DBCoercion.UPDATE, DBCoercion.UPDATEOBJECT, + DBCoercion.SET, DBCoercion.SETOBJECT, DBCoercion.GETPARAM, DBCoercion.REG, DBCoercion.NCHAR})); + + } + +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNumber.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNumber.java index 7b9ae494d..efa9dc04f 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNumber.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNumber.java @@ -1,25 +1,16 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework.sqlType; - -import java.sql.JDBCType; - -public abstract class SqlNumber extends SqlType { - SqlNumber(String name, - JDBCType jdbctype, - int precision, - int scale, - Object min, - Object max, - Object nullvalue, - VariableLengthType variableLengthType, - Class type) { - super(name, jdbctype, precision, scale, min, max, nullvalue, VariableLengthType.Fixed, type); - } -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework.sqlType; + +import java.sql.JDBCType; + + +public abstract class SqlNumber extends SqlType { + SqlNumber(String name, JDBCType jdbctype, int precision, int scale, Object min, Object max, Object nullvalue, + VariableLengthType variableLengthType, Class type) { + super(name, jdbctype, precision, scale, min, max, nullvalue, VariableLengthType.Fixed, type); + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNumeric.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNumeric.java index 1a71843b8..7b843915d 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNumeric.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlNumeric.java @@ -1,18 +1,16 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework.sqlType; - -import java.sql.JDBCType; - -public class SqlNumeric extends SqlDecimal { - - public SqlNumeric() { - super("numeric", JDBCType.NUMERIC); - } -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework.sqlType; + +import java.sql.JDBCType; + + +public class SqlNumeric extends SqlDecimal { + + public SqlNumeric() { + super("numeric", JDBCType.NUMERIC); + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlReal.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlReal.java index 5edaf59ac..4ae52a3e0 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlReal.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlReal.java @@ -1,25 +1,23 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework.sqlType; - -import java.sql.JDBCType; -import java.util.concurrent.ThreadLocalRandom; - -public class SqlReal extends SqlFloat { - - public SqlReal() { - super("real", JDBCType.REAL, 24, SqlTypeValue.REAL.minValue, SqlTypeValue.REAL.maxValue, SqlTypeValue.REAL.nullValue, - VariableLengthType.Fixed, Float.class); - } - - @Override - public Object createdata() { - return (float) ThreadLocalRandom.current().nextDouble((Float) minvalue, (Float) maxvalue); - } -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework.sqlType; + +import java.sql.JDBCType; +import java.util.concurrent.ThreadLocalRandom; + + +public class SqlReal extends SqlFloat { + + public SqlReal() { + super("real", JDBCType.REAL, 24, SqlTypeValue.REAL.minValue, SqlTypeValue.REAL.maxValue, + SqlTypeValue.REAL.nullValue, VariableLengthType.Fixed, Float.class); + } + + @Override + public Object createdata() { + return (float) ThreadLocalRandom.current().nextDouble((Float) minvalue, (Float) maxvalue); + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlSmallDateTime.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlSmallDateTime.java index c9ab21c3d..708514fba 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlSmallDateTime.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlSmallDateTime.java @@ -1,41 +1,38 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework.sqlType; - -import static org.junit.jupiter.api.Assertions.fail; - -import java.sql.JDBCType; -import java.sql.Timestamp; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.concurrent.ThreadLocalRandom; - -public class SqlSmallDateTime extends SqlDateTime { - static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss"); - - public SqlSmallDateTime() { - super("smalldatetime", JDBCType.TIMESTAMP, null, null); - try { - minvalue = new Timestamp(dateFormat.parse((String) SqlTypeValue.SMALLDATETIME.minValue).getTime()); - maxvalue = new Timestamp(dateFormat.parse((String) SqlTypeValue.SMALLDATETIME.maxValue).getTime()); - } - catch (ParseException ex) { - fail(ex.getMessage()); - } - } - - public Object createdata() { - Timestamp smallDateTime = new Timestamp( - ThreadLocalRandom.current().nextLong(((Timestamp) minvalue).getTime(), ((Timestamp) maxvalue).getTime())); - // remove the random nanosecond value if any - smallDateTime.setNanos(0); - return smallDateTime.toString().substring(0,19);// ignore the nano second portion -// return smallDateTime; - } -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework.sqlType; + +import static org.junit.jupiter.api.Assertions.fail; + +import java.sql.JDBCType; +import java.sql.Timestamp; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.concurrent.ThreadLocalRandom; + + +public class SqlSmallDateTime extends SqlDateTime { + static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd'T'HH:mm:ss"); + + public SqlSmallDateTime() { + super("smalldatetime", JDBCType.TIMESTAMP, null, null); + try { + minvalue = new Timestamp(dateFormat.parse((String) SqlTypeValue.SMALLDATETIME.minValue).getTime()); + maxvalue = new Timestamp(dateFormat.parse((String) SqlTypeValue.SMALLDATETIME.maxValue).getTime()); + } catch (ParseException ex) { + fail(ex.getMessage()); + } + } + + public Object createdata() { + Timestamp smallDateTime = new Timestamp(ThreadLocalRandom.current().nextLong(((Timestamp) minvalue).getTime(), + ((Timestamp) maxvalue).getTime())); + // remove the random nanosecond value if any + smallDateTime.setNanos(0); + return smallDateTime.toString().substring(0, 19);// ignore the nano second portion + // return smallDateTime; + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlSmallInt.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlSmallInt.java index 7d2cebcae..af064093f 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlSmallInt.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlSmallInt.java @@ -1,26 +1,24 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework.sqlType; - -import java.sql.JDBCType; -import java.util.concurrent.ThreadLocalRandom; - -public class SqlSmallInt extends SqlNumber { - - public SqlSmallInt() { - super("smallint", JDBCType.SMALLINT, 5, 0, SqlTypeValue.SMALLINT.minValue, SqlTypeValue.SMALLINT.maxValue, SqlTypeValue.SMALLINT.nullValue, - VariableLengthType.Fixed, Short.class); - - } - - public Object createdata() { - // TODO: include max value - return (short) ThreadLocalRandom.current().nextInt(Short.MIN_VALUE, Short.MAX_VALUE); - } -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework.sqlType; + +import java.sql.JDBCType; +import java.util.concurrent.ThreadLocalRandom; + + +public class SqlSmallInt extends SqlNumber { + + public SqlSmallInt() { + super("smallint", JDBCType.SMALLINT, 5, 0, SqlTypeValue.SMALLINT.minValue, SqlTypeValue.SMALLINT.maxValue, + SqlTypeValue.SMALLINT.nullValue, VariableLengthType.Fixed, Short.class); + + } + + public Object createdata() { + // TODO: include max value + return (short) ThreadLocalRandom.current().nextInt(Short.MIN_VALUE, Short.MAX_VALUE); + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlSmallMoney.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlSmallMoney.java index 4ea418bc0..af93d2510 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlSmallMoney.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlSmallMoney.java @@ -1,16 +1,14 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework.sqlType; - -public class SqlSmallMoney extends SqlDecimal { - - public SqlSmallMoney() { - super("smallmoney", 10, 4, SqlTypeValue.SMALLMONEY.minValue, SqlTypeValue.SMALLMONEY.maxValue, VariableLengthType.Fixed); - } -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework.sqlType; + +public class SqlSmallMoney extends SqlDecimal { + + public SqlSmallMoney() { + super("smallmoney", 10, 4, SqlTypeValue.SMALLMONEY.minValue, SqlTypeValue.SMALLMONEY.maxValue, + VariableLengthType.Fixed); + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlTime.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlTime.java index 1f48ba866..2ecaa1762 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlTime.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlTime.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.testframework.sqlType; @@ -20,6 +17,7 @@ import java.time.temporal.ChronoField; import java.util.concurrent.ThreadLocalRandom; + public class SqlTime extends SqlDateTime { static SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss.SSSSSSS"); @@ -32,22 +30,22 @@ public SqlTime() { try { minvalue = new Time(dateFormat.parse((String) SqlTypeValue.TIME.minValue).getTime()); maxvalue = new Time(dateFormat.parse((String) SqlTypeValue.TIME.maxValue).getTime()); - } - catch (ParseException ex) { + } catch (ParseException ex) { fail(ex.getMessage()); } this.scale = 7; this.variableLengthType = VariableLengthType.ScaleOnly; generateScale(); - - formatter = new DateTimeFormatterBuilder().appendPattern(basePattern).appendFraction(ChronoField.NANO_OF_SECOND, 0, this.scale, true) - .toFormatter(); + + formatter = new DateTimeFormatterBuilder().appendPattern(basePattern) + .appendFraction(ChronoField.NANO_OF_SECOND, 0, this.scale, true).toFormatter(); formatter = formatter.withResolverStyle(ResolverStyle.STRICT); } public Object createdata() { - Time temp = new Time(ThreadLocalRandom.current().nextLong(((Time) minvalue).getTime(), ((Time) maxvalue).getTime())); + Time temp = new Time( + ThreadLocalRandom.current().nextLong(((Time) minvalue).getTime(), ((Time) maxvalue).getTime())); String timeNano = temp.toString() + "." + generateRandomInt(this.scale); return timeNano; @@ -56,6 +54,6 @@ public Object createdata() { /* * converting string '20:53:44.9' to LocalTime results in 20:53:44.900, this extra scale causes failure */ -// return LocalTime.parse(timeNano, formatter); + // return LocalTime.parse(timeNano, formatter); } -} \ No newline at end of file +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlTinyInt.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlTinyInt.java index ca5ca58fb..ab9e41e7b 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlTinyInt.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlTinyInt.java @@ -1,25 +1,23 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework.sqlType; - -import java.sql.JDBCType; -import java.util.concurrent.ThreadLocalRandom; - -public class SqlTinyInt extends SqlNumber { - - public SqlTinyInt() { - super("tinyint", JDBCType.TINYINT, 3, 0, SqlTypeValue.TINYINT.minValue, SqlTypeValue.TINYINT.maxValue, SqlTypeValue.TINYINT.nullValue, - VariableLengthType.Fixed, Byte.class); - } - - public Object createdata() { - // TODO: include max value - return (short) ThreadLocalRandom.current().nextInt((short) minvalue, ((short) maxvalue)); - } -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework.sqlType; + +import java.sql.JDBCType; +import java.util.concurrent.ThreadLocalRandom; + + +public class SqlTinyInt extends SqlNumber { + + public SqlTinyInt() { + super("tinyint", JDBCType.TINYINT, 3, 0, SqlTypeValue.TINYINT.minValue, SqlTypeValue.TINYINT.maxValue, + SqlTypeValue.TINYINT.nullValue, VariableLengthType.Fixed, Byte.class); + } + + public Object createdata() { + // TODO: include max value + return (short) ThreadLocalRandom.current().nextInt((short) minvalue, ((short) maxvalue)); + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlType.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlType.java index 36480f7ec..e8acf7c0b 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlType.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlType.java @@ -1,273 +1,263 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework.sqlType; - -import java.sql.JDBCType; -import java.util.BitSet; -import java.util.concurrent.ThreadLocalRandom; - -import com.microsoft.sqlserver.testframework.DBCoercion; -import com.microsoft.sqlserver.testframework.DBCoercions; -import com.microsoft.sqlserver.testframework.DBConnection; -import com.microsoft.sqlserver.testframework.DBItems; - -public abstract class SqlType extends DBItems { - // TODO: add seed to generate random data -> will help to reproduce the - // exact data for debugging - protected String name = null; // type name for creating SQL query - protected JDBCType jdbctype = JDBCType.NULL; - protected int precision = 0; - protected int scale = 0; - protected Object minvalue = null; - protected Object maxvalue = null; - protected Object nullvalue = null; // Primitives have non-null defaults - protected VariableLengthType variableLengthType; - protected Class type = null; - protected BitSet flags = new BitSet(); - protected DBCoercions coercions = new DBCoercions(); - - public static final int DEFAULT = 0; - public static final int NULLABLE = 1; - public static final int UPDATABLE = 2; - public static final int NUMERIC = 3; - public static final int FLOATINGPOINT = 4; - public static final int FIXED = 5; - public static final int CREATEPARAMS = 6; - public static final int CHARACTER = 7; - public static final int UNICODE = 8; - public static final int LONG = 9; - public static final int SEARCHABLE = 10; - public static final int XML = 11; - public static final int UDT = 12; - public static final int BINARY = 13; - public static final int TEMPORAL = 14; - public static final int BOOLEAN = 15; - public static final int PRIMITIVE = 16; - public static final int COLLATE = 17; - public static final int GUID = 18; - - /** - * - * @param name - * @param jdbctype - * @param precision - * @param scale - * @param min - * minimum allowed value for the SQL type - * @param max - * maximum allowed value for the SQL type - * @param nullvalue - * default null value for the SQL type - * @param variableLengthType - * {@link VariableLengthType} - */ - SqlType(String name, - JDBCType jdbctype, - int precision, - int scale, - Object min, - Object max, - Object nullvalue, - VariableLengthType variableLengthType, - Class type) { - this.name = name; - this.jdbctype = jdbctype; - this.precision = precision; - this.scale = scale; - this.minvalue = min; - this.maxvalue = max; - this.nullvalue = nullvalue; - this.variableLengthType = variableLengthType; - this.type = type; - } - - /** - * - * @return valid random value for the SQL type - */ - public Object createdata() { - try { - return null; - } - catch (Exception e) { - // Make this easier to debug - throw new Error("createdata failed: ", e); - } - } - - /** - * create valid random value for the SQL type - * @param type - * @param data - * @return - */ - public Object createdata(Class type, - byte[] data) { - if (type == String.class) - return new String(data); - return data; - } - - /** - * - * @return JDBCType of SqlType object - */ - public JDBCType getJdbctype() { - return jdbctype; - } - - /** - * - * @return - */ - public Class getType() { - return type; - } - - /** - * - * @param jdbctype - * set JDBCType of SqlType object - */ - public void setJdbctype(JDBCType jdbctype) { - this.jdbctype = jdbctype; - } - - /** - * - * @return precision set for the SqlType - */ - public int getPrecision() { - return precision; - } - - /** - * - * @param precision - * set precision for SqlType - */ - public void setPrecision(int precision) { - this.precision = precision; - } - - /** - * - * @return scale set for the SqlType - */ - public int getScale() { - return scale; - } - - /** - * - * @param scale - * set precision for SqlType - */ - public void setScale(int scale) { - this.scale = scale; - } - - /** - * - * @return string value of SqlType - */ - public String getName() { - return name; - } - - /** - * - * @return null value for the SqlType - */ - public Object getNullvalue() { - return nullvalue; - } - - /** - * - * @return minimum allowed value for the SQL type - */ - public Object getMinvalue() { - return minvalue; - } - - /** - * - * @return maximum allowed value for the SQL type - */ - public Object getMaxvalue() { - return maxvalue; - } - - /** - * - * @return variableLengthType {@link VariableLengthType} - */ - public Object getVariableLengthType() { - return variableLengthType; - } - - /** - * generates random precision for SQL types with precision - */ - void generatePrecision() { - int minPrecision = 1; - int maxPrecision = this.precision; - this.precision = ThreadLocalRandom.current().nextInt(minPrecision, maxPrecision + 1); - } - - /** - * generates random precision for SQL types with scale - */ - void generateScale() { - int minScale = 1; - int maxScale = this.scale; - this.scale = ThreadLocalRandom.current().nextInt(minScale, maxScale + 1); - } - - /** - * @return - */ - public boolean isString() { - return flags.get(CHARACTER); - } - - /** - * - * @param target - * @param flag - * @param conn - * @return - * @throws Exception - */ - public boolean canConvert(Class target, - int flag, - DBConnection conn) throws Exception { - double serverversion = conn.getServerVersion(); - - if (flag == DBCoercion.SET || flag == DBCoercion.SETOBJECT || flag == DBCoercion.UPDATE || flag == DBCoercion.UPDATEOBJECT - || flag == DBCoercion.REG) { - // SQL 8 does not allow conversion from string to money - if (flag != DBCoercion.SETOBJECT && serverversion < 9.0 && this instanceof SqlMoney && target == String.class) - return false; - if (flag == DBCoercion.SET || flag == DBCoercion.SETOBJECT) { - // setTemporal() on textual columns returns unverifiable format - if (this.isString() && (target == java.sql.Date.class || target == java.sql.Time.class || target == java.sql.Timestamp.class)) - return false; - } - } - - DBCoercion coercion = coercions.find(target); - if (coercion != null) - return coercion.flags().get(flag); - - return false; - } - -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework.sqlType; + +import java.sql.JDBCType; +import java.util.BitSet; +import java.util.concurrent.ThreadLocalRandom; + +import com.microsoft.sqlserver.testframework.DBCoercion; +import com.microsoft.sqlserver.testframework.DBCoercions; +import com.microsoft.sqlserver.testframework.DBConnection; +import com.microsoft.sqlserver.testframework.DBItems; + + +public abstract class SqlType extends DBItems { + // TODO: add seed to generate random data -> will help to reproduce the + // exact data for debugging + protected String name = null; // type name for creating SQL query + protected JDBCType jdbctype = JDBCType.NULL; + protected int precision = 0; + protected int scale = 0; + protected Object minvalue = null; + protected Object maxvalue = null; + protected Object nullvalue = null; // Primitives have non-null defaults + protected VariableLengthType variableLengthType; + protected Class type = null; + protected BitSet flags = new BitSet(); + protected DBCoercions coercions = new DBCoercions(); + + public static final int DEFAULT = 0; + public static final int NULLABLE = 1; + public static final int UPDATABLE = 2; + public static final int NUMERIC = 3; + public static final int FLOATINGPOINT = 4; + public static final int FIXED = 5; + public static final int CREATEPARAMS = 6; + public static final int CHARACTER = 7; + public static final int UNICODE = 8; + public static final int LONG = 9; + public static final int SEARCHABLE = 10; + public static final int XML = 11; + public static final int UDT = 12; + public static final int BINARY = 13; + public static final int TEMPORAL = 14; + public static final int BOOLEAN = 15; + public static final int PRIMITIVE = 16; + public static final int COLLATE = 17; + public static final int GUID = 18; + + /** + * + * @param name + * @param jdbctype + * @param precision + * @param scale + * @param min + * minimum allowed value for the SQL type + * @param max + * maximum allowed value for the SQL type + * @param nullvalue + * default null value for the SQL type + * @param variableLengthType + * {@link VariableLengthType} + */ + SqlType(String name, JDBCType jdbctype, int precision, int scale, Object min, Object max, Object nullvalue, + VariableLengthType variableLengthType, Class type) { + this.name = name; + this.jdbctype = jdbctype; + this.precision = precision; + this.scale = scale; + this.minvalue = min; + this.maxvalue = max; + this.nullvalue = nullvalue; + this.variableLengthType = variableLengthType; + this.type = type; + } + + /** + * + * @return valid random value for the SQL type + */ + public Object createdata() { + try { + return null; + } catch (Exception e) { + // Make this easier to debug + throw new Error("createdata failed: ", e); + } + } + + /** + * create valid random value for the SQL type + * + * @param type + * @param data + * @return + */ + public Object createdata(Class type, byte[] data) { + if (type == String.class) + return new String(data); + return data; + } + + /** + * + * @return JDBCType of SqlType object + */ + public JDBCType getJdbctype() { + return jdbctype; + } + + /** + * + * @return + */ + public Class getType() { + return type; + } + + /** + * + * @param jdbctype + * set JDBCType of SqlType object + */ + public void setJdbctype(JDBCType jdbctype) { + this.jdbctype = jdbctype; + } + + /** + * + * @return precision set for the SqlType + */ + public int getPrecision() { + return precision; + } + + /** + * + * @param precision + * set precision for SqlType + */ + public void setPrecision(int precision) { + this.precision = precision; + } + + /** + * + * @return scale set for the SqlType + */ + public int getScale() { + return scale; + } + + /** + * + * @param scale + * set precision for SqlType + */ + public void setScale(int scale) { + this.scale = scale; + } + + /** + * + * @return string value of SqlType + */ + public String getName() { + return name; + } + + /** + * + * @return null value for the SqlType + */ + public Object getNullvalue() { + return nullvalue; + } + + /** + * + * @return minimum allowed value for the SQL type + */ + public Object getMinvalue() { + return minvalue; + } + + /** + * + * @return maximum allowed value for the SQL type + */ + public Object getMaxvalue() { + return maxvalue; + } + + /** + * + * @return variableLengthType {@link VariableLengthType} + */ + public Object getVariableLengthType() { + return variableLengthType; + } + + /** + * generates random precision for SQL types with precision + */ + void generatePrecision() { + int minPrecision = 1; + int maxPrecision = this.precision; + this.precision = ThreadLocalRandom.current().nextInt(minPrecision, maxPrecision + 1); + } + + /** + * generates random precision for SQL types with scale + */ + void generateScale() { + int minScale = 1; + int maxScale = this.scale; + this.scale = ThreadLocalRandom.current().nextInt(minScale, maxScale + 1); + } + + /** + * @return + */ + public boolean isString() { + return flags.get(CHARACTER); + } + + /** + * + * @param target + * @param flag + * @param conn + * @return + * @throws Exception + */ + public boolean canConvert(Class target, int flag, DBConnection conn) throws Exception { + double serverversion = conn.getServerVersion(); + + if (flag == DBCoercion.SET || flag == DBCoercion.SETOBJECT || flag == DBCoercion.UPDATE + || flag == DBCoercion.UPDATEOBJECT || flag == DBCoercion.REG) { + // SQL 8 does not allow conversion from string to money + if (flag != DBCoercion.SETOBJECT && serverversion < 9.0 && this instanceof SqlMoney + && target == String.class) + return false; + if (flag == DBCoercion.SET || flag == DBCoercion.SETOBJECT) { + // setTemporal() on textual columns returns unverifiable format + if (this.isString() && (target == java.sql.Date.class || target == java.sql.Time.class + || target == java.sql.Timestamp.class)) + return false; + } + } + + DBCoercion coercion = coercions.find(target); + if (coercion != null) + return coercion.flags().get(flag); + + return false; + } + +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlTypeValue.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlTypeValue.java index 4aa2dd035..91c51210b 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlTypeValue.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlTypeValue.java @@ -1,48 +1,45 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.testframework.sqlType; import java.math.BigDecimal; + /* - * Maps SQL type to its minimum, maximum and null value - * - * temporal min/max values used are not DATEFORMAT dependent as in https://msdn.microsoft.com/en-us/library/ms180878.aspx + * Maps SQL type to its minimum, maximum and null value temporal min/max values used are not DATEFORMAT dependent as in + * https://msdn.microsoft.com/en-us/library/ms180878.aspx */ enum SqlTypeValue { - // minValue // maxValue // nullValue - BIGINT (Long.MIN_VALUE, Long.MAX_VALUE, 0L), - INTEGER (Integer.MIN_VALUE, Integer.MAX_VALUE, 0), - SMALLINT (Short.MIN_VALUE, Short.MAX_VALUE, (short) 0), - TINYINT ((short) 0, (short) 255, (short) 0), - BIT (0, 1, null), - DECIMAL (new BigDecimal("-1.0E38").add(new BigDecimal("1")), new BigDecimal("1.0E38").subtract(new BigDecimal("1")), null), - MONEY (new BigDecimal("-922337203685477.5808"), new BigDecimal("+922337203685477.5807"), null), - SMALLMONEY (new BigDecimal("-214748.3648"), new BigDecimal("214748.3647"), null), - FLOAT (-1.79E308, +1.79E308, 0d), - REAL ((float) -3.4E38, (float) +3.4E38, 0f), - CHAR (null, null, null),// CHAR used by char, nchar, varchar, nvarchar - BINARY (null, null, null), - DATETIME ("17530101T00:00:00.000", "99991231T23:59:59.997", null), - DATE ("00010101", "99991231", null), - TIME ("00:00:00.0000000", "23:59:59.9999999", null), - SMALLDATETIME ("19000101T00:00:00", "20790606T23:59:59", null), - DATETIME2 ("00010101T00:00:00.0000000", "99991231T23:59:59.9999999", null), - DATETIMEOFFSET ("0001-01-01 00:00:00", "9999-12-31 23:59:59", null), - ; - + // minValue // maxValue // nullValue + BIGINT(Long.MIN_VALUE, Long.MAX_VALUE, 0L), + INTEGER(Integer.MIN_VALUE, Integer.MAX_VALUE, 0), + SMALLINT(Short.MIN_VALUE, Short.MAX_VALUE, (short) 0), + TINYINT((short) 0, (short) 255, (short) 0), + BIT(0, 1, null), + DECIMAL(new BigDecimal("-1.0E38").add(new BigDecimal("1")), new BigDecimal("1.0E38") + .subtract(new BigDecimal("1")), null), + MONEY(new BigDecimal("-922337203685477.5808"), new BigDecimal("+922337203685477.5807"), null), + SMALLMONEY(new BigDecimal("-214748.3648"), new BigDecimal("214748.3647"), null), + FLOAT(-1.79E308, +1.79E308, 0d), + REAL((float) -3.4E38, (float) +3.4E38, 0f), + CHAR(null, null, null), // CHAR used by char, nchar, varchar, nvarchar + BINARY(null, null, null), + DATETIME("17530101T00:00:00.000", "99991231T23:59:59.997", null), + DATE("00010101", "99991231", null), + TIME("00:00:00.0000000", "23:59:59.9999999", null), + SMALLDATETIME("19000101T00:00:00", "20790606T23:59:59", null), + DATETIME2("00010101T00:00:00.0000000", "99991231T23:59:59.9999999", null), + DATETIMEOFFSET("0001-01-01 00:00:00", "9999-12-31 23:59:59", null),; + Object minValue; Object maxValue; Object nullValue; - + static final int MAX_DECIMAL_PRECISION = 38; - + SqlTypeValue(Object minValue, Object maxValue, Object nullValue) { this.minValue = minValue; this.maxValue = maxValue; diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlVarBinary.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlVarBinary.java index cfaca9ef9..964c2bc20 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlVarBinary.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlVarBinary.java @@ -1,44 +1,43 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework.sqlType; - -import java.sql.JDBCType; - -import com.microsoft.sqlserver.testframework.DBCoercion; -import com.microsoft.sqlserver.testframework.Utils; -import com.microsoft.sqlserver.testframework.Utils.DBBinaryStream; -import com.microsoft.sqlserver.testframework.Utils.DBCharacterStream; - -/** - * Contains name, jdbctype, precision, scale for varbinary data type - */ -public class SqlVarBinary extends SqlBinary { - - /** - * set JDBCType and precision for SqlVarBinary - */ - public SqlVarBinary() { - super("varbinary", JDBCType.VARBINARY, 4000); - coercions.add(new DBCoercion(String.class, new int[] {DBCoercion.GET, DBCoercion.GETPARAM})); - coercions.add(new DBCoercion(Object.class, new int[] {DBCoercion.GET, DBCoercion.UPDATE, DBCoercion.UPDATEOBJECT, DBCoercion.SET, - DBCoercion.SETOBJECT, DBCoercion.GETPARAM, DBCoercion.REG})); - coercions.add(new DBCoercion(byte[].class, new int[] {DBCoercion.GET, DBCoercion.UPDATE, DBCoercion.UPDATEOBJECT, DBCoercion.SET, - DBCoercion.SETOBJECT, DBCoercion.GETPARAM, DBCoercion.REG})); - - // TODO: Following coercions are not supported by AE. add a check later - // coercions.remove(String.class); - coercions.add(new DBCoercion(String.class, - new int[] {DBCoercion.GET, DBCoercion.UPDATE, DBCoercion.UPDATEOBJECT, DBCoercion.SETOBJECT, DBCoercion.GETPARAM})); - coercions.add(new DBCoercion(DBBinaryStream.class, new int[] {DBCoercion.GET, DBCoercion.UPDATE, DBCoercion.UPDATEOBJECT, DBCoercion.SET, - DBCoercion.SETOBJECT, DBCoercion.GETPARAM, DBCoercion.REG, DBCoercion.STREAM})); - coercions.add(new DBCoercion(DBCharacterStream.class, new int[] {DBCoercion.GET, DBCoercion.UPDATE, DBCoercion.UPDATEOBJECT, - DBCoercion.SETOBJECT, DBCoercion.GETPARAM, DBCoercion.REG, DBCoercion.STREAM})); - - } -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework.sqlType; + +import java.sql.JDBCType; + +import com.microsoft.sqlserver.testframework.DBCoercion; +import com.microsoft.sqlserver.testframework.Utils.DBBinaryStream; +import com.microsoft.sqlserver.testframework.Utils.DBCharacterStream; + + +/** + * Contains name, jdbctype, precision, scale for varbinary data type + */ +public class SqlVarBinary extends SqlBinary { + + /** + * set JDBCType and precision for SqlVarBinary + */ + public SqlVarBinary() { + super("varbinary", JDBCType.VARBINARY, 4000); + coercions.add(new DBCoercion(String.class, new int[] {DBCoercion.GET, DBCoercion.GETPARAM})); + coercions.add(new DBCoercion(Object.class, new int[] {DBCoercion.GET, DBCoercion.UPDATE, + DBCoercion.UPDATEOBJECT, DBCoercion.SET, DBCoercion.SETOBJECT, DBCoercion.GETPARAM, DBCoercion.REG})); + coercions.add(new DBCoercion(byte[].class, new int[] {DBCoercion.GET, DBCoercion.UPDATE, + DBCoercion.UPDATEOBJECT, DBCoercion.SET, DBCoercion.SETOBJECT, DBCoercion.GETPARAM, DBCoercion.REG})); + + // TODO: Following coercions are not supported by AE. add a check later + // coercions.remove(String.class); + coercions.add(new DBCoercion(String.class, new int[] {DBCoercion.GET, DBCoercion.UPDATE, + DBCoercion.UPDATEOBJECT, DBCoercion.SETOBJECT, DBCoercion.GETPARAM})); + coercions.add(new DBCoercion(DBBinaryStream.class, + new int[] {DBCoercion.GET, DBCoercion.UPDATE, DBCoercion.UPDATEOBJECT, DBCoercion.SET, + DBCoercion.SETOBJECT, DBCoercion.GETPARAM, DBCoercion.REG, DBCoercion.STREAM})); + coercions.add(new DBCoercion(DBCharacterStream.class, + new int[] {DBCoercion.GET, DBCoercion.UPDATE, DBCoercion.UPDATEOBJECT, DBCoercion.SETOBJECT, + DBCoercion.GETPARAM, DBCoercion.REG, DBCoercion.STREAM})); + + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlVarBinaryMax.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlVarBinaryMax.java index 80f7ba6bb..ccc115211 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlVarBinaryMax.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlVarBinaryMax.java @@ -1,27 +1,24 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ -package com.microsoft.sqlserver.testframework.sqlType; - -import java.sql.Blob; -import java.sql.JDBCType; - -import com.microsoft.sqlserver.testframework.DBCoercion; -import com.microsoft.sqlserver.testframework.DBCoercions; - -public class SqlVarBinaryMax extends SqlVarBinary { - - public SqlVarBinaryMax() { - super(); - name = "varbinary(max)"; - jdbctype = JDBCType.LONGVARBINARY; - variableLengthType = variableLengthType.Variable; - coercions.add(new DBCoercion(Blob.class, new int[] {DBCoercion.GET, DBCoercion.UPDATE, DBCoercion.UPDATEOBJECT, DBCoercion.SET, - DBCoercion.SETOBJECT, DBCoercion.GETPARAM, DBCoercion.REG})); - } - -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package com.microsoft.sqlserver.testframework.sqlType; + +import java.sql.Blob; +import java.sql.JDBCType; + +import com.microsoft.sqlserver.testframework.DBCoercion; + + +public class SqlVarBinaryMax extends SqlVarBinary { + + public SqlVarBinaryMax() { + super(); + name = "varbinary(max)"; + jdbctype = JDBCType.LONGVARBINARY; + variableLengthType = variableLengthType.Variable; + coercions.add(new DBCoercion(Blob.class, new int[] {DBCoercion.GET, DBCoercion.UPDATE, DBCoercion.UPDATEOBJECT, + DBCoercion.SET, DBCoercion.SETOBJECT, DBCoercion.GETPARAM, DBCoercion.REG})); + } + +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlVarChar.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlVarChar.java index 35276a5ad..7d6bac54f 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlVarChar.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlVarChar.java @@ -1,18 +1,16 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework.sqlType; - -import java.sql.JDBCType; - -public class SqlVarChar extends SqlChar { - - public SqlVarChar() { - super("varchar", JDBCType.VARCHAR, 4000); - } -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework.sqlType; + +import java.sql.JDBCType; + + +public class SqlVarChar extends SqlChar { + + public SqlVarChar() { + super("varchar", JDBCType.VARCHAR, 4000); + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlVarCharMax.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlVarCharMax.java index a4e700fd3..b8578cc33 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlVarCharMax.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/SqlVarCharMax.java @@ -1,28 +1,24 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ -package com.microsoft.sqlserver.testframework.sqlType; - -import java.sql.Clob; -import java.util.ArrayList; - -import com.microsoft.sqlserver.testframework.DBCoercion; -import com.microsoft.sqlserver.testframework.DBCoercions; - -public class SqlVarCharMax extends SqlVarChar { - - public SqlVarCharMax() { - - super(); - name = "varchar(max)"; - jdbctype = jdbctype.LONGVARCHAR; - variableLengthType = variableLengthType.Variable; - coercions.add(new DBCoercion(Clob.class, new int[] {DBCoercion.GET, DBCoercion.UPDATE, DBCoercion.UPDATEOBJECT, DBCoercion.SET, - DBCoercion.SETOBJECT, DBCoercion.GETPARAM, DBCoercion.REG, DBCoercion.CHAR})); - - } -} \ No newline at end of file +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ +package com.microsoft.sqlserver.testframework.sqlType; + +import java.sql.Clob; + +import com.microsoft.sqlserver.testframework.DBCoercion; + + +public class SqlVarCharMax extends SqlVarChar { + + public SqlVarCharMax() { + + super(); + name = "varchar(max)"; + jdbctype = jdbctype.LONGVARCHAR; + variableLengthType = variableLengthType.Variable; + coercions.add(new DBCoercion(Clob.class, new int[] {DBCoercion.GET, DBCoercion.UPDATE, DBCoercion.UPDATEOBJECT, + DBCoercion.SET, DBCoercion.SETOBJECT, DBCoercion.GETPARAM, DBCoercion.REG, DBCoercion.CHAR})); + + } +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/VariableLengthType.java b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/VariableLengthType.java index fb12fa1ae..064a33733 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/sqlType/VariableLengthType.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/sqlType/VariableLengthType.java @@ -1,20 +1,17 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework.sqlType; - -/** - * Used to identify if the SQL type is of fixed length, or has Precision or Scale - */ -public enum VariableLengthType { - Fixed, // primitive types with fixed Length - Precision, // variable length type that just has precision char/varchar - Scale, // variable length type with scale and precision - ScaleOnly, // variable length type with just scale like Time - Variable -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework.sqlType; + +/** + * Used to identify if the SQL type is of fixed length, or has Precision or Scale + */ +public enum VariableLengthType { + Fixed, // primitive types with fixed Length + Precision, // variable length type that just has precision char/varchar + Scale, // variable length type with scale and precision + ScaleOnly, // variable length type with just scale like Time + Variable +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/util/ComparisonUtil.java b/src/test/java/com/microsoft/sqlserver/testframework/util/ComparisonUtil.java index 8de791994..30a7e9d93 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/util/ComparisonUtil.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/util/ComparisonUtil.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.testframework.util; @@ -27,6 +24,7 @@ import com.microsoft.sqlserver.testframework.DBTable; import com.microsoft.sqlserver.testframework.Utils; + public class ComparisonUtil { /** @@ -37,11 +35,12 @@ public class ComparisonUtil { * @param destTable * @throws SQLException */ - public static void compareSrcTableAndDestTableIgnoreRowOrder(DBConnection con, - DBTable srcTable, + public static void compareSrcTableAndDestTableIgnoreRowOrder(DBConnection con, DBTable srcTable, DBTable destTable) throws SQLException { - DBResultSet srcResultSetCount = con.createStatement().executeQuery("SELECT COUNT(*) FROM " + srcTable.getEscapedTableName() + ";"); - DBResultSet dstResultSetCount = con.createStatement().executeQuery("SELECT COUNT(*) FROM " + destTable.getEscapedTableName() + ";"); + DBResultSet srcResultSetCount = con.createStatement() + .executeQuery("SELECT COUNT(*) FROM " + srcTable.getEscapedTableName() + ";"); + DBResultSet dstResultSetCount = con.createStatement() + .executeQuery("SELECT COUNT(*) FROM " + destTable.getEscapedTableName() + ";"); srcResultSetCount.next(); dstResultSetCount.next(); int srcRows = srcResultSetCount.getInt(1); @@ -55,15 +54,19 @@ public static void compareSrcTableAndDestTableIgnoreRowOrder(DBConnection con, fail("Souce table and Destination table have different number of columns."); } - DBResultSet srcResultSet = con.createStatement().executeQuery("SELECT * FROM " + srcTable.getEscapedTableName() + " ORDER BY [" - + srcTable.getColumnName(1) + "], [" + srcTable.getColumnName(2) + "],[" + srcTable.getColumnName(3) + "];"); - DBResultSet dstResultSet = con.createStatement().executeQuery("SELECT * FROM " + destTable.getEscapedTableName() + " ORDER BY [" - + destTable.getColumnName(1) + "], [" + destTable.getColumnName(2) + "],[" + destTable.getColumnName(3) + "];"); + DBResultSet srcResultSet = con.createStatement().executeQuery( + "SELECT * FROM " + srcTable.getEscapedTableName() + " ORDER BY [" + srcTable.getColumnName(1) + "], [" + + srcTable.getColumnName(2) + "],[" + srcTable.getColumnName(3) + "];"); + DBResultSet dstResultSet = con.createStatement().executeQuery( + "SELECT * FROM " + destTable.getEscapedTableName() + " ORDER BY [" + destTable.getColumnName(1) + "], [" + + destTable.getColumnName(2) + "],[" + destTable.getColumnName(3) + "];"); while (srcResultSet.next() && dstResultSet.next()) { for (int i = 0; i < destTable.getColumns().size(); i++) { - SQLServerResultSetMetaData srcMeta = (SQLServerResultSetMetaData) ((ResultSet) srcResultSet.product()).getMetaData(); - SQLServerResultSetMetaData destMeta = (SQLServerResultSetMetaData) ((ResultSet) dstResultSet.product()).getMetaData(); + SQLServerResultSetMetaData srcMeta = (SQLServerResultSetMetaData) ((ResultSet) srcResultSet.product()) + .getMetaData(); + SQLServerResultSetMetaData destMeta = (SQLServerResultSetMetaData) ((ResultSet) dstResultSet.product()) + .getMetaData(); int srcJDBCTypeInt = srcMeta.getColumnType(i + 1); int destJDBCTypeInt = destMeta.getColumnType(i + 1); @@ -88,33 +91,37 @@ public static void compareSrcTableAndDestTableIgnoreRowOrder(DBConnection con, * @param expectedValue * @param actualValue */ - public static void compareExpectedAndActual(int dataType, - Object expectedValue, - Object actualValue) { + public static void compareExpectedAndActual(int dataType, Object expectedValue, Object actualValue) { // Bulkcopy doesn't guarantee order of insertion - if we need to test several rows either use primary key or // validate result based on sql JOIN if ((null == expectedValue) || (null == actualValue)) { // if one value is null other should be null too assertEquals(expectedValue, actualValue, "Expected null in source and destination"); - } - else + } else switch (dataType) { case java.sql.Types.BIGINT: - assertTrue((((Long) expectedValue).longValue() == ((Long) actualValue).longValue()), "Unexpected bigint value. Expected:" + ((Long) expectedValue).longValue() + " Actual:" + ((Long) actualValue).longValue()); + assertTrue((((Long) expectedValue).longValue() == ((Long) actualValue).longValue()), + "Unexpected bigint value. Expected:" + ((Long) expectedValue).longValue() + " Actual:" + + ((Long) actualValue).longValue()); break; case java.sql.Types.INTEGER: - assertTrue((((Integer) expectedValue).intValue() == ((Integer) actualValue).intValue()), "Unexpected int value. Expected:" + ((Integer) expectedValue).intValue() + " Actual:" + ((Integer) actualValue).intValue()); + assertTrue((((Integer) expectedValue).intValue() == ((Integer) actualValue).intValue()), + "Unexpected int value. Expected:" + ((Integer) expectedValue).intValue() + " Actual:" + + ((Integer) actualValue).intValue()); break; case java.sql.Types.SMALLINT: case java.sql.Types.TINYINT: - assertTrue((((Short) expectedValue).shortValue() == ((Short) actualValue).shortValue()), "Unexpected smallint/tinyint value. Expected:" + ((Short) expectedValue).shortValue() + " Actual:" + ((Short) actualValue).shortValue()); + assertTrue((((Short) expectedValue).shortValue() == ((Short) actualValue).shortValue()), + "Unexpected smallint/tinyint value. Expected:" + ((Short) expectedValue).shortValue() + + " Actual:" + ((Short) actualValue).shortValue()); break; case java.sql.Types.BIT: - assertTrue((((Boolean) expectedValue).booleanValue() == ((Boolean) actualValue).booleanValue()), "Unexpected bit value"); + assertTrue((((Boolean) expectedValue).booleanValue() == ((Boolean) actualValue).booleanValue()), + "Unexpected bit value"); break; case java.sql.Types.DECIMAL: @@ -124,26 +131,33 @@ public static void compareExpectedAndActual(int dataType, break; case java.sql.Types.DOUBLE: - assertTrue((((Double) expectedValue).doubleValue() == ((Double) actualValue).doubleValue()), "Unexpected double value. Expected:" + ((Double) expectedValue).doubleValue() + " Actual:" + ((Double) actualValue).doubleValue()); + assertTrue((((Double) expectedValue).doubleValue() == ((Double) actualValue).doubleValue()), + "Unexpected double value. Expected:" + ((Double) expectedValue).doubleValue() + " Actual:" + + ((Double) actualValue).doubleValue()); break; case java.sql.Types.REAL: - assertTrue((((Float) expectedValue).floatValue() == ((Float) actualValue).floatValue()), "Unexpected real/float value. Expected:" + ((Float) expectedValue).floatValue() + " Actual:" + ((Float) actualValue).floatValue()); + assertTrue((((Float) expectedValue).floatValue() == ((Float) actualValue).floatValue()), + "Unexpected real/float value. Expected:" + ((Float) expectedValue).floatValue() + " Actual:" + + ((Float) actualValue).floatValue()); break; case java.sql.Types.VARCHAR: case java.sql.Types.NVARCHAR: - assertTrue(((((String) expectedValue).trim()).equals(((String) actualValue).trim())), "Unexpected varchar/nvarchar value "); + assertTrue(((((String) expectedValue).trim()).equals(((String) actualValue).trim())), + "Unexpected varchar/nvarchar value "); break; case java.sql.Types.CHAR: case java.sql.Types.NCHAR: - assertTrue(((((String) expectedValue).trim()).equals(((String) actualValue).trim())), "Unexpected char/nchar value "); + assertTrue(((((String) expectedValue).trim()).equals(((String) actualValue).trim())), + "Unexpected char/nchar value "); break; case java.sql.Types.BINARY: case java.sql.Types.VARBINARY: - assertTrue(Utils.parseByte((byte[]) expectedValue, (byte[]) actualValue), "Unexpected bianry/varbinary value "); + assertTrue(Utils.parseByte((byte[]) expectedValue, (byte[]) actualValue), + "Unexpected bianry/varbinary value "); break; case java.sql.Types.TIMESTAMP: @@ -153,19 +167,21 @@ public static void compareExpectedAndActual(int dataType, case java.sql.Types.DATE: Calendar expC = Calendar.getInstance(); - expC.setTime((Date)expectedValue); + expC.setTime((Date) expectedValue); Calendar actC = Calendar.getInstance(); - actC.setTime((Date)actualValue); - assertTrue(expC.get(Calendar.DAY_OF_MONTH) == actC.get(Calendar.DAY_OF_MONTH), "Unexpected datetime value"); + actC.setTime((Date) actualValue); + assertTrue(expC.get(Calendar.DAY_OF_MONTH) == actC.get(Calendar.DAY_OF_MONTH), + "Unexpected datetime value"); break; case java.sql.Types.TIME: - assertTrue(((Time) expectedValue).getTime() == ((Time) actualValue).getTime(), "Unexpected time value "); + assertTrue(((Time) expectedValue).getTime() == ((Time) actualValue).getTime(), + "Unexpected time value "); break; case microsoft.sql.Types.DATETIMEOFFSET: - assertTrue(0 == ((microsoft.sql.DateTimeOffset) expectedValue).compareTo((microsoft.sql.DateTimeOffset) actualValue), - "Unexpected time value "); + assertTrue(0 == ((microsoft.sql.DateTimeOffset) expectedValue) + .compareTo((microsoft.sql.DateTimeOffset) actualValue), "Unexpected time value "); break; default: diff --git a/src/test/java/com/microsoft/sqlserver/testframework/util/RandomData.java b/src/test/java/com/microsoft/sqlserver/testframework/util/RandomData.java index 50be438c8..7d367f262 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/util/RandomData.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/util/RandomData.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.testframework.util; @@ -19,6 +16,7 @@ import microsoft.sql.DateTimeOffset; + /** * Utility class for generating random data for testing */ @@ -27,7 +25,8 @@ 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 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 @@ -75,8 +74,7 @@ public static Integer generateInt(boolean nullable) { if (returnMinMax) { if (r.nextBoolean()) { return 2147483647; - } - else { + } else { return -2147483648; } } @@ -105,8 +103,7 @@ public static Long generateLong(boolean nullable) { if (returnMinMax) { if (r.nextBoolean()) { return 9223372036854775807L; - } - else { + } else { return -9223372036854775808L; } } @@ -126,8 +123,7 @@ public static Short generateTinyint(boolean nullable) { if (null != value) { return value.shortValue(); - } - else { + } else { return null; } } @@ -143,8 +139,7 @@ public static Short generateSmallint(boolean nullable) { if (null != value) { return value.shortValue(); - } - else { + } else { return null; } } @@ -157,9 +152,7 @@ public static Short generateSmallint(boolean nullable) { * @param nullable * @return */ - public static BigDecimal generateDecimalNumeric(int precision, - int scale, - boolean nullable) { + public static BigDecimal generateDecimalNumeric(int precision, int scale, boolean nullable) { if (nullable) { if (returnNull) { @@ -177,15 +170,16 @@ public static BigDecimal generateDecimalNumeric(int precision, 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, RoundingMode.HALF_UP)) + return new BigDecimal(n, scale) + .subtract(new BigDecimal("" + Math.pow(10, -scale)).setScale(scale, RoundingMode.HALF_UP)) .negate(); else return new BigDecimal(n, scale).subtract(new BigDecimal("1")).negate(); - } - else { + } else { n = BigInteger.TEN.pow(precision); if (scale > 0) - return new BigDecimal(n, scale).subtract(new BigDecimal("" + Math.pow(10, -scale)).setScale(scale, RoundingMode.HALF_UP)) + return new BigDecimal(n, scale) + .subtract(new BigDecimal("" + Math.pow(10, -scale)).setScale(scale, RoundingMode.HALF_UP)) .negate(); else return new BigDecimal(n, scale).subtract(new BigDecimal("1")).negate(); @@ -212,8 +206,7 @@ public static Float generateReal(boolean nullable) { if (null != doubleValue) { return doubleValue.floatValue(); - } - else { + } else { return null; } } @@ -222,12 +215,11 @@ public static Float generateReal(boolean nullable) { * Utility method for generating a random double. * * @param n - * integer + * integer * @param nullable * @return */ - public static Double generateFloat(Integer n, - boolean nullable) { + public static Double generateFloat(Integer n, boolean nullable) { if (nullable) { if (returnNull) { return null; @@ -243,11 +235,9 @@ public static Double generateFloat(Integer n, // https://msdn.microsoft.com/en-us/library/ms173773.aspx if (null == n) { n = 53; - } - else if (25 <= n && 53 >= n) { + } else if (25 <= n && 53 >= n) { n = 53; - } - else { + } else { n = 24; } @@ -256,34 +246,27 @@ else if (25 <= n && 53 >= n) { if (r.nextBoolean()) { if (r.nextBoolean()) { return Double.valueOf("1.79E+308"); - } - else { + } else { return Double.valueOf("2.23E-308"); } - } - else { + } else { if (r.nextBoolean()) { return Double.valueOf("-2.23E-308"); - } - else { + } else { return Double.valueOf("-1.79E+308"); } } - } - else { + } else { if (r.nextBoolean()) { if (r.nextBoolean()) { return Double.valueOf("3.40E+38"); - } - else { + } else { return Double.valueOf("1.18E-38"); } - } - else { + } else { if (r.nextBoolean()) { return Double.valueOf("-1.18E-38"); - } - else { + } else { return Double.valueOf("-3.40E+38"); } } @@ -339,17 +322,13 @@ public static BigDecimal generateSmallMoney(boolean nullable) { * @param encrypted * @return */ - public static String generateCharTypes(String columnLength, - boolean nullable, - boolean encrypted) { + 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) { + public static String generateNCharTypes(String columnLength, boolean nullable, boolean encrypted) { String charSet = specicalCharSet + normalCharSet + unicodeCharSet; return buildCharOrNChar(columnLength, nullable, encrypted, charSet, 4001); @@ -363,9 +342,7 @@ public static String generateNCharTypes(String columnLength, * @param encrypted * @return */ - public static byte[] generateBinaryTypes(String columnLength, - boolean nullable, - boolean encrypted) { + public static byte[] generateBinaryTypes(String columnLength, boolean nullable, boolean encrypted) { int maxBound = 8001; if (nullable) { @@ -388,23 +365,20 @@ public static byte[] generateBinaryTypes(String columnLength, byte[] bytes = new byte[length]; r.nextBytes(bytes); return bytes; - } - else { + } else { length = r.nextInt(maxBound - minimumLength) + minimumLength; byte[] bytes = new byte[length]; r.nextBytes(bytes); return bytes; } - } - else { + } else { int columnLengthInt = Integer.parseInt(columnLength); if (returnFullLength) { length = columnLengthInt; byte[] bytes = new byte[length]; r.nextBytes(bytes); return bytes; - } - else { + } else { length = r.nextInt(columnLengthInt - minimumLength) + minimumLength; byte[] bytes = new byte[length]; r.nextBytes(bytes); @@ -432,8 +406,7 @@ public static Date generateDate(boolean nullable) { if (returnMinMax) { if (r.nextBoolean()) { return new Date(max); - } - else { + } else { return new Date(min); } } @@ -466,8 +439,7 @@ public static Timestamp generateDatetime(boolean nullable) { * @param nullable * @return */ - public static DateTimeOffset generateDatetimeoffset(Integer precision, - boolean nullable) { + public static DateTimeOffset generateDatetimeoffset(Integer precision, boolean nullable) { if (null == precision) { precision = 7; } @@ -487,8 +459,7 @@ public static DateTimeOffset generateDatetimeoffset(Integer precision, if (returnMinMax) { if (r.nextBoolean()) { return maxDTS; - } - else { + } else { // return minDTS; return calculateDateTimeOffsetMinMax("min", precision, "0001-01-01 00:00:00.0000000"); } @@ -522,8 +493,7 @@ public static Timestamp generateSmalldatetime(boolean nullable) { * @param nullable * @return */ - public static Timestamp generateDatetime2(Integer precision, - boolean nullable) { + public static Timestamp generateDatetime2(Integer precision, boolean nullable) { if (null == precision) { precision = 7; } @@ -542,14 +512,14 @@ public static Timestamp generateDatetime2(Integer precision, int precisionDigits = buildPrecision(precision, "9"); ts.setNanos(precisionDigits); return ts; - } - else { + } 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 + 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; @@ -562,8 +532,7 @@ public static Timestamp generateDatetime2(Integer precision, * @param nullable * @return */ - public static Time generateTime(Integer precision, - boolean nullable) { + public static Time generateTime(Integer precision, boolean nullable) { if (null == precision) { precision = 7; } @@ -582,8 +551,7 @@ public static Time generateTime(Integer precision, int precisionDigits = buildPrecision(precision, "9"); ts.setNanos(precisionDigits); return new Time(ts.getTime()); - } - else { + } else { ts.setNanos(0); return new Time(ts.getTime()); } @@ -594,14 +562,12 @@ public static Time generateTime(Integer precision, return new Time(ts.getTime()); } - private static int buildPrecision(int precision, - String charSet) { + 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) { + 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(); @@ -617,9 +583,7 @@ private static String calculatePrecisionDigits(int precision, return sb.toString(); } - private static Timestamp generateTimestamp(boolean nullable, - long max, - long min) { + private static Timestamp generateTimestamp(boolean nullable, long max, long min) { if (nullable) { if (returnNull) { return null; @@ -629,8 +593,7 @@ private static Timestamp generateTimestamp(boolean nullable, if (returnMinMax) { if (r.nextBoolean()) { return new Timestamp(max); - } - else { + } else { return new Timestamp(min); } } @@ -644,11 +607,8 @@ private static Timestamp generateTimestamp(boolean nullable, } } - private static BigDecimal generateMoneyOrSmallMoney(boolean nullable, - BigDecimal max, - BigDecimal min, - float multiplier, - String charSet) { + private static BigDecimal generateMoneyOrSmallMoney(boolean nullable, BigDecimal max, BigDecimal min, + float multiplier, String charSet) { if (nullable) { if (returnNull) { return null; @@ -662,8 +622,7 @@ private static BigDecimal generateMoneyOrSmallMoney(boolean nullable, if (returnMinMax) { if (r.nextBoolean()) { return max; - } - else { + } else { return min; } } @@ -679,14 +638,11 @@ private static BigDecimal generateMoneyOrSmallMoney(boolean nullable, return new BigDecimal(intPart + "." + sb.toString()); } - private static DateTimeOffset calculateDateTimeOffsetMinMax(String maxOrMin, - Integer precision, - String tsMinMax) { + private static DateTimeOffset calculateDateTimeOffsetMinMax(String maxOrMin, Integer precision, String tsMinMax) { int providedTimeZoneInMinutes; if (maxOrMin.toLowerCase().equals("max")) { providedTimeZoneInMinutes = 840; - } - else { + } else { providedTimeZoneInMinutes = -840; } @@ -706,9 +662,7 @@ private static DateTimeOffset calculateDateTimeOffsetMinMax(String maxOrMin, return microsoft.sql.DateTimeOffset.valueOf(tsMax, providedTimeZoneInMinutes); } - private static Integer pickInt(boolean nullable, - int max, - int min) { + private static Integer pickInt(boolean nullable, int max, int min) { if (nullable) { if (returnNull) { return null; @@ -722,8 +676,7 @@ private static Integer pickInt(boolean nullable, if (returnMinMax) { if (r.nextBoolean()) { return max; - } - else { + } else { return min; } } @@ -731,10 +684,7 @@ private static Integer pickInt(boolean nullable, return (int) r.nextInt(max - min) + min; } - private static String buildCharOrNChar(String columnLength, - boolean nullable, - boolean encrypted, - String charSet, + private static String buildCharOrNChar(String columnLength, boolean nullable, boolean encrypted, String charSet, int maxBound) { if (nullable) { @@ -755,27 +705,23 @@ private static String buildCharOrNChar(String columnLength, if (r.nextBoolean()) { length = r.nextInt(100000) + maxBound; return buildRandomString(length, charSet); - } - else { + } else { length = r.nextInt(maxBound - minimumLength) + minimumLength; return buildRandomString(length, charSet); } - } - else { + } else { int columnLengthInt = Integer.parseInt(columnLength); if (returnFullLength) { length = columnLengthInt; return buildRandomString(length, charSet); - } - else { + } else { length = r.nextInt(columnLengthInt - minimumLength) + minimumLength; return buildRandomString(length, charSet); } } } - private static String buildRandomString(int length, - String charSet) { + private static String buildRandomString(int length, String charSet) { StringBuffer sb = new StringBuffer(); for (int i = 0; i < length; i++) { char c = pickRandomChar(charSet); @@ -792,14 +738,11 @@ private static char pickRandomChar(String charSet) { return charSet.charAt(randomIndex); } - private static BigInteger newRandomBigInteger(BigInteger n, - Random rnd, - int precision) { + private static BigInteger newRandomBigInteger(BigInteger n, Random rnd, int precision) { BigInteger r; do { r = new BigInteger(n.bitLength(), rnd); - } - while (r.toString().length() != precision); + } while (r.toString().length() != precision); return r; } diff --git a/src/test/java/com/microsoft/sqlserver/testframework/util/RandomUtil.java b/src/test/java/com/microsoft/sqlserver/testframework/util/RandomUtil.java index a49620e75..f3b00ffbc 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/util/RandomUtil.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/util/RandomUtil.java @@ -1,108 +1,99 @@ -/* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. - */ - -package com.microsoft.sqlserver.testframework.util; - -import java.util.UUID; - -/** - * Utility Class - */ -public class RandomUtil { - - static int _maxIdentifier = 128; // Max identifier allowed by SQL Server - - static public String getIdentifier(String prefix) { - return getIdentifier(prefix, _maxIdentifier, true, false); - } - - public static String getIdentifierForDB(String prefix) { - return getIdentifierForDB(prefix, _maxIdentifier, true); - } - - /** - * - * @param prefix - * Prefix - * @param maxLength - * max length - * @param unique - * Includes UUID. - * @param isDatabase - * Do you want for db name. - * @return - */ - static public String getIdentifier(String prefix, - int maxLength, - boolean unique, - boolean isDatabase) { - String identifier; - StringBuilder sb = new StringBuilder(); - sb.append(prefix); - sb.append("_"); - sb.append("jdbc_"); - sb.append(System.getProperty("user.name")); - sb.append("_"); - if (unique) { - // Create UUID. - sb.append(UUID.randomUUID().toString()); - } - - identifier = sb.toString(); - - if (maxLength < identifier.length()) { - identifier = identifier.substring(0, maxLength); - } - return identifier; - } - - /** - * Get Identifier for DB Name. - * - * @param prefix - * Prefix - * @param maxLength - * max length - * @param unique - * Includes UUID. - * @return - */ - public static String getIdentifierForDB(String prefix, - int maxLength, - boolean unique) { - String identifier = getIdentifier(prefix, maxLength, unique, true); - return removeInvalidDBChars(identifier); - } - - /** - * - * @param prefix - * Prefix - * @param maxLength - * max length - * @param isDatabase - * Do you want for db name. - * @return - */ - public static String getUniqueIdentifier(String prefix, - int maxLength, - boolean isDatabase) { - return getIdentifier(prefix, maxLength, true, isDatabase); - } - - /** - * Remove Invalid DB Chars. - * - * @param s - * @return - */ - private static String removeInvalidDBChars(String s) { - return s.replaceAll("[:-]", "_"); - } - -} +/* + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. + */ + +package com.microsoft.sqlserver.testframework.util; + +import java.util.UUID; + + +/** + * Utility Class + */ +public class RandomUtil { + + static int _maxIdentifier = 128; // Max identifier allowed by SQL Server + + static public String getIdentifier(String prefix) { + return getIdentifier(prefix, _maxIdentifier, true, false); + } + + public static String getIdentifierForDB(String prefix) { + return getIdentifierForDB(prefix, _maxIdentifier, true); + } + + /** + * + * @param prefix + * Prefix + * @param maxLength + * max length + * @param unique + * Includes UUID. + * @param isDatabase + * Do you want for db name. + * @return + */ + static public String getIdentifier(String prefix, int maxLength, boolean unique, boolean isDatabase) { + String identifier; + StringBuilder sb = new StringBuilder(); + sb.append(prefix); + sb.append("_"); + sb.append("jdbc_"); + sb.append(System.getProperty("user.name")); + sb.append("_"); + if (unique) { + // Create UUID. + sb.append(UUID.randomUUID().toString()); + } + + identifier = sb.toString(); + + if (maxLength < identifier.length()) { + identifier = identifier.substring(0, maxLength); + } + return identifier; + } + + /** + * Get Identifier for DB Name. + * + * @param prefix + * Prefix + * @param maxLength + * max length + * @param unique + * Includes UUID. + * @return + */ + public static String getIdentifierForDB(String prefix, int maxLength, boolean unique) { + String identifier = getIdentifier(prefix, maxLength, unique, true); + return removeInvalidDBChars(identifier); + } + + /** + * + * @param prefix + * Prefix + * @param maxLength + * max length + * @param isDatabase + * Do you want for db name. + * @return + */ + public static String getUniqueIdentifier(String prefix, int maxLength, boolean isDatabase) { + return getIdentifier(prefix, maxLength, true, isDatabase); + } + + /** + * Remove Invalid DB Chars. + * + * @param s + * @return + */ + private static String removeInvalidDBChars(String s) { + return s.replaceAll("[:-]", "_"); + } + +} diff --git a/src/test/java/com/microsoft/sqlserver/testframework/util/Util.java b/src/test/java/com/microsoft/sqlserver/testframework/util/Util.java index ee4ea2c75..6b66613a3 100644 --- a/src/test/java/com/microsoft/sqlserver/testframework/util/Util.java +++ b/src/test/java/com/microsoft/sqlserver/testframework/util/Util.java @@ -1,9 +1,6 @@ /* - * Microsoft JDBC Driver for SQL Server - * - * Copyright(c) Microsoft Corporation All rights reserved. - * - * This program is made available under the terms of the MIT License. See the LICENSE file in the project root for more information. + * Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made + * available under the terms of the MIT License. See the LICENSE file in the project root for more information. */ package com.microsoft.sqlserver.testframework.util; @@ -21,6 +18,7 @@ import com.microsoft.sqlserver.jdbc.SQLServerDatabaseMetaData; import com.microsoft.sqlserver.jdbc.SQLServerStatementColumnEncryptionSetting; + /** * Utility class for testing */ @@ -30,22 +28,20 @@ public class Util { * Utility method for generating a prepared statement * * @param connection - * connection object + * connection object * @param sql - * SQL string + * SQL string * @param stmtColEncSetting - * SQLServerStatementColumnEncryptionSetting object + * SQLServerStatementColumnEncryptionSetting object * @return */ - public static PreparedStatement getPreparedStmt(Connection connection, - String sql, + 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); + } else { + return ((SQLServerConnection) connection).prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, + ResultSet.CONCUR_READ_ONLY, connection.getHoldability(), stmtColEncSetting); } } @@ -53,11 +49,11 @@ public static PreparedStatement getPreparedStmt(Connection connection, * Utility method for a statement * * @param connection - * connection object + * connection object * @param sql - * SQL string + * SQL string * @param stmtColEncSetting - * SQLServerStatementColumnEncryptionSetting object + * SQLServerStatementColumnEncryptionSetting object * @return */ public static Statement getStatement(Connection connection, @@ -65,10 +61,9 @@ public static Statement getStatement(Connection connection, // 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); + } else { + return ((SQLServerConnection) connection).createStatement(ResultSet.TYPE_FORWARD_ONLY, + ResultSet.CONCUR_READ_ONLY, connection.getHoldability(), stmtColEncSetting); } } @@ -76,50 +71,50 @@ public static Statement getStatement(Connection connection, * Utility method for a scrollable statement * * @param connection - * connection object + * connection object * @return */ public static Statement getScrollableStatement(Connection connection) throws SQLException { - return ((SQLServerConnection) connection).createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); + return ((SQLServerConnection) connection).createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, + ResultSet.CONCUR_UPDATABLE); } /** * Utility method for a scrollable statement * * @param connection - * connection object + * connection object * @param stmtColEncSetting - * SQLServerStatementColumnEncryptionSetting object + * 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); + 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 + * connection object * @param stmtColEncSetting - * SQLServerStatementColumnEncryptionSetting object + * SQLServerStatementColumnEncryptionSetting object * @param rsScrollSensitivity * @param rsConcurrence * @return */ public static Statement getStatement(Connection connection, - SQLServerStatementColumnEncryptionSetting stmtColEncSetting, - int rsScrollSensitivity, + 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); + return ((SQLServerConnection) connection).createStatement(rsScrollSensitivity, rsConcurrence, + connection.getHoldability()); + } else { + return ((SQLServerConnection) connection).createStatement(rsScrollSensitivity, rsConcurrence, + connection.getHoldability(), stmtColEncSetting); } } @@ -127,21 +122,19 @@ public static Statement getStatement(Connection connection, * Utility method for a callable statement * * @param connection - * connection object + * connection object * @param stmtColEncSetting - * SQLServerStatementColumnEncryptionSetting object + * SQLServerStatementColumnEncryptionSetting object * @param sql * @return */ - public static CallableStatement getCallableStmt(Connection connection, - String sql, + 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); + } else { + return ((SQLServerConnection) connection).prepareCall(sql, ResultSet.TYPE_FORWARD_ONLY, + ResultSet.CONCUR_READ_ONLY, connection.getHoldability(), stmtColEncSetting); } } @@ -162,8 +155,7 @@ public static Object roundSmallDateTimeValue(Object value) { if (value instanceof Calendar) { cal = (Calendar) value; - } - else { + } else { ts = (java.sql.Timestamp) value; cal = Calendar.getInstance(); cal.setTimeInMillis(ts.getTime()); @@ -171,7 +163,8 @@ public static Object roundSmallDateTimeValue(Object value) { } // round to the nearest minute - double seconds = cal.get(Calendar.SECOND) + (nanos == -1 ? ((double) cal.get(Calendar.MILLISECOND) / 1000) : ((double) nanos / 1000000000)); + 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); } @@ -185,8 +178,7 @@ public static Object roundSmallDateTimeValue(Object value) { // return appropriate value if (value instanceof Calendar) { return cal; - } - else { + } else { ts.setTime(cal.getTimeInMillis()); ts.setNanos(nanos); return ts; @@ -202,7 +194,8 @@ public static Object roundSmallDateTimeValue(Object value) { public static Object roundDatetimeValue(Object value) { if (value == null) return null; - Timestamp ts = value instanceof Timestamp ? (Timestamp) value : new Timestamp(((Calendar) value).getTimeInMillis()); + Timestamp ts = value instanceof Timestamp ? (Timestamp) value + : new Timestamp(((Calendar) value).getTimeInMillis()); int millis = ts.getNanos() / 1000000; int lastDigit = (int) (millis % 10); switch (lastDigit) { @@ -257,31 +250,26 @@ public static Object roundDatetimeValue(Object value) { * @param Statement * @param Connection */ - public static void close(ResultSet rs, - Statement stmt, - Connection con) { + public static void close(ResultSet rs, Statement stmt, Connection con) { if (rs != null) { try { rs.close(); - } - catch (SQLException e) { + } catch (SQLException e) { System.out.println("The result set cannot be closed."); } } if (stmt != null) { try { stmt.close(); - } - catch (SQLException e) { + } catch (SQLException e) { System.out.println("The statement cannot be closed."); } } if (con != null) { try { con.close(); - } - catch (SQLException e) { + } catch (SQLException e) { System.out.println("The data source connection cannot be closed."); } } @@ -318,8 +306,7 @@ public static boolean supportJDBC43(Connection con) throws SQLException { public static boolean serverSupportsDataClassification(Statement stmt) { try { stmt.execute("SELECT * FROM SYS.SENSITIVITY_CLASSIFICATIONS"); - } - catch (SQLException e) { + } catch (SQLException e) { // Check for Error 208: Invalid Object Name if (e.getErrorCode() == 208) { return false; @@ -331,15 +318,14 @@ public static boolean serverSupportsDataClassification(Statement stmt) { /** * * @param b - * byte value + * byte value * @param length - * length of the array + * length of the array * @return */ final static char[] hexChars = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; - public static String bytesToHexString(byte[] b, - int length) { + public static String bytesToHexString(byte[] b, int length) { StringBuilder sb = new StringBuilder(length * 2); for (int i = 0; i < length; i++) { int hexVal = b[i] & 0xFF; @@ -353,7 +339,7 @@ public static String bytesToHexString(byte[] b, * conversion routine valid values 0-9 a-f A-F throws exception when failed to convert * * @param value - * charArray + * charArray * @return * @throws SQLException */ @@ -361,14 +347,11 @@ static byte CharToHex(char value) throws SQLException { byte ret = 0; if (value >= 'A' && value <= 'F') { ret = (byte) (value - 'A' + 10); - } - else if (value >= 'a' && value <= 'f') { + } else if (value >= 'a' && value <= 'f') { ret = (byte) (value - 'a' + 10); - } - else if (value >= '0' && value <= '9') { + } else if (value >= '0' && value <= '9') { ret = (byte) (value - '0'); - } - else { + } else { throw new IllegalArgumentException("The string is not in a valid hex format. "); } return ret; @@ -378,7 +361,7 @@ else if (value >= '0' && value <= '9') { * Converts a string to an array of bytes * * @param hexV - * a hexized string representation of bytes + * a hexized string representation of bytes * @return * @throws SQLException */