diff --git a/AppVeyorJCE/README.md b/AppVeyorJCE/README.md
index db088d8636..994e013855 100644
--- a/AppVeyorJCE/README.md
+++ b/AppVeyorJCE/README.md
@@ -1,31 +1,31 @@
-# JCE chocolatey package
-
-### Disclaimers:
-1. All contents within this directory originate from [this GitHub project](https://github.com/TobseF/jce-chocolatey-package). This project was added to allow us to test the Always Encrypted feature on AppVeyor builds.
-
-2. This is not an official project of Oracle. It\`s only easy of the manual installation: It downloads the JCE from oracle.com and unpacks it to the installed JDK.
-
-
-[Chocolatey](https://chocolatey.org/) package for the [JCE (Unlimited Strength Java Cryptography Extension Policy Files)](http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html)
-
-This chocolatey package adds the JCE to latest installed Java SDK. The The `JAVA_HOME` environment variable has to point to the JDK. If `JAVA_HOME` is not set, nothing will be changed. The original files are backuped (renamed to `*_old`) and can be reverted at any time. This package is a perfect addion to the [JDK8 package](https://chocolatey.org/packages/jdk8).
-
-#### Install with [Chocolatey](https://chocolatey.org/)
-```PowerShell
-choco install jce -y
-```
-
-#### Build from source:
-1. Install [Chocolatey](https://chocolatey.org/).
-2. Open cmd with admin rights in jce package directory.
-3. Pack NuGet Package (.nupkg).
-```PowerShell
-cpack
-```
-4. Install JCE NuGet Package.
-```PowerShell
-choco install jce -fdv -s . -y
-```
-
-
-
+# JCE chocolatey package
+
+### Disclaimers:
+1. All contents within this directory originate from [this GitHub project](https://github.com/TobseF/jce-chocolatey-package). This project was added to allow us to test the Always Encrypted feature on AppVeyor builds.
+
+2. This is not an official project of Oracle. It\`s only easy of the manual installation: It downloads the JCE from oracle.com and unpacks it to the installed JDK.
+
+
+[Chocolatey](https://chocolatey.org/) package for the [JCE (Unlimited Strength Java Cryptography Extension Policy Files)](http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html)
+
+This chocolatey package adds the JCE to latest installed Java SDK. The The `JAVA_HOME` environment variable has to point to the JDK. If `JAVA_HOME` is not set, nothing will be changed. The original files are backuped (renamed to `*_old`) and can be reverted at any time. This package is a perfect addion to the [JDK8 package](https://chocolatey.org/packages/jdk8).
+
+#### Install with [Chocolatey](https://chocolatey.org/)
+```PowerShell
+choco install jce -y
+```
+
+#### Build from source:
+1. Install [Chocolatey](https://chocolatey.org/).
+2. Open cmd with admin rights in jce package directory.
+3. Pack NuGet Package (.nupkg).
+```PowerShell
+cpack
+```
+4. Install JCE NuGet Package.
+```PowerShell
+choco install jce -fdv -s . -y
+```
+
+
+
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9da698da7d..ffd905d636 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,20 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/)
+## [6.3.0] Preview Release
+### Added
+- Added support for sql_variant datatype [#387](https://github.com/Microsoft/mssql-jdbc/pull/387)
+- Added more Junit tests for AlwaysEncrpyted [#404](https://github.com/Microsoft/mssql-jdbc/pull/404)
+
+### Fixed Issues
+- Fixed Turkey locale issue when lowercasing an "i" [#384](https://github.com/Microsoft/mssql-jdbc/pull/384)
+- Fixed issue with incorrect parameter count for INSERT with subquery [#373](https://github.com/Microsoft/mssql-jdbc/pull/373)
+- Fixed issue with running DDL in PreparedStatement [#372](https://github.com/Microsoft/mssql-jdbc/pull/372)
+- Fixed issue with parameter metadata with whitespace characters [#371](https://github.com/Microsoft/mssql-jdbc/pull/371)
+- Fixed handling of explicit boxing and unboxing [#84](https://github.com/Microsoft/mssql-jdbc/pull/84)
+- Fixed metadata caching batch query issue [#393](https://github.com/Microsoft/mssql-jdbc/pull/393)
+- Fixed javadoc issue for the newest maven version [#385](https://github.com/Microsoft/mssql-jdbc/pull/385)
+
## [6.2.1] Hotfix & Stable Release
### Fixed Issues
- Fixed queries without parameters using preparedStatement [#372](https://github.com/Microsoft/mssql-jdbc/pull/372)
diff --git a/README.md b/README.md
index ae22e0381e..1621e04553 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,6 @@
[](https://raw.githubusercontent.com/Microsoft/mssql-jdbc/master/LICENSE)
[](http://mvnrepository.com/artifact/com.microsoft.sqlserver/mssql-jdbc)
+[](http://codecov.io/github/Microsoft/mssql-jdbc?branch=master)
[](http://javadoc.io/doc/com.microsoft.sqlserver/mssql-jdbc)
[](https://gitter.im/Microsoft/mssql-developers)
@@ -61,6 +62,8 @@ To build the jar files, you must use Java 8 with Maven. You can choose to build
## Resources
### Documentation
+API reference documentation is available in [Javadocs](https://aka.ms/jdbcjavadocs).
+
This driver is documented on [Microsoft's Documentation web site](https://msdn.microsoft.com/en-us/library/mt720657).
### Sample Code
diff --git a/build.gradle b/build.gradle
index 7a402dfbc6..e648bff700 100644
--- a/build.gradle
+++ b/build.gradle
@@ -80,4 +80,4 @@ dependencies {
'org.junit.jupiter:junit-jupiter-engine:5.0.0-M3',
'com.zaxxer:HikariCP:2.6.0',
'org.apache.commons:commons-dbcp2:2.1.1'
-}
+}
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 62b790dd7a..bd9d0ced66 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.microsoft.sqlserver
mssql-jdbc
- 6.2.0
+ 6.3.0
jar
@@ -48,14 +48,14 @@
com.microsoft.azure
azure-keyvault
- 0.9.7
+ 1.0.0
true
com.microsoft.azure
adal4j
- 1.1.3
+ 1.2.0
true
@@ -158,7 +158,7 @@
maven-jar-plugin
3.0.2
- ${project.artifactId}-${project.version}.jre7
+ ${project.artifactId}-${project.version}.jre7-preview
${project.build.outputDirectory}/META-INF/MANIFEST.MF
@@ -192,7 +192,7 @@
maven-jar-plugin
3.0.2
- ${project.artifactId}-${project.version}.jre8
+ ${project.artifactId}-${project.version}.jre8-preview
${project.build.outputDirectory}/META-INF/MANIFEST.MF
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/Column.java b/src/main/java/com/microsoft/sqlserver/jdbc/Column.java
index 6a4a5d6708..a9c09e3305 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/Column.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/Column.java
@@ -18,7 +18,16 @@
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;
}
@@ -187,11 +196,12 @@ Object getValue(JDBCType jdbcType,
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)).intValue();
+ return (Integer) getValue(JDBCType.INTEGER, null, null, tdsReader);
}
void updateValue(JDBCType jdbcType,
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/DDC.java b/src/main/java/com/microsoft/sqlserver/jdbc/DDC.java
index 53c5b6f1c4..562b958c8d 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/DDC.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/DDC.java
@@ -54,15 +54,15 @@ static final Object convertIntegerToObject(int intValue,
StreamType streamType) {
switch (jdbcType) {
case INTEGER:
- return new Integer(intValue);
+ return intValue;
case SMALLINT: // 2.21 small and tinyint returned as short
case TINYINT:
- return new Short((short) intValue);
+ return (short) intValue;
case BIT:
case BOOLEAN:
- return new Boolean(0 != intValue);
+ return 0 != intValue;
case BIGINT:
- return new Long(intValue);
+ return (long) intValue;
case DECIMAL:
case NUMERIC:
case MONEY:
@@ -70,9 +70,9 @@ static final Object convertIntegerToObject(int intValue,
return new BigDecimal(Integer.toString(intValue));
case FLOAT:
case DOUBLE:
- return new Double(intValue);
+ return (double) intValue;
case REAL:
- return new Float(intValue);
+ return (float) intValue;
case BINARY:
return convertIntToBytes(intValue, valueLength);
default:
@@ -99,15 +99,15 @@ static final Object convertLongToObject(long longVal,
StreamType streamType) {
switch (jdbcType) {
case BIGINT:
- return new Long(longVal);
+ return longVal;
case INTEGER:
- return new Integer((int) longVal);
+ return (int) longVal;
case SMALLINT: // small and tinyint returned as short
case TINYINT:
- return new Short((short) longVal);
+ return (short) longVal;
case BIT:
case BOOLEAN:
- return new Boolean(0 != longVal);
+ return 0 != longVal;
case DECIMAL:
case NUMERIC:
case MONEY:
@@ -115,9 +115,9 @@ static final Object convertLongToObject(long longVal,
return new BigDecimal(Long.toString(longVal));
case FLOAT:
case DOUBLE:
- return new Double(longVal);
+ return (double) longVal;
case REAL:
- return new Float(longVal);
+ return (float) longVal;
case BINARY:
byte[] convertedBytes = convertLongToBytes(longVal);
int bytesToReturnLength;
@@ -152,23 +152,23 @@ static final Object convertLongToObject(long longVal,
case VARBINARY:
switch (baseSSType) {
case BIGINT:
- return new Long(longVal);
+ return longVal;
case INTEGER:
- return new Integer((int) longVal);
+ return (int) longVal;
case SMALLINT: // small and tinyint returned as short
case TINYINT:
- return new Short((short) longVal);
+ return (short) longVal;
case BIT:
- return new Boolean(0 != longVal);
+ return 0 != longVal;
case DECIMAL:
case NUMERIC:
case MONEY:
case SMALLMONEY:
return new BigDecimal(Long.toString(longVal));
case FLOAT:
- return new Double(longVal);
+ return (double) longVal;
case REAL:
- return new Float(longVal);
+ return (float) longVal;
case BINARY:
return convertLongToBytes(longVal);
default:
@@ -214,17 +214,17 @@ static final Object convertFloatToObject(float floatVal,
StreamType streamType) {
switch (jdbcType) {
case REAL:
- return new Float(floatVal);
+ return floatVal;
case INTEGER:
- return new Integer((int) floatVal);
+ return (int) floatVal;
case SMALLINT: // small and tinyint returned as short
case TINYINT:
- return new Short((short) floatVal);
+ return (short) floatVal;
case BIT:
case BOOLEAN:
- return new Boolean(0 != Float.compare(0.0f, floatVal));
+ return 0 != Float.compare(0.0f, floatVal);
case BIGINT:
- return new Long((long) floatVal);
+ return (long) floatVal;
case DECIMAL:
case NUMERIC:
case MONEY:
@@ -232,7 +232,7 @@ static final Object convertFloatToObject(float floatVal,
return new BigDecimal(Float.toString(floatVal));
case FLOAT:
case DOUBLE:
- return new Double((new Float(floatVal)).doubleValue());
+ return (new Float(floatVal)).doubleValue();
case BINARY:
return convertIntToBytes(Float.floatToRawIntBits(floatVal), 4);
default:
@@ -273,19 +273,19 @@ static final Object convertDoubleToObject(double doubleVal,
switch (jdbcType) {
case FLOAT:
case DOUBLE:
- return new Double(doubleVal);
+ return doubleVal;
case REAL:
- return new Float((new Double(doubleVal)).floatValue());
+ return (new Double(doubleVal)).floatValue();
case INTEGER:
- return new Integer((int) doubleVal);
+ return (int) doubleVal;
case SMALLINT: // small and tinyint returned as short
case TINYINT:
- return new Short((short) doubleVal);
+ return (short) doubleVal;
case BIT:
case BOOLEAN:
- return new Boolean(0 != Double.compare(0.0d, doubleVal));
+ return 0 != Double.compare(0.0d, doubleVal);
case BIGINT:
- return new Long((long) doubleVal);
+ return (long) doubleVal;
case DECIMAL:
case NUMERIC:
case MONEY:
@@ -355,19 +355,19 @@ static final Object convertBigDecimalToObject(BigDecimal bigDecimalVal,
return bigDecimalVal;
case FLOAT:
case DOUBLE:
- return new Double(bigDecimalVal.doubleValue());
+ return bigDecimalVal.doubleValue();
case REAL:
- return new Float(bigDecimalVal.floatValue());
+ return bigDecimalVal.floatValue();
case INTEGER:
- return new Integer(bigDecimalVal.intValue());
+ return bigDecimalVal.intValue();
case SMALLINT: // small and tinyint returned as short
case TINYINT:
- return new Short(bigDecimalVal.shortValue());
+ return bigDecimalVal.shortValue();
case BIT:
case BOOLEAN:
- return new Boolean(0 != bigDecimalVal.compareTo(BigDecimal.valueOf(0)));
+ return 0 != bigDecimalVal.compareTo(BigDecimal.valueOf(0));
case BIGINT:
- return new Long(bigDecimalVal.longValue());
+ return bigDecimalVal.longValue();
case BINARY:
return convertBigDecimalToBytes(bigDecimalVal, bigDecimalVal.scale());
default:
@@ -400,19 +400,19 @@ static final Object convertMoneyToObject(BigDecimal bigDecimalVal,
return bigDecimalVal;
case FLOAT:
case DOUBLE:
- return new Double(bigDecimalVal.doubleValue());
+ return bigDecimalVal.doubleValue();
case REAL:
- return new Float(bigDecimalVal.floatValue());
+ return bigDecimalVal.floatValue();
case INTEGER:
- return new Integer(bigDecimalVal.intValue());
+ return bigDecimalVal.intValue();
case SMALLINT: // small and tinyint returned as short
case TINYINT:
- return new Short(bigDecimalVal.shortValue());
+ return bigDecimalVal.shortValue();
case BIT:
case BOOLEAN:
- return new Boolean(0 != bigDecimalVal.compareTo(BigDecimal.valueOf(0)));
+ return 0 != bigDecimalVal.compareTo(BigDecimal.valueOf(0));
case BIGINT:
- return new Long(bigDecimalVal.longValue());
+ return bigDecimalVal.longValue();
case BINARY:
return convertToBytes(bigDecimalVal, bigDecimalVal.scale(), numberOfBytes);
default:
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/DataTypes.java b/src/main/java/com/microsoft/sqlserver/jdbc/DataTypes.java
index a7dc9b021c..914e382a29 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/DataTypes.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/DataTypes.java
@@ -95,7 +95,7 @@ static TDSType valueOf(int intValue) throws IllegalArgumentException {
if (!(0 <= intValue && intValue < valuesTypes.length) || null == (tdsType = valuesTypes[intValue])) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_unknownSSType"));
- Object[] msgArgs = {new Integer(intValue)};
+ Object[] msgArgs = {intValue};
throw new IllegalArgumentException(form.format(msgArgs));
}
@@ -145,7 +145,7 @@ enum SSType
DECIMAL (Category.NUMERIC, "decimal", JDBCType.DECIMAL),
NUMERIC (Category.NUMERIC, "numeric", JDBCType.NUMERIC),
GUID (Category.GUID, "uniqueidentifier", JDBCType.GUID),
- SQL_VARIANT (Category.VARIANT, "sql_variant", JDBCType.VARCHAR),
+ 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);
@@ -203,7 +203,7 @@ enum Category {
TIME,
TIMESTAMP,
UDT,
- VARIANT,
+ SQL_VARIANT,
XML
}
@@ -358,7 +358,20 @@ enum GetterConversion
SSType.Category.GUID,
EnumSet.of(
JDBCType.Category.BINARY,
- JDBCType.Category.CHARACTER));
+ 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;
@@ -842,7 +855,9 @@ enum JDBCType
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");
+ GUID (Category.CHARACTER, microsoft.sql.Types.GUID, "java.lang.String"),
+ SQL_VARIANT (Category.SQL_VARIANT, microsoft.sql.Types.SQL_VARIANT, "java.lang.Object");
+
final Category category;
private final int intValue;
@@ -889,7 +904,8 @@ enum Category {
SQLXML,
UNKNOWN,
TVP,
- GUID;
+ GUID,
+ SQL_VARIANT,
}
// This SetterConversion enum is based on the Category enum
@@ -908,7 +924,8 @@ enum SetterConversion {
JDBCType.Category.LONG_NCHARACTER,
JDBCType.Category.BINARY,
JDBCType.Category.LONG_BINARY,
- JDBCType.Category.GUID)),
+ JDBCType.Category.GUID,
+ JDBCType.Category.SQL_VARIANT)),
LONG_CHARACTER (
JDBCType.Category.LONG_CHARACTER,
@@ -932,7 +949,8 @@ enum SetterConversion {
EnumSet.of(
JDBCType.Category.NCHARACTER,
JDBCType.Category.LONG_NCHARACTER,
- JDBCType.Category.NCLOB)),
+ JDBCType.Category.NCLOB,
+ JDBCType.Category.SQL_VARIANT)),
LONG_NCHARACTER (
JDBCType.Category.LONG_NCHARACTER,
@@ -960,7 +978,8 @@ enum SetterConversion {
JDBCType.Category.BINARY,
JDBCType.Category.LONG_BINARY,
JDBCType.Category.BLOB,
- JDBCType.Category.GUID)),
+ JDBCType.Category.GUID,
+ JDBCType.Category.SQL_VARIANT)),
LONG_BINARY (
JDBCType.Category.LONG_BINARY,
@@ -981,7 +1000,8 @@ enum SetterConversion {
JDBCType.Category.CHARACTER,
JDBCType.Category.LONG_CHARACTER,
JDBCType.Category.NCHARACTER,
- JDBCType.Category.LONG_NCHARACTER)),
+ JDBCType.Category.LONG_NCHARACTER,
+ JDBCType.Category.SQL_VARIANT)),
DATE (
JDBCType.Category.DATE,
@@ -992,7 +1012,8 @@ enum SetterConversion {
JDBCType.Category.CHARACTER,
JDBCType.Category.LONG_CHARACTER,
JDBCType.Category.NCHARACTER,
- JDBCType.Category.LONG_NCHARACTER)),
+ JDBCType.Category.LONG_NCHARACTER,
+ JDBCType.Category.SQL_VARIANT)),
TIME (
JDBCType.Category.TIME,
@@ -1003,7 +1024,8 @@ enum SetterConversion {
JDBCType.Category.CHARACTER,
JDBCType.Category.LONG_CHARACTER,
JDBCType.Category.NCHARACTER,
- JDBCType.Category.LONG_NCHARACTER)),
+ JDBCType.Category.LONG_NCHARACTER,
+ JDBCType.Category.SQL_VARIANT)),
TIMESTAMP (
JDBCType.Category.TIMESTAMP,
@@ -1015,7 +1037,8 @@ enum SetterConversion {
JDBCType.Category.CHARACTER,
JDBCType.Category.LONG_CHARACTER,
JDBCType.Category.NCHARACTER,
- JDBCType.Category.LONG_NCHARACTER)),
+ JDBCType.Category.LONG_NCHARACTER,
+ JDBCType.Category.SQL_VARIANT)),
TIME_WITH_TIMEZONE (
JDBCType.Category.TIME_WITH_TIMEZONE,
@@ -1103,7 +1126,8 @@ enum UpdaterConversion {
SSType.Category.LONG_BINARY,
SSType.Category.UDT,
SSType.Category.GUID,
- SSType.Category.TIMESTAMP)),
+ SSType.Category.TIMESTAMP,
+ SSType.Category.SQL_VARIANT)),
LONG_CHARACTER (
JDBCType.Category.LONG_CHARACTER,
@@ -1128,7 +1152,8 @@ enum UpdaterConversion {
EnumSet.of(
SSType.Category.NCHARACTER,
SSType.Category.LONG_NCHARACTER,
- SSType.Category.XML)),
+ SSType.Category.XML,
+ SSType.Category.SQL_VARIANT)),
LONG_NCHARACTER (
JDBCType.Category.LONG_NCHARACTER,
@@ -1157,7 +1182,8 @@ enum UpdaterConversion {
SSType.Category.LONG_BINARY,
SSType.Category.UDT,
SSType.Category.TIMESTAMP,
- SSType.Category.GUID)),
+ SSType.Category.GUID,
+ SSType.Category.SQL_VARIANT)),
LONG_BINARY (
JDBCType.Category.LONG_BINARY,
@@ -1184,7 +1210,8 @@ enum UpdaterConversion {
SSType.Category.CHARACTER,
SSType.Category.LONG_CHARACTER,
SSType.Category.NCHARACTER,
- SSType.Category.LONG_NCHARACTER)),
+ SSType.Category.LONG_NCHARACTER,
+ SSType.Category.SQL_VARIANT)),
DATE (
JDBCType.Category.DATE,
@@ -1196,7 +1223,8 @@ enum UpdaterConversion {
SSType.Category.CHARACTER,
SSType.Category.LONG_CHARACTER,
SSType.Category.NCHARACTER,
- SSType.Category.LONG_NCHARACTER)),
+ SSType.Category.LONG_NCHARACTER,
+ SSType.Category.SQL_VARIANT)),
TIME (
JDBCType.Category.TIME,
@@ -1208,7 +1236,8 @@ enum UpdaterConversion {
SSType.Category.CHARACTER,
SSType.Category.LONG_CHARACTER,
SSType.Category.NCHARACTER,
- SSType.Category.LONG_NCHARACTER)),
+ SSType.Category.LONG_NCHARACTER,
+ SSType.Category.SQL_VARIANT)),
TIMESTAMP (
JDBCType.Category.TIMESTAMP,
@@ -1221,7 +1250,8 @@ enum UpdaterConversion {
SSType.Category.CHARACTER,
SSType.Category.LONG_CHARACTER,
SSType.Category.NCHARACTER,
- SSType.Category.LONG_NCHARACTER)),
+ SSType.Category.LONG_NCHARACTER,
+ SSType.Category.SQL_VARIANT)),
DATETIMEOFFSET (
JDBCType.Category.DATETIMEOFFSET,
@@ -1259,8 +1289,13 @@ enum UpdaterConversion {
SSType.Category.CHARACTER,
SSType.Category.LONG_CHARACTER,
SSType.Category.NCHARACTER,
- SSType.Category.LONG_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;
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/FailOverInfo.java b/src/main/java/com/microsoft/sqlserver/jdbc/FailOverInfo.java
index 1f83263231..0e905bc7d4 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/FailOverInfo.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/FailOverInfo.java
@@ -71,7 +71,7 @@ private void setupInfo(SQLServerConnection con) throws SQLServerException {
instancePort = con.getInstancePort(failoverPartner, instanceValue);
try {
- portNumber = (new Integer(instancePort)).intValue();
+ portNumber = new Integer(instancePort);
}
catch (NumberFormatException e) {
// Should not get here as the server should give a proper port number anyway.
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java b/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java
index 92638ffe06..01ad482566 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java
@@ -134,6 +134,9 @@ 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;
static final String getTokenName(int tdsTokenType) {
switch (tdsTokenType) {
@@ -1383,7 +1386,7 @@ private final class HostNameOverrideX509TrustManager extends Object implements X
this.logContext = tdsChannel.toString() + " (HostNameOverrideX509TrustManager):";
defaultTrustManager = tm;
// canonical name is in lower case so convert this to lowercase too.
- this.hostName = hostName.toLowerCase();
+ this.hostName = hostName.toLowerCase(Locale.ENGLISH);
;
}
@@ -1506,13 +1509,11 @@ private void validateServerNameInCertificate(X509Certificate cert) throws Certif
if (value != null && value instanceof String) {
String dnsNameInSANCert = (String) value;
- // convert to upper case and then to lower case in english locale
- // to avoid Turkish i issues.
+ // Use English locale to avoid Turkish i issues.
// Note that, this conversion was not necessary for
// cert.getSubjectX500Principal().getName("canonical");
// as the above API already does this by default as per documentation.
- dnsNameInSANCert = dnsNameInSANCert.toUpperCase(Locale.US);
- dnsNameInSANCert = dnsNameInSANCert.toLowerCase(Locale.US);
+ dnsNameInSANCert = dnsNameInSANCert.toLowerCase(Locale.ENGLISH);
isServerNameValidated = validateServerName(dnsNameInSANCert);
@@ -2588,17 +2589,17 @@ private void findSocketUsingJavaNIO(InetAddress[] inetAddrs,
}
}
- // if a channel was selected, make the necessary updates
+ // if a channel was selected, make the necessary updates
if (selectedChannel != null) {
- //the selectedChannel has the address that is connected successfully
- //convert it to a java.net.Socket object with the address
- SocketAddress iadd = selectedChannel.getRemoteAddress();
+ // the selectedChannel has the address that is connected successfully
+ // convert it to a java.net.Socket object with the address
+ SocketAddress iadd = selectedChannel.getRemoteAddress();
selectedSocket = new Socket();
selectedSocket.connect(iadd);
result = Result.SUCCESS;
-
- //close the channel since it is not used anymore
+
+ // close the channel since it is not used anymore
selectedChannel.close();
}
}
@@ -3238,6 +3239,17 @@ void writeByte(byte value) throws SQLServerException {
}
}
+ /**
+ * writing sqlCollation information for sqlVariant type when sending character types.
+ *
+ * @param variantType
+ * @throws SQLServerException
+ */
+ void writeCollationForSqlVariant(SqlVariant variantType) throws SQLServerException {
+ writeInt(variantType.getCollation().getCollationInfo());
+ writeByte((byte) (variantType.getCollation().getCollationSortID() & 0xFF));
+ }
+
void writeChar(char value) throws SQLServerException {
if (stagingBuffer.remaining() >= 2) {
stagingBuffer.putChar(value);
@@ -3293,7 +3305,7 @@ void writeInt(int value) throws SQLServerException {
* the data value
*/
void writeReal(Float value) throws SQLServerException {
- writeInt(Float.floatToRawIntBits(value.floatValue()));
+ writeInt(Float.floatToRawIntBits(value));
}
/**
@@ -3364,6 +3376,64 @@ 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
+ * @param srcJdbcType
+ * the source JDBCType
+ */
+ 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.
+ */
+
+ boolean isNegative = (bigDecimalVal.signum() < 0);
+ BigInteger bi = bigDecimalVal.unscaledValue();
+ if (isNegative)
+ {
+ bi = bi.negate();
+ }
+ int bLength;
+ bLength = BYTES16;
+
+ writeByte((byte) (isNegative ? 0 : 1));
+
+ // Get the bytes of the BigInteger value. It is in reverse order, with
+ // most significant byte in 0-th element. We need to reverse it first before sending over TDS.
+ byte[] unscaledBytes = bi.toByteArray();
+
+ if (unscaledBytes.length > bLength) {
+ // 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);
+ }
+
+ // Byte array to hold all the reversed and padding bytes.
+ byte[] bytes = new byte[bLength];
+
+ // We need to fill up the rest of the array with zeros, as unscaledBytes may have less bytes
+ // than the required size for TDS.
+ int remaining = bLength - unscaledBytes.length;
+
+ // Reverse the bytes.
+ int i, j;
+ for (i = 0, j = unscaledBytes.length - 1; i < unscaledBytes.length;)
+ bytes[i++] = unscaledBytes[j--];
+
+ // Fill the rest of the array with zeros.
+ for (; i < remaining; i++)
+ {
+ bytes[i] = (byte) 0x00;
+ }
+ writeBytes(bytes);
+ }
void writeSmalldatetime(String value) throws SQLServerException {
GregorianCalendar calendar = initializeCalender(TimeZone.getDefault());
@@ -3781,7 +3851,7 @@ void writeStream(InputStream inputStream,
// the actual stream length did not match then cancel the request.
if (DataTypes.UNKNOWN_STREAM_LENGTH != advertisedLength && actualLength != advertisedLength) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_mismatchedStreamLength"));
- Object[] msgArgs = {Long.valueOf(advertisedLength), Long.valueOf(actualLength)};
+ Object[] msgArgs = {advertisedLength, actualLength};
error(form.format(msgArgs), SQLState.DATA_EXCEPTION_LENGTH_MISMATCH, DriverError.NOT_SET);
}
}
@@ -3866,10 +3936,10 @@ void writeNonUnicodeReader(Reader reader,
// the actual stream length did not match then cancel the request.
if (DataTypes.UNKNOWN_STREAM_LENGTH != advertisedLength && actualLength != advertisedLength) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_mismatchedStreamLength"));
- Object[] msgArgs = {Long.valueOf(advertisedLength), Long.valueOf(actualLength)};
+ 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
@@ -3931,7 +4001,7 @@ void writeReader(Reader reader,
// the actual stream length did not match then cancel the request.
if (DataTypes.UNKNOWN_STREAM_LENGTH != advertisedLength && actualLength != advertisedLength) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_mismatchedStreamLength"));
- Object[] msgArgs = {Long.valueOf(advertisedLength), Long.valueOf(actualLength)};
+ Object[] msgArgs = {advertisedLength, actualLength};
error(form.format(msgArgs), SQLState.DATA_EXCEPTION_LENGTH_MISMATCH, DriverError.NOT_SET);
}
}
@@ -4153,7 +4223,7 @@ void writeRPCBit(String sName,
}
else {
writeByte((byte) 1); // length of datatype
- writeByte((byte) (booleanValue.booleanValue() ? 1 : 0));
+ writeByte((byte) (booleanValue ? 1 : 0));
}
}
@@ -4177,7 +4247,7 @@ void writeRPCByte(String sName,
}
else {
writeByte((byte) 1); // length of datatype
- writeByte(byteValue.byteValue());
+ writeByte(byteValue);
}
}
@@ -4201,7 +4271,7 @@ void writeRPCShort(String sName,
}
else {
writeByte((byte) 2); // length of datatype
- writeShort(shortValue.shortValue());
+ writeShort(shortValue);
}
}
@@ -4225,7 +4295,7 @@ void writeRPCInt(String sName,
}
else {
writeByte((byte) 4); // length of datatype
- writeInt(intValue.intValue());
+ writeInt(intValue);
}
}
@@ -4249,7 +4319,7 @@ void writeRPCLong(String sName,
}
else {
writeByte((byte) 8); // length of datatype
- writeLong(longValue.longValue());
+ writeLong(longValue);
}
}
@@ -4276,7 +4346,19 @@ void writeRPCReal(String sName,
else {
writeByte((byte) 4); // max length
writeByte((byte) 4); // actual length
- writeInt(Float.floatToRawIntBits(floatValue.floatValue()));
+ writeInt(Float.floatToRawIntBits(floatValue));
+ }
+ }
+
+ void writeRPCSqlVariant(String sName,
+ SqlVariant sqlVariantValue,
+ boolean bOut) throws SQLServerException {
+ writeRPCNameValType(sName, bOut, TDSType.SQL_VARIANT);
+
+ // Data and length
+ if (null == sqlVariantValue) {
+ writeInt(0); // max length
+ writeInt(0); // actual length
}
}
@@ -4304,7 +4386,7 @@ void writeRPCDouble(String sName,
}
else {
writeByte((byte) l); // len of data bytes
- long bits = Double.doubleToLongBits(doubleValue.doubleValue());
+ long bits = Double.doubleToLongBits(doubleValue);
long mask = 0xFF;
int nShift = 0;
for (int i = 0; i < 8; i++) {
@@ -4526,9 +4608,6 @@ void writeTVP(TVP value) throws SQLServerException {
}
void writeTVPRows(TVP value) throws SQLServerException {
- boolean isShortValue, isNull;
- int dataLength;
-
boolean tdsWritterCached = false;
ByteBuffer cachedTVPHeaders = null;
TDSCommand cachedCommand = null;
@@ -4536,7 +4615,7 @@ void writeTVPRows(TVP value) throws SQLServerException {
boolean cachedRequestComplete = false;
boolean cachedInterruptsEnabled = false;
boolean cachedProcessedResponse = false;
-
+
if (!value.isNull()) {
// If the preparedStatement and the ResultSet are created by the same connection, and TVP is set with ResultSet and Server Cursor
@@ -4566,12 +4645,12 @@ void writeTVPRows(TVP value) throws SQLServerException {
}
}
}
-
+
Map columnMetadata = value.getColumnMetadata();
Iterator> columnsIterator;
while (value.next()) {
-
+
// restore command and TDS header, which have been overwritten by value.next()
if (tdsWritterCached) {
command = cachedCommand;
@@ -4580,7 +4659,7 @@ void writeTVPRows(TVP value) throws SQLServerException {
logBuffer.clear();
writeBytes(cachedTVPHeaders.array(), 0, cachedTVPHeaders.position());
}
-
+
Object[] rowData = value.getRowData();
// ROW
@@ -4609,201 +4688,7 @@ void writeTVPRows(TVP value) throws SQLServerException {
}
}
}
- try {
- switch (jdbcType) {
- case BIGINT:
- if (null == currentColumnStringValue)
- writeByte((byte) 0);
- else {
- writeByte((byte) 8);
- writeLong(Long.valueOf(currentColumnStringValue).longValue());
- }
- break;
-
- case BIT:
- if (null == currentColumnStringValue)
- writeByte((byte) 0);
- else {
- writeByte((byte) 1);
- writeByte((byte) (Boolean.valueOf(currentColumnStringValue).booleanValue() ? 1 : 0));
- }
- break;
-
- case INTEGER:
- if (null == currentColumnStringValue)
- writeByte((byte) 0);
- else {
- writeByte((byte) 4);
- writeInt(Integer.valueOf(currentColumnStringValue).intValue());
- }
- break;
-
- case SMALLINT:
- case TINYINT:
- if (null == currentColumnStringValue)
- writeByte((byte) 0);
- else {
- writeByte((byte) 2); // length of datatype
- writeShort(Short.valueOf(currentColumnStringValue).shortValue());
- }
- break;
-
- case DECIMAL:
- case NUMERIC:
- if (null == currentColumnStringValue)
- writeByte((byte) 0);
- 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
- */
- bdValue = bdValue.setScale(columnPair.getValue().scale, RoundingMode.HALF_UP);
-
- byte[] valueBytes = DDC.convertBigDecimalToBytes(bdValue, bdValue.scale());
-
- // 1-byte for sign and 16-byte for integer
- byte[] byteValue = new byte[17];
-
- // removing the precision and scale information from the valueBytes array
- System.arraycopy(valueBytes, 2, byteValue, 0, valueBytes.length - 2);
- writeBytes(byteValue);
- }
- break;
-
- case DOUBLE:
- if (null == currentColumnStringValue)
- writeByte((byte) 0); // len of data bytes
- else {
- writeByte((byte) 8); // len of data bytes
- long bits = Double.doubleToLongBits(Double.valueOf(currentColumnStringValue).doubleValue());
- long mask = 0xFF;
- int nShift = 0;
- for (int i = 0; i < 8; i++) {
- writeByte((byte) ((bits & mask) >> nShift));
- nShift += 8;
- mask = mask << 8;
- }
- }
- break;
-
- case FLOAT:
- case REAL:
- if (null == currentColumnStringValue)
- writeByte((byte) 0); // actual length (0 == null)
- else {
- writeByte((byte) 4); // actual length
- writeInt(Float.floatToRawIntBits(Float.valueOf(currentColumnStringValue).floatValue()));
- }
- break;
-
- case DATE:
- case TIME:
- case TIMESTAMP:
- case DATETIMEOFFSET:
- case TIMESTAMP_WITH_TIMEZONE:
- case TIME_WITH_TIMEZONE:
- case CHAR:
- case VARCHAR:
- case NCHAR:
- case NVARCHAR:
- case LONGVARCHAR:
- case LONGNVARCHAR:
- case SQLXML:
- isShortValue = (2L * columnPair.getValue().precision) <= DataTypes.SHORT_VARTYPE_MAX_BYTES;
- isNull = (null == currentColumnStringValue);
- dataLength = isNull ? 0 : currentColumnStringValue.length() * 2;
- if (!isShortValue) {
- // check null
- if (isNull)
- // Null header for v*max types is 0xFFFFFFFFFFFFFFFF.
- writeLong(0xFFFFFFFFFFFFFFFFL);
- else if (DataTypes.UNKNOWN_STREAM_LENGTH == dataLength)
- // Append v*max length.
- // UNKNOWN_PLP_LEN is 0xFFFFFFFFFFFFFFFE
- writeLong(0xFFFFFFFFFFFFFFFEL);
- else
- // For v*max types with known length, length is
- writeLong(dataLength);
- if (!isNull) {
- if (dataLength > 0) {
- writeInt(dataLength);
- writeString(currentColumnStringValue);
- }
- // Send the terminator PLP chunk.
- writeInt(0);
- }
- }
- else {
- if (isNull)
- writeShort((short) -1); // actual len
- else {
- writeShort((short) dataLength);
- writeString(currentColumnStringValue);
- }
- }
- break;
-
- case BINARY:
- case VARBINARY:
- case LONGVARBINARY:
- // Handle conversions as done in other types.
- isShortValue = columnPair.getValue().precision <= DataTypes.SHORT_VARTYPE_MAX_BYTES;
- isNull = (null == currentObject);
- if (currentObject instanceof String)
- dataLength = isNull ? 0 : (toByteArray(currentObject.toString())).length;
- else
- dataLength = isNull ? 0 : ((byte[]) currentObject).length;
- if (!isShortValue) {
- // check null
- if (isNull)
- // Null header for v*max types is 0xFFFFFFFFFFFFFFFF.
- writeLong(0xFFFFFFFFFFFFFFFFL);
- else if (DataTypes.UNKNOWN_STREAM_LENGTH == dataLength)
- // Append v*max length.
- // UNKNOWN_PLP_LEN is 0xFFFFFFFFFFFFFFFE
- writeLong(0xFFFFFFFFFFFFFFFEL);
- else
- // For v*max types with known length, length is
- writeLong(dataLength);
- if (!isNull) {
- if (dataLength > 0) {
- writeInt(dataLength);
- if (currentObject instanceof String)
- writeBytes(toByteArray(currentObject.toString()));
- else
- writeBytes((byte[]) currentObject);
- }
- // Send the terminator PLP chunk.
- writeInt(0);
- }
- }
- else {
- if (isNull)
- writeShort((short) -1); // actual len
- else {
- writeShort((short) dataLength);
- if (currentObject instanceof String)
- writeBytes(toByteArray(currentObject.toString()));
- else
- writeBytes((byte[]) currentObject);
- }
- }
- break;
-
- default:
- assert false : "Unexpected JDBC type " + jdbcType.toString();
- }
- }
- catch (IllegalArgumentException e) {
- throw new SQLServerException(SQLServerException.getErrString("R_errorConvertingValue"), e);
- }
- catch (ArrayIndexOutOfBoundsException e) {
- throw new SQLServerException(SQLServerException.getErrString("R_CSVDataSchemaMismatch"), e);
- }
+ writeInternalTVPRowValues(jdbcType, currentColumnStringValue, currentObject, columnPair, false);
currentColumn++;
}
@@ -4842,6 +4727,303 @@ else if (DataTypes.UNKNOWN_STREAM_LENGTH == dataLength)
}
}
+ private void writeInternalTVPRowValues(JDBCType jdbcType,
+ String currentColumnStringValue,
+ Object currentObject,
+ Map.Entry columnPair,
+ boolean isSqlVariant) throws SQLServerException {
+ boolean isShortValue, isNull;
+ int dataLength;
+ switch (jdbcType) {
+ case BIGINT:
+ if (null == currentColumnStringValue)
+ writeByte((byte) 0);
+ else {
+ if (isSqlVariant) {
+ writeTVPSqlVariantHeader(10, TDSType.INT8.byteValue(), (byte) 0);
+ }
+ else {
+ writeByte((byte) 8);
+ }
+ writeLong(Long.valueOf(currentColumnStringValue).longValue());
+ }
+ break;
+
+ case BIT:
+ if (null == currentColumnStringValue)
+ writeByte((byte) 0);
+ else {
+ if (isSqlVariant)
+ writeTVPSqlVariantHeader(3, TDSType.BIT1.byteValue(), (byte) 0);
+ else
+ writeByte((byte) 1);
+ writeByte((byte) (Boolean.valueOf(currentColumnStringValue).booleanValue() ? 1 : 0));
+ }
+ break;
+
+ case INTEGER:
+ if (null == currentColumnStringValue)
+ writeByte((byte) 0);
+ else {
+ if (!isSqlVariant)
+ writeByte((byte) 4);
+ else
+ writeTVPSqlVariantHeader(6, TDSType.INT4.byteValue(), (byte) 0);
+ writeInt(Integer.valueOf(currentColumnStringValue).intValue());
+ }
+ break;
+
+ case SMALLINT:
+ case TINYINT:
+ if (null == currentColumnStringValue)
+ writeByte((byte) 0);
+ else {
+ if (isSqlVariant) {
+ writeTVPSqlVariantHeader(6, TDSType.INT4.byteValue(), (byte) 0);
+ writeInt(Integer.valueOf(currentColumnStringValue));
+ }
+ else {
+ writeByte((byte) 2); // length of datatype
+ writeShort(Short.valueOf(currentColumnStringValue).shortValue());
+ }
+ }
+ break;
+
+ case DECIMAL:
+ case NUMERIC:
+ if (null == currentColumnStringValue)
+ writeByte((byte) 0);
+ else {
+ if (isSqlVariant) {
+ writeTVPSqlVariantHeader(21, TDSType.DECIMALN.byteValue(), (byte) 2);
+ writeByte((byte) 38); // scale (byte)variantType.getScale()
+ writeByte((byte) 4); // scale (byte)variantType.getScale()
+ }
+ 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
+ */
+ bdValue = bdValue.setScale(columnPair.getValue().scale, RoundingMode.HALF_UP);
+
+ byte[] valueBytes = DDC.convertBigDecimalToBytes(bdValue, bdValue.scale());
+
+ // 1-byte for sign and 16-byte for integer
+ byte[] byteValue = new byte[17];
+
+ // removing the precision and scale information from the valueBytes array
+ System.arraycopy(valueBytes, 2, byteValue, 0, valueBytes.length - 2);
+ writeBytes(byteValue);
+ }
+ break;
+
+ case DOUBLE:
+ if (null == currentColumnStringValue)
+ writeByte((byte) 0); // len of data bytes
+ else {
+ if (isSqlVariant) {
+ writeTVPSqlVariantHeader(10, TDSType.FLOAT8.byteValue(), (byte) 0);
+ writeDouble(Double.valueOf(currentColumnStringValue.toString()));
+ break;
+ }
+ writeByte((byte) 8); // len of data bytes
+ long bits = Double.doubleToLongBits(Double.valueOf(currentColumnStringValue).doubleValue());
+ long mask = 0xFF;
+ int nShift = 0;
+ for (int i = 0; i < 8; i++) {
+ writeByte((byte) ((bits & mask) >> nShift));
+ nShift += 8;
+ mask = mask << 8;
+ }
+ }
+ break;
+
+ case FLOAT:
+ case REAL:
+ if (null == currentColumnStringValue)
+ writeByte((byte) 0);
+ else {
+ if (isSqlVariant) {
+ writeTVPSqlVariantHeader(6, TDSType.FLOAT4.byteValue(), (byte) 0);
+ writeInt(Float.floatToRawIntBits(Float.valueOf(currentColumnStringValue).floatValue()));
+ }
+ else {
+ writeByte((byte) 4);
+ writeInt(Float.floatToRawIntBits(Float.valueOf(currentColumnStringValue).floatValue()));
+ }
+ }
+ break;
+
+ case DATE:
+ case TIME:
+ case TIMESTAMP:
+ case DATETIMEOFFSET:
+ case TIMESTAMP_WITH_TIMEZONE:
+ case TIME_WITH_TIMEZONE:
+ case CHAR:
+ case VARCHAR:
+ case NCHAR:
+ case NVARCHAR:
+ case LONGVARCHAR:
+ case LONGNVARCHAR:
+ case SQLXML:
+ isShortValue = (2L * columnPair.getValue().precision) <= DataTypes.SHORT_VARTYPE_MAX_BYTES;
+ isNull = (null == currentColumnStringValue);
+ dataLength = isNull ? 0 : currentColumnStringValue.length() * 2;
+ if (!isShortValue) {
+ // check null
+ 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
+ // 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.
+ // 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"));
+ throw new SQLServerException(null, form.format(new Object[] {}), null, 0, false);
+ }
+ int length = currentColumnStringValue.length();
+ writeTVPSqlVariantHeader(9 + length, TDSType.BIGVARCHAR.byteValue(), (byte) 0x07);
+ SQLCollation col = con.getDatabaseCollation();
+ // write collation for sql variant
+ writeInt(col.getCollationInfo());
+ writeByte((byte) col.getCollationSortID());
+ writeShort((short) (length));
+ writeBytes(currentColumnStringValue.getBytes());
+ break;
+ }
+
+ else if (DataTypes.UNKNOWN_STREAM_LENGTH == dataLength)
+ // Append v*max length.
+ // UNKNOWN_PLP_LEN is 0xFFFFFFFFFFFFFFFE
+ writeLong(0xFFFFFFFFFFFFFFFEL);
+ else
+ // For v*max types with known length, length is
+ writeLong(dataLength);
+ if (!isNull) {
+ if (dataLength > 0) {
+ writeInt(dataLength);
+ writeString(currentColumnStringValue);
+ }
+ // Send the terminator PLP chunk.
+ writeInt(0);
+ }
+ }
+ 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
+ // check for this
+ int length = currentColumnStringValue.length() * 2;
+ writeTVPSqlVariantHeader(9 + length, TDSType.NVARCHAR.byteValue(), (byte) 7);
+ SQLCollation col = con.getDatabaseCollation();
+ // write collation for sql variant
+ writeInt(col.getCollationInfo());
+ writeByte((byte) col.getCollationSortID());
+ int stringLength = currentColumnStringValue.length();
+ byte[] typevarlen = new byte[2];
+ typevarlen[0] = (byte) (2 * stringLength & 0xFF);
+ typevarlen[1] = (byte) ((2 * stringLength >> 8) & 0xFF);
+ writeBytes(typevarlen);
+ writeString(currentColumnStringValue);
+ break;
+ }
+ else {
+ writeShort((short) dataLength);
+ writeString(currentColumnStringValue);
+ }
+ }
+ }
+ break;
+
+ case BINARY:
+ case VARBINARY:
+ case LONGVARBINARY:
+ // Handle conversions as done in other types.
+ isShortValue = columnPair.getValue().precision <= DataTypes.SHORT_VARTYPE_MAX_BYTES;
+ isNull = (null == currentObject);
+ if (currentObject instanceof String)
+ dataLength = isNull ? 0 : (toByteArray(currentObject.toString())).length;
+ else
+ dataLength = isNull ? 0 : ((byte[]) currentObject).length;
+ if (!isShortValue) {
+ // check null
+ if (isNull)
+ // Null header for v*max types is 0xFFFFFFFFFFFFFFFF.
+ writeLong(0xFFFFFFFFFFFFFFFFL);
+ else if (DataTypes.UNKNOWN_STREAM_LENGTH == dataLength)
+ // Append v*max length.
+ // UNKNOWN_PLP_LEN is 0xFFFFFFFFFFFFFFFE
+ writeLong(0xFFFFFFFFFFFFFFFEL);
+ else
+ // For v*max types with known length, length is
+ writeLong(dataLength);
+ if (!isNull) {
+ if (dataLength > 0) {
+ writeInt(dataLength);
+ if (currentObject instanceof String)
+ writeBytes(toByteArray(currentObject.toString()));
+ else
+ writeBytes((byte[]) currentObject);
+ }
+ // Send the terminator PLP chunk.
+ writeInt(0);
+ }
+ }
+ else {
+ if (isNull)
+ writeShort((short) -1); // actual len
+ else {
+ writeShort((short) dataLength);
+ if (currentObject instanceof String)
+ writeBytes(toByteArray(currentObject.toString()));
+ else
+ writeBytes((byte[]) currentObject);
+ }
+ }
+ break;
+ case SQL_VARIANT:
+ boolean isShiloh = (8 >= con.getServerMajorVersion() ? true : false);
+ if (isShiloh) {
+ MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_SQLVariantSupport"));
+ throw new SQLServerException(null, form.format(new Object[] {}), null, 0, false);
+ }
+ JDBCType internalJDBCType;
+ JavaType javaType = JavaType.of(currentObject);
+ internalJDBCType = javaType.getJDBCType(SSType.UNKNOWN, jdbcType);
+ writeInternalTVPRowValues(internalJDBCType, currentColumnStringValue, currentObject, columnPair, true);
+ break;
+ default:
+ assert false : "Unexpected JDBC type " + jdbcType.toString();
+ }
+ }
+
+ /**
+ * 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 {
+ writeInt(length);
+ writeByte(tdsType);
+ writeByte(probBytes);
+ }
+
private static byte[] toByteArray(String s) {
return DatatypeConverter.parseHexBinary(s);
}
@@ -4958,6 +5140,11 @@ void writeTVPColumnMetaData(TVP value) throws SQLServerException {
else // non PLP
writeShort((short) DataTypes.SHORT_VARTYPE_MAX_BYTES);
break;
+ case SQL_VARIANT:
+ writeByte(TDSType.SQL_VARIANT.byteValue());
+ writeInt(TDS.SQL_VARIANT_LENGTH);// write length of sql variant 8009
+
+ break;
default:
assert false : "Unexpected JDBC type " + jdbcType.toString();
@@ -5525,6 +5712,7 @@ 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
@@ -5962,7 +6150,7 @@ void writeRPCInputStream(String sName,
if (streamLength >= maxStreamLength) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidLength"));
- Object[] msgArgs = {Long.valueOf(streamLength)};
+ Object[] msgArgs = {streamLength};
SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), "", true);
}
@@ -6928,11 +7116,12 @@ final class TimeoutTimer implements Runnable {
private final int timeoutSeconds;
private final TDSCommand command;
private volatile Future> task;
-
+
private static final ExecutorService executor = Executors.newCachedThreadPool(new ThreadFactory() {
private final ThreadGroup tg = new ThreadGroup(threadGroupName);
private final String threadNamePrefix = tg.getName() + "-";
private final AtomicInteger threadNumber = new AtomicInteger(0);
+
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(tg, r, threadNamePrefix + threadNumber.incrementAndGet());
@@ -6940,7 +7129,7 @@ public Thread newThread(Runnable r) {
return t;
}
});
-
+
private volatile boolean canceled = false;
TimeoutTimer(int timeoutSeconds,
@@ -6961,7 +7150,7 @@ final void stop() {
canceled = true;
}
- public void run() {
+ public void run() {
int secondsRemaining = timeoutSeconds;
try {
// Poll every second while time is left on the timer.
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/KeyVaultCredential.java b/src/main/java/com/microsoft/sqlserver/jdbc/KeyVaultCredential.java
index 70d99421a1..d0b5693c3d 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/KeyVaultCredential.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/KeyVaultCredential.java
@@ -8,13 +8,14 @@
package com.microsoft.sqlserver.jdbc;
-import java.util.Map;
-
-import org.apache.http.Header;
-import org.apache.http.message.BasicHeader;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import com.microsoft.aad.adal4j.AuthenticationContext;
+import com.microsoft.aad.adal4j.AuthenticationResult;
+import com.microsoft.aad.adal4j.ClientCredential;
import com.microsoft.azure.keyvault.authentication.KeyVaultCredentials;
-import com.microsoft.windowsazure.core.pipeline.filter.ServiceRequestContext;
/**
*
@@ -23,42 +24,46 @@
*/
class KeyVaultCredential extends KeyVaultCredentials {
- // this is the only supported access token type
- // https://msdn.microsoft.com/en-us/library/azure/dn645538.aspx
- private final String accessTokenType = "Bearer";
-
- SQLServerKeyVaultAuthenticationCallback authenticationCallback = null;
String clientId = null;
String clientKey = null;
- String accessToken = null;
- KeyVaultCredential(SQLServerKeyVaultAuthenticationCallback authenticationCallback) {
- this.authenticationCallback = authenticationCallback;
+ KeyVaultCredential(String clientId,
+ String clientKey) {
+ this.clientId = clientId;
+ this.clientKey = clientKey;
}
- /**
- * Authenticates the service request
- *
- * @param request
- * the ServiceRequestContext
- * @param challenge
- * used to get the accessToken
- * @return BasicHeader
- */
- @Override
- public Header doAuthenticate(ServiceRequestContext request,
- Map challenge) {
- assert null != challenge;
-
- String authorization = challenge.get("authorization");
- String resource = challenge.get("resource");
-
- accessToken = authenticationCallback.getAccessToken(authorization, resource, "");
- return new BasicHeader("Authorization", accessTokenType + " " + accessToken);
+ public String doAuthenticate(String authorization,
+ String resource,
+ String scope) {
+ AuthenticationResult token = getAccessTokenFromClientCredentials(authorization, resource, clientId, clientKey);
+ return token.getAccessToken();
}
- void setAccessToken(String accessToken) {
- this.accessToken = accessToken;
- }
+ private static AuthenticationResult getAccessTokenFromClientCredentials(String authorization,
+ String resource,
+ String clientId,
+ String clientKey) {
+ AuthenticationContext context = null;
+ AuthenticationResult result = null;
+ ExecutorService service = null;
+ try {
+ service = Executors.newFixedThreadPool(1);
+ context = new AuthenticationContext(authorization, false, service);
+ ClientCredential credentials = new ClientCredential(clientId, clientKey);
+ Future future = context.acquireToken(resource, credentials, null);
+ result = future.get();
+ }
+ catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ finally {
+ service.shutdown();
+ }
+ if (result == null) {
+ throw new RuntimeException("authentication result was null");
+ }
+ return result;
+ }
}
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/Parameter.java b/src/main/java/com/microsoft/sqlserver/jdbc/Parameter.java
index 87ddcf88c2..afb71cd7fa 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/Parameter.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/Parameter.java
@@ -26,6 +26,7 @@
import java.util.Calendar;
import java.util.Locale;
+
/**
* 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.
@@ -253,7 +254,7 @@ void setFromReturnStatus(int returnStatus,
if (null == getterDTV)
getterDTV = new DTV();
- getterDTV.setValue(null, JDBCType.INTEGER, new 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,
@@ -415,7 +416,7 @@ Object getValue(JDBCType jdbcType,
int getInt(TDSReader tdsReader) throws SQLServerException {
Integer value = (Integer) getValue(JDBCType.INTEGER, null, null, tdsReader);
- return null != value ? value.intValue() : 0;
+ return null != value ? value : 0;
}
/**
@@ -494,8 +495,8 @@ private void setTypeDefinition(DTV dtv) {
// - the specified input scale (if any)
// - the registered output scale
Integer inScale = dtv.getScale();
- if (null != inScale && scale < inScale.intValue())
- scale = inScale.intValue();
+ if (null != inScale && scale < inScale)
+ scale = inScale;
if (param.isOutput() && scale < param.getOutScale())
scale = param.getOutScale();
@@ -878,7 +879,10 @@ 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;
default:
assert false : "Unexpected JDBC type " + dtv.getJdbcType();
break;
@@ -1133,6 +1137,17 @@ void execute(DTV dtv,
setTypeDefinition(dtv);
}
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.microsoft.sqlserver.jdbc.DTVExecuteOp#execute(com.microsoft.sqlserver.jdbc.DTV, microsoft.sql.SqlVariant)
+ */
+ @Override
+ void execute(DTV dtv,
+ SqlVariant SqlVariantValue) throws SQLServerException {
+ setTypeDefinition(dtv);
+ }
+
}
/**
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLCollation.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLCollation.java
index 46f08e9c2c..7a47b6fecd 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLCollation.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLCollation.java
@@ -47,6 +47,24 @@ final class SQLCollation implements java.io.Serializable
static final int tdsLength() { return 5; } // Length of collation in TDS (in bytes)
+ /**
+ * Returns the collation info
+ *
+ * @return
+ */
+ int getCollationInfo() {
+ return this.info;
+ }
+
+ /**
+ * return sort ID
+ *
+ * @return
+ */
+ int getCollationSortID() {
+ return this.sortId;
+ }
+
/**
* Reads TDS collation from TDS buffer into SQLCollation class.
* @param tdsReader
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLJdbcVersion.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLJdbcVersion.java
index f31892ebfe..94d392034c 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLJdbcVersion.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLJdbcVersion.java
@@ -10,7 +10,7 @@
final class SQLJdbcVersion {
static final int major = 6;
- static final int minor = 2;
+ static final int minor = 3;
static final int patch = 0;
static final int build = 0;
}
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBlob.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBlob.java
index 452455111f..ef74f5c488 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBlob.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBlob.java
@@ -197,13 +197,13 @@ public byte[] getBytes(long pos,
getBytesFromStream();
if (pos < 1) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidPositionIndex"));
- Object[] msgArgs = {new Long(pos)};
+ Object[] msgArgs = {pos};
SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true);
}
if (length < 0) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidLength"));
- Object[] msgArgs = {new Integer(length)};
+ Object[] msgArgs = {length};
SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true);
}
@@ -271,7 +271,7 @@ public long position(Blob pattern,
getBytesFromStream();
if (start < 1) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidPositionIndex"));
- Object[] msgArgs = {new Long(start)};
+ Object[] msgArgs = {start};
SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true);
}
@@ -299,7 +299,7 @@ public long position(byte[] bPattern,
getBytesFromStream();
if (start < 1) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidPositionIndex"));
- Object[] msgArgs = {new Long(start)};
+ Object[] msgArgs = {start};
SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true);
}
@@ -345,7 +345,7 @@ public void truncate(long len) throws SQLException {
if (len < 0) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidLength"));
- Object[] msgArgs = {new Long(len)};
+ Object[] msgArgs = {len};
SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true);
}
@@ -431,14 +431,14 @@ public int setBytes(long pos,
// Offset must be within incoming bytes boundary.
if (offset < 0 || offset > bytes.length) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidOffset"));
- Object[] msgArgs = {new Integer(offset)};
+ Object[] msgArgs = {offset};
SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true);
}
// len must be within incoming bytes boundary.
if (len < 0 || len > bytes.length - offset) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidLength"));
- Object[] msgArgs = {new Integer(len)};
+ Object[] msgArgs = {len};
SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true);
}
@@ -447,7 +447,7 @@ public int setBytes(long pos,
// past the end of data to request "append" mode.
if (pos <= 0 || pos > value.length + 1) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidPositionIndex"));
- Object[] msgArgs = {new Long(pos)};
+ Object[] msgArgs = {pos};
SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true);
}
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java
index 2fa3a3ef07..3076c90177 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java
@@ -1136,7 +1136,10 @@ private void writeTypeInfo(TDSWriter tdsWriter,
tdsWriter.writeByte((byte) srcScale);
}
break;
-
+ case microsoft.sql.Types.SQL_VARIANT: //0x62
+ tdsWriter.writeByte(TDSType.SQL_VARIANT.byteValue());
+ tdsWriter.writeInt(TDS.SQL_VARIANT_LENGTH);
+ break;
default:
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_BulkTypeNotSupported"));
String unsupportedDataType = JDBCType.of(srcJdbcType).toString().toLowerCase(Locale.ENGLISH);
@@ -1455,7 +1458,8 @@ private String getDestTypeFromSrcType(int srcColIndx,
else {
return "datetimeoffset(" + bulkScale + ")";
}
-
+ case microsoft.sql.Types.SQL_VARIANT:
+ return "sql_variant";
default: {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_BulkTypeNotSupported"));
Object[] msgArgs = {JDBCType.of(bulkJdbcType).toString().toLowerCase(Locale.ENGLISH)};
@@ -1483,7 +1487,7 @@ private String createInsertBulkCommand(TDSWriter tdsWriter) throws SQLServerExce
.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().trim().startsWith("char") || destType.toLowerCase().trim().startsWith("varchar")))
+ if (null != destType && (destType.toLowerCase(Locale.ENGLISH).trim().startsWith("char") || destType.toLowerCase(Locale.ENGLISH).trim().startsWith("varchar")))
addCollate = " COLLATE " + columnCollation;
}
bulkCmd.append("[" + colMapping.destinationColumnName + "] " + destType + addCollate + endColumn);
@@ -2045,6 +2049,9 @@ private void writeNullToTdsWriter(TDSWriter tdsWriter,
case microsoft.sql.Types.DATETIMEOFFSET:
tdsWriter.writeByte((byte) 0x00);
return;
+ case microsoft.sql.Types.SQL_VARIANT:
+ tdsWriter.writeInt((byte) 0x00);
+ return;
default:
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_BulkTypeNotSupported"));
Object[] msgArgs = {JDBCType.of(srcJdbcType).toString().toLowerCase(Locale.ENGLISH)};
@@ -2141,7 +2148,7 @@ else if (null != sourceBulkRecord) {
if (bulkNullable) {
tdsWriter.writeByte((byte) 0x01);
}
- tdsWriter.writeByte((byte) (((Boolean) colValue).booleanValue() ? 1 : 0));
+ tdsWriter.writeByte((byte) ((Boolean) colValue ? 1 : 0));
}
break;
@@ -2510,11 +2517,19 @@ else if (4 >= bulkScale)
tdsWriter.writeDateTimeOffset(colValue, bulkScale, destSSType);
}
break;
-
+ case microsoft.sql.Types.SQL_VARIANT:
+ boolean isShiloh = (8 >= connection.getServerMajorVersion() ? true : false);
+ if (isShiloh) {
+ 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);
+ break;
default:
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_BulkTypeNotSupported"));
Object[] msgArgs = {JDBCType.of(bulkJdbcType).toString().toLowerCase(Locale.ENGLISH)};
SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), null, true);
+ break;
} // End of switch
}
catch (ClassCastException ex) {
@@ -2528,6 +2543,279 @@ else if (4 >= bulkScale)
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 {
+ if (null == colValue) {
+ writeNullToTdsWriter(tdsWriter, bulkJdbcType, isStreaming);
+ return;
+ }
+ SqlVariant variantType = ((SQLServerResultSet) sourceResultSet).getVariantInternalType(srcColOrdinal);
+ int baseType = variantType.getBaseType();
+ // for sql variant we normally should return the colvalue for time as time string. but for
+ // bulkcopy we need it to be timestamp. so we have to retrieve it again once we are in bulkcopy
+ // and make sure that the base type is time.
+ if (TDSType.TIMEN == TDSType.valueOf(baseType)) {
+ variantType.setIsBaseTypeTimeValue(true);
+ ((SQLServerResultSet) sourceResultSet).setInternalVariantType(srcColOrdinal, variantType);
+ colValue = ((SQLServerResultSet) sourceResultSet).getObject(srcColOrdinal);
+ }
+ switch (TDSType.valueOf(baseType)) {
+ case INT8:
+ 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
+ writeBulkCopySqlVariantHeader(21, TDSType.DECIMALN.byteValue(), (byte) 2, tdsWriter);
+ tdsWriter.writeByte((byte) 38);
+ 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 timeHeaderLength = 0x08; // default
+ if (2 >= bulkScale) {
+ timeHeaderLength = 0x06;
+ }
+ else if (4 >= bulkScale) {
+ timeHeaderLength = 0x07;
+ }
+ else {
+ timeHeaderLength = 0x08;
+ }
+ 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);
+ 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
+ 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
+ // 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.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());
+ }
+ 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.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());
+ }
+ 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
+ int stringLength = colValue.toString().length();
+ byte[] typevarlen = new byte[2];
+ typevarlen[0] = (byte) (2 * stringLength & 0xFF);
+ typevarlen[1] = (byte) ((2 * stringLength >> 8) & 0xFF);
+ 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
+ stringLength = colValue.toString().length();
+ typevarlen = new byte[2];
+ typevarlen[0] = (byte) (2 * stringLength & 0xFF);
+ typevarlen[1] = (byte) ((2 * stringLength >> 8) & 0xFF);
+ 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
+ // 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();
+ variantType.setCollation(collation);
+ 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());
+ }
+ break;
+
+ case BIGBINARY:
+ byte[] b = (byte[]) colValue;
+ length = b.length;
+ writeBulkCopySqlVariantHeader(4 + length, TDSType.BIGVARBINARY.byteValue(), (byte) 2, tdsWriter);
+ tdsWriter.writeShort((short) (variantType.getMaxLength())); // length
+ if (null == colValue) {
+ writeNullToTdsWriter(tdsWriter, bulkJdbcType, isStreaming);
+ }
+ else {
+ byte[] srcBytes;
+ if (colValue instanceof byte[]) {
+ srcBytes = (byte[]) colValue;
+ }
+ else {
+ try {
+ srcBytes = ParameterUtils.HexToBin(colValue.toString());
+ }
+ catch (SQLServerException e) {
+ throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveSourceData"), e);
+ }
+ }
+ tdsWriter.writeBytes(srcBytes);
+ }
+ break;
+
+ case BIGVARBINARY:
+ b = (byte[]) colValue;
+ length = b.length;
+ writeBulkCopySqlVariantHeader(4 + length, TDSType.BIGVARBINARY.byteValue(), (byte) 2, tdsWriter);
+ tdsWriter.writeShort((short) (variantType.getMaxLength())); // length
+ if (null == colValue) {
+ writeNullToTdsWriter(tdsWriter, bulkJdbcType, isStreaming);
+ }
+ else {
+ byte[] srcBytes;
+ if (colValue instanceof byte[]) {
+ srcBytes = (byte[]) colValue;
+ }
+ else {
+ try {
+ srcBytes = ParameterUtils.HexToBin(colValue.toString());
+ }
+ 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)};
+ SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), null, true);
+ break;
+ }
+ }
+
+ /**
+ * Write header for sql_variant
+ *
+ * @param length:
+ * length of base type + Basetype + probBytes
+ * @param tdsType
+ * @param probBytes
+ * @param tdsWriter
+ * @throws SQLServerException
+ */
+ 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,
@@ -2630,14 +2918,16 @@ private Object readColumnFromResultSet(int srcColOrdinal,
// 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:
+ return sourceResultSet.getObject(srcColOrdinal);
default:
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_BulkTypeNotSupported"));
Object[] msgArgs = {JDBCType.of(srcJdbcType).toString().toLowerCase(Locale.ENGLISH)};
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;
- } // End of switch
- }// End of Try
+ }
+ }
catch (SQLException e) {
throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveSourceData"), e);
}
@@ -3030,57 +3320,57 @@ private byte[] normalizedValue(JDBCType destJdbcType,
try {
switch (destJdbcType) {
case BIT:
- longValue = Long.valueOf((Boolean) value ? 1 : 0);
- return ByteBuffer.allocate(Long.SIZE / Byte.SIZE).order(ByteOrder.LITTLE_ENDIAN).putLong(longValue.longValue()).array();
+ longValue = (long) ((Boolean) value ? 1 : 0);
+ return ByteBuffer.allocate(Long.SIZE / Byte.SIZE).order(ByteOrder.LITTLE_ENDIAN).putLong(longValue).array();
case TINYINT:
case SMALLINT:
switch (srcJdbcType) {
case BIT:
- longValue = new Long((Boolean) value ? 1 : 0);
+ longValue = (long) ((Boolean) value ? 1 : 0);
break;
default:
if (value instanceof Integer) {
int intValue = (int) value;
short shortValue = (short) intValue;
- longValue = new Long(shortValue);
+ longValue = (long) shortValue;
}
else
- longValue = new Long((short) value);
+ longValue = (long) (short) value;
}
- return ByteBuffer.allocate(Long.SIZE / Byte.SIZE).order(ByteOrder.LITTLE_ENDIAN).putLong(longValue.longValue()).array();
+ return ByteBuffer.allocate(Long.SIZE / Byte.SIZE).order(ByteOrder.LITTLE_ENDIAN).putLong(longValue).array();
case INTEGER:
switch (srcJdbcType) {
case BIT:
- longValue = new Long((Boolean) value ? 1 : 0);
+ longValue = (long) ((Boolean) value ? 1 : 0);
break;
case TINYINT:
case SMALLINT:
- longValue = new Long((short) value);
+ longValue = (long) (short) value;
break;
default:
longValue = new Long((Integer) value);
}
- return ByteBuffer.allocate(Long.SIZE / Byte.SIZE).order(ByteOrder.LITTLE_ENDIAN).putLong(longValue.longValue()).array();
+ return ByteBuffer.allocate(Long.SIZE / Byte.SIZE).order(ByteOrder.LITTLE_ENDIAN).putLong(longValue).array();
case BIGINT:
switch (srcJdbcType) {
case BIT:
- longValue = new Long((Boolean) value ? 1 : 0);
+ longValue = (long) ((Boolean) value ? 1 : 0);
break;
case TINYINT:
case SMALLINT:
- longValue = new Long((short) value);
+ longValue = (long) (short) value;
break;
case INTEGER:
longValue = new Long((Integer) value);
break;
default:
- longValue = new Long((long) value);
+ longValue = (long) value;
}
- return ByteBuffer.allocate(Long.SIZE / Byte.SIZE).order(ByteOrder.LITTLE_ENDIAN).putLong(longValue.longValue()).array();
+ return ByteBuffer.allocate(Long.SIZE / Byte.SIZE).order(ByteOrder.LITTLE_ENDIAN).putLong(longValue).array();
case BINARY:
case VARBINARY:
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerCallableStatement.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerCallableStatement.java
index 2dd460cc38..e5eaa7ccf5 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerCallableStatement.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerCallableStatement.java
@@ -30,6 +30,7 @@
import java.text.MessageFormat;
import java.util.ArrayList;
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
@@ -89,11 +90,11 @@ String getClassNameInternal() {
public void registerOutParameter(int index,
int sqlType) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
- loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {new Integer(index), new Integer(sqlType)});
+ loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {index, sqlType});
checkClosed();
if (index < 1 || index > inOutParam.length) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_indexOutOfRange"));
- Object[] msgArgs = {new Integer(index)};
+ Object[] msgArgs = {index};
SQLServerException.makeFromDriverError(connection, this, form.format(msgArgs), "7009", false);
}
@@ -318,7 +319,7 @@ boolean onRetValue(TDSReader tdsReader) throws SQLServerException {
// If we were asked to retain the OUT parameters as we skip past them,
// then report an error if we did not find any.
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_valueNotSetForParameter"));
- Object[] msgArgs = {new Integer(outParamIndex + 1)};
+ Object[] msgArgs = {outParamIndex + 1};
SQLServerException.makeFromDriverError(connection, this, form.format(msgArgs), null, false);
}
@@ -346,7 +347,7 @@ boolean onRetValue(TDSReader tdsReader) throws SQLServerException {
int sqlType,
String typeName) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
- loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {new Integer(index), new Integer(sqlType), typeName});
+ loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {index, sqlType, typeName});
checkClosed();
@@ -360,7 +361,7 @@ boolean onRetValue(TDSReader tdsReader) throws SQLServerException {
int scale) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "registerOutParameter",
- new Object[] {new Integer(index), new Integer(sqlType), new Integer(scale)});
+ new Object[] {index, sqlType, scale});
checkClosed();
@@ -376,7 +377,7 @@ public void registerOutParameter(int index,
int scale) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "registerOutParameter",
- new Object[] {new Integer(index), new Integer(sqlType), new Integer(scale), new Integer(precision)});
+ new Object[] {index, sqlType, scale, precision});
checkClosed();
@@ -395,14 +396,14 @@ private Parameter getterGetParam(int index) throws SQLServerException {
// Check for valid index
if (index < 1 || index > inOutParam.length) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidOutputParameter"));
- Object[] msgArgs = {new Integer(index)};
+ Object[] msgArgs = {index};
SQLServerException.makeFromDriverError(connection, this, form.format(msgArgs), "07009", false);
}
// Check index refers to a registered OUT parameter
if (!inOutParam[index - 1].isOutput()) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_outputParameterNotRegisteredForOutput"));
- Object[] msgArgs = {new Integer(index)};
+ Object[] msgArgs = {index};
SQLServerException.makeFromDriverError(connection, this, form.format(msgArgs), "07009", true);
}
@@ -457,7 +458,7 @@ public int getInt(int index) throws SQLServerException {
checkClosed();
Integer value = (Integer) getValue(index, JDBCType.INTEGER);
loggerExternal.exiting(getClassNameLogging(), "getInt", value);
- return null != value ? value.intValue() : 0;
+ return null != value ? value : 0;
}
public int getInt(String sCol) throws SQLServerException {
@@ -465,21 +466,29 @@ public int getInt(String sCol) throws SQLServerException {
checkClosed();
Integer value = (Integer) getValue(findColumn(sCol), JDBCType.INTEGER);
loggerExternal.exiting(getClassNameLogging(), "getInt", value);
- return null != value ? value.intValue() : 0;
+ return null != value ? value : 0;
}
public String getString(int index) throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "getString", index);
checkClosed();
- String value = (String) getValue(index, JDBCType.CHAR);
+ String value = null;
+ Object objectValue = getValue(index, JDBCType.CHAR);
+ if (null != objectValue) {
+ value = objectValue.toString();
+ }
loggerExternal.exiting(getClassNameLogging(), "getString", value);
return value;
}
-
+
public String getString(String sCol) throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "getString", sCol);
checkClosed();
- String value = (String) getValue(findColumn(sCol), JDBCType.CHAR);
+ String value = null;
+ Object objectValue = getValue(findColumn(sCol), JDBCType.CHAR);
+ if (null != objectValue) {
+ value = objectValue.toString();
+ }
loggerExternal.exiting(getClassNameLogging(), "getString", value);
return value;
}
@@ -504,7 +513,7 @@ public final String getNString(String parameterName) 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[] {Integer.valueOf(parameterIndex), Integer.valueOf(scale)});
+ loggerExternal.entering(getClassNameLogging(), "getBigDecimal", new Object[] {parameterIndex, scale});
checkClosed();
BigDecimal value = (BigDecimal) getValue(parameterIndex, JDBCType.DECIMAL);
if (null != value)
@@ -517,7 +526,7 @@ public BigDecimal getBigDecimal(int parameterIndex,
public BigDecimal getBigDecimal(String parameterName,
int scale) throws SQLException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
- loggerExternal.entering(getClassNameLogging(), "getBigDecimal", new Object[] {parameterName, Integer.valueOf(scale)});
+ loggerExternal.entering(getClassNameLogging(), "getBigDecimal", new Object[] {parameterName, scale});
checkClosed();
BigDecimal value = (BigDecimal) getValue(findColumn(parameterName), JDBCType.DECIMAL);
if (null != value)
@@ -531,7 +540,7 @@ public boolean getBoolean(int index) throws SQLServerException {
checkClosed();
Boolean value = (Boolean) getValue(index, JDBCType.BIT);
loggerExternal.exiting(getClassNameLogging(), "getBoolean", value);
- return null != value ? value.booleanValue() : false;
+ return null != value ? value : false;
}
public boolean getBoolean(String sCol) throws SQLServerException {
@@ -539,7 +548,7 @@ public boolean getBoolean(String sCol) throws SQLServerException {
checkClosed();
Boolean value = (Boolean) getValue(findColumn(sCol), JDBCType.BIT);
loggerExternal.exiting(getClassNameLogging(), "getBoolean", value);
- return null != value ? value.booleanValue() : false;
+ return null != value ? value : false;
}
public byte getByte(int index) throws SQLServerException {
@@ -617,7 +626,7 @@ public double getDouble(int index) throws SQLServerException {
checkClosed();
Double value = (Double) getValue(index, JDBCType.DOUBLE);
loggerExternal.exiting(getClassNameLogging(), "getDouble", value);
- return null != value ? value.doubleValue() : 0;
+ return null != value ? value : 0;
}
public double getDouble(String sCol) throws SQLServerException {
@@ -625,7 +634,7 @@ public double getDouble(String sCol) throws SQLServerException {
checkClosed();
Double value = (Double) getValue(findColumn(sCol), JDBCType.DOUBLE);
loggerExternal.exiting(getClassNameLogging(), "getDouble", value);
- return null != value ? value.doubleValue() : 0;
+ return null != value ? value : 0;
}
public float getFloat(int index) throws SQLServerException {
@@ -633,7 +642,7 @@ public float getFloat(int index) throws SQLServerException {
checkClosed();
Float value = (Float) getValue(index, JDBCType.REAL);
loggerExternal.exiting(getClassNameLogging(), "getFloat", value);
- return null != value ? value.floatValue() : 0;
+ return null != value ? value : 0;
}
public float getFloat(String sCol) throws SQLServerException {
@@ -642,7 +651,7 @@ public float getFloat(String sCol) throws SQLServerException {
checkClosed();
Float value = (Float) getValue(findColumn(sCol), JDBCType.REAL);
loggerExternal.exiting(getClassNameLogging(), "getFloat", value);
- return null != value ? value.floatValue() : 0;
+ return null != value ? value : 0;
}
public long getLong(int index) throws SQLServerException {
@@ -651,7 +660,7 @@ public long getLong(int index) throws SQLServerException {
checkClosed();
Long value = (Long) getValue(index, JDBCType.BIGINT);
loggerExternal.exiting(getClassNameLogging(), "getLong", value);
- return null != value ? value.longValue() : 0;
+ return null != value ? value : 0;
}
public long getLong(String sCol) throws SQLServerException {
@@ -659,7 +668,7 @@ public long getLong(String sCol) throws SQLServerException {
checkClosed();
Long value = (Long) getValue(findColumn(sCol), JDBCType.BIGINT);
loggerExternal.exiting(getClassNameLogging(), "getLong", value);
- return null != value ? value.longValue() : 0;
+ return null != value ? value : 0;
}
public Object getObject(int index) throws SQLServerException {
@@ -674,8 +683,84 @@ public Object getObject(int index) throws SQLServerException {
public T getObject(int index,
Class type) throws SQLException {
- // The driver currently does not implement the optional JDBC APIs
- throw new SQLFeatureNotSupportedException(SQLServerException.getErrString("R_notSupported"));
+ loggerExternal.entering(getClassNameLogging(), "getObject", index);
+ checkClosed();
+ Object returnValue;
+ if (type == String.class) {
+ returnValue = getString(index);
+ }
+ else if (type == Byte.class) {
+ byte byteValue = getByte(index);
+ returnValue = wasNull() ? null : byteValue;
+ }
+ else if (type == Short.class) {
+ short shortValue = getShort(index);
+ returnValue = wasNull() ? null : shortValue;
+ }
+ else if (type == Integer.class) {
+ int intValue = getInt(index);
+ returnValue = wasNull() ? null : intValue;
+ }
+ else if (type == Long.class) {
+ long longValue = getLong(index);
+ returnValue = wasNull() ? null : longValue;
+ }
+ else if (type == BigDecimal.class) {
+ returnValue = getBigDecimal(index);
+ }
+ else if (type == Boolean.class) {
+ boolean booleanValue = getBoolean(index);
+ returnValue = wasNull() ? null : booleanValue;
+ }
+ else if (type == java.sql.Date.class) {
+ returnValue = getDate(index);
+ }
+ else if (type == java.sql.Time.class) {
+ returnValue = getTime(index);
+ }
+ else if (type == java.sql.Timestamp.class) {
+ returnValue = getTimestamp(index);
+ }
+ else if (type == microsoft.sql.DateTimeOffset.class) {
+ returnValue = getDateTimeOffset(index);
+ }
+ 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) {
+ returnValue = getSQLXML(index);
+ }
+ else if (type == Blob.class) {
+ returnValue = getBlob(index);
+ }
+ else if (type == Clob.class) {
+ returnValue = getClob(index);
+ }
+ else if (type == NClob.class) {
+ returnValue = getNClob(index);
+ }
+ else if (type == byte[].class) {
+ returnValue = getBytes(index);
+ }
+ else if (type == Float.class) {
+ float floatValue = getFloat(index);
+ returnValue = wasNull() ? null : floatValue;
+ }
+ else if (type == Double.class) {
+ double doubleValue = getDouble(index);
+ returnValue = wasNull() ? null : doubleValue;
+ }
+ 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);
+ }
+ loggerExternal.exiting(getClassNameLogging(), "getObject", index);
+ return type.cast(returnValue);
}
public Object getObject(String sCol) throws SQLServerException {
@@ -690,8 +775,12 @@ public Object getObject(String sCol) throws SQLServerException {
public T getObject(String sCol,
Class type) throws SQLException {
- // The driver currently does not implement the optional JDBC APIs
- throw new SQLFeatureNotSupportedException(SQLServerException.getErrString("R_notSupported"));
+ loggerExternal.entering(getClassNameLogging(), "getObject", sCol);
+ checkClosed();
+ int parameterIndex = findColumn(sCol);
+ T value = getObject(parameterIndex, type);
+ loggerExternal.exiting(getClassNameLogging(), "getObject", value);
+ return value;
}
public short getShort(int index) throws SQLServerException {
@@ -700,7 +789,7 @@ public short getShort(int index) throws SQLServerException {
checkClosed();
Short value = (Short) getValue(index, JDBCType.SMALLINT);
loggerExternal.exiting(getClassNameLogging(), "getShort", value);
- return null != value ? value.shortValue() : 0;
+ return null != value ? value : 0;
}
public short getShort(String sCol) throws SQLServerException {
@@ -708,7 +797,7 @@ public short getShort(String sCol) throws SQLServerException {
checkClosed();
Short value = (Short) getValue(findColumn(sCol), JDBCType.SMALLINT);
loggerExternal.exiting(getClassNameLogging(), "getShort", value);
- return null != value ? value.shortValue() : 0;
+ return null != value ? value : 0;
}
public Time getTime(int index) throws SQLServerException {
@@ -1752,7 +1841,7 @@ public void setObject(String sCol,
// For all other types, this value will be ignored.
setObject(setterGetParam(findColumn(sCol)), o, JavaType.of(o), JDBCType.of(n),
- (java.sql.Types.NUMERIC == n || java.sql.Types.DECIMAL == n) ? Integer.valueOf(m) : null, null, forceEncrypt, findColumn(sCol), null);
+ (java.sql.Types.NUMERIC == n || java.sql.Types.DECIMAL == n) ? m : null, null, forceEncrypt, findColumn(sCol), null);
loggerExternal.exiting(getClassNameLogging(), "setObject");
}
@@ -1802,7 +1891,7 @@ public final void setObject(String sCol,
setObject(setterGetParam(findColumn(sCol)), 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)) ? Integer.valueOf(scale) : null,
+ || InputStream.class.isInstance(x) || Reader.class.isInstance(x)) ? scale : null,
precision, false, findColumn(sCol), null);
loggerExternal.exiting(getClassNameLogging(), "setObject");
@@ -2273,7 +2362,7 @@ public void setByte(String sCol,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setByte", new Object[] {sCol, b});
checkClosed();
- setValue(findColumn(sCol), JDBCType.TINYINT, Byte.valueOf(b), JavaType.BYTE, false);
+ setValue(findColumn(sCol), JDBCType.TINYINT, b, JavaType.BYTE, false);
loggerExternal.exiting(getClassNameLogging(), "setByte");
}
@@ -2299,7 +2388,7 @@ public void setByte(String sCol,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setByte", new Object[] {sCol, b, forceEncrypt});
checkClosed();
- setValue(findColumn(sCol), JDBCType.TINYINT, Byte.valueOf(b), JavaType.BYTE, forceEncrypt);
+ setValue(findColumn(sCol), JDBCType.TINYINT, b, JavaType.BYTE, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setByte");
}
@@ -2506,7 +2595,7 @@ public void setDouble(String sCol,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setDouble", new Object[] {sCol, d});
checkClosed();
- setValue(findColumn(sCol), JDBCType.DOUBLE, Double.valueOf(d), JavaType.DOUBLE, false);
+ setValue(findColumn(sCol), JDBCType.DOUBLE, d, JavaType.DOUBLE, false);
loggerExternal.exiting(getClassNameLogging(), "setDouble");
}
@@ -2532,7 +2621,7 @@ public void setDouble(String sCol,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setDouble", new Object[] {sCol, d, forceEncrypt});
checkClosed();
- setValue(findColumn(sCol), JDBCType.DOUBLE, Double.valueOf(d), JavaType.DOUBLE, forceEncrypt);
+ setValue(findColumn(sCol), JDBCType.DOUBLE, d, JavaType.DOUBLE, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setDouble");
}
@@ -2541,7 +2630,7 @@ public void setFloat(String sCol,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setFloat", new Object[] {sCol, f});
checkClosed();
- setValue(findColumn(sCol), JDBCType.REAL, Float.valueOf(f), JavaType.FLOAT, false);
+ setValue(findColumn(sCol), JDBCType.REAL, f, JavaType.FLOAT, false);
loggerExternal.exiting(getClassNameLogging(), "setFloat");
}
@@ -2567,7 +2656,7 @@ public void setFloat(String sCol,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setFloat", new Object[] {sCol, f, forceEncrypt});
checkClosed();
- setValue(findColumn(sCol), JDBCType.REAL, Float.valueOf(f), JavaType.FLOAT, forceEncrypt);
+ setValue(findColumn(sCol), JDBCType.REAL, f, JavaType.FLOAT, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setFloat");
}
@@ -2576,7 +2665,7 @@ public void setInt(String sCol,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setInt", new Object[] {sCol, i});
checkClosed();
- setValue(findColumn(sCol), JDBCType.INTEGER, Integer.valueOf(i), JavaType.INTEGER, false);
+ setValue(findColumn(sCol), JDBCType.INTEGER, i, JavaType.INTEGER, false);
loggerExternal.exiting(getClassNameLogging(), "setInt");
}
@@ -2602,7 +2691,7 @@ public void setInt(String sCol,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setInt", new Object[] {sCol, i, forceEncrypt});
checkClosed();
- setValue(findColumn(sCol), JDBCType.INTEGER, Integer.valueOf(i), JavaType.INTEGER, forceEncrypt);
+ setValue(findColumn(sCol), JDBCType.INTEGER, i, JavaType.INTEGER, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setInt");
}
@@ -2611,7 +2700,7 @@ public void setLong(String sCol,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setLong", new Object[] {sCol, l});
checkClosed();
- setValue(findColumn(sCol), JDBCType.BIGINT, Long.valueOf(l), JavaType.LONG, false);
+ setValue(findColumn(sCol), JDBCType.BIGINT, l, JavaType.LONG, false);
loggerExternal.exiting(getClassNameLogging(), "setLong");
}
@@ -2637,7 +2726,7 @@ public void setLong(String sCol,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setLong", new Object[] {sCol, l, forceEncrypt});
checkClosed();
- setValue(findColumn(sCol), JDBCType.BIGINT, Long.valueOf(l), JavaType.LONG, forceEncrypt);
+ setValue(findColumn(sCol), JDBCType.BIGINT, l, JavaType.LONG, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setLong");
}
@@ -2646,7 +2735,7 @@ public void setShort(String sCol,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setShort", new Object[] {sCol, s});
checkClosed();
- setValue(findColumn(sCol), JDBCType.SMALLINT, Short.valueOf(s), JavaType.SHORT, false);
+ setValue(findColumn(sCol), JDBCType.SMALLINT, s, JavaType.SHORT, false);
loggerExternal.exiting(getClassNameLogging(), "setShort");
}
@@ -2672,7 +2761,7 @@ public void setShort(String sCol,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setShort", new Object[] {sCol, s, forceEncrypt});
checkClosed();
- setValue(findColumn(sCol), JDBCType.SMALLINT, Short.valueOf(s), JavaType.SHORT, forceEncrypt);
+ setValue(findColumn(sCol), JDBCType.SMALLINT, s, JavaType.SHORT, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setShort");
}
@@ -2681,7 +2770,7 @@ public void setBoolean(String sCol,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setBoolean", new Object[] {sCol, b});
checkClosed();
- setValue(findColumn(sCol), JDBCType.BIT, Boolean.valueOf(b), JavaType.BOOLEAN, false);
+ setValue(findColumn(sCol), JDBCType.BIT, b, JavaType.BOOLEAN, false);
loggerExternal.exiting(getClassNameLogging(), "setBoolean");
}
@@ -2707,7 +2796,7 @@ public void setBoolean(String sCol,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setBoolean", new Object[] {sCol, b, forceEncrypt});
checkClosed();
- setValue(findColumn(sCol), JDBCType.BIT, Boolean.valueOf(b), JavaType.BOOLEAN, forceEncrypt);
+ setValue(findColumn(sCol), JDBCType.BIT, b, JavaType.BOOLEAN, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setBoolean");
}
@@ -2866,7 +2955,7 @@ public void registerOutParameter(String s,
int n,
String s1) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
- loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {s, new Integer(n), s1});
+ loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {s, n, s1});
checkClosed();
registerOutParameter(findColumn(s), n, s1);
loggerExternal.exiting(getClassNameLogging(), "registerOutParameter");
@@ -2877,7 +2966,7 @@ public void registerOutParameter(String parameterName,
int scale) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "registerOutParameter",
- new Object[] {parameterName, new Integer(sqlType), new Integer(scale)});
+ new Object[] {parameterName, sqlType, scale});
checkClosed();
registerOutParameter(findColumn(parameterName), sqlType, scale);
loggerExternal.exiting(getClassNameLogging(), "registerOutParameter");
@@ -2889,7 +2978,7 @@ public void registerOutParameter(String parameterName,
int scale) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "registerOutParameter",
- new Object[] {parameterName, new Integer(sqlType), new Integer(scale)});
+ new Object[] {parameterName, sqlType, scale});
checkClosed();
registerOutParameter(findColumn(parameterName), sqlType, precision, scale);
loggerExternal.exiting(getClassNameLogging(), "registerOutParameter");
@@ -2898,7 +2987,7 @@ public void registerOutParameter(String parameterName,
public void registerOutParameter(String s,
int n) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
- loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {s, new Integer(n)});
+ loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {s, n});
checkClosed();
registerOutParameter(findColumn(s), n);
loggerExternal.exiting(getClassNameLogging(), "registerOutParameter");
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerCallableStatement42.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerCallableStatement42.java
index ee73cc1768..cf5e1f2460 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerCallableStatement42.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerCallableStatement42.java
@@ -34,10 +34,10 @@ public void registerOutParameter(int index,
DriverJDBCVersion.checkSupportsJDBC42();
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
- loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {new Integer(index), sqlType});
+ loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {index, sqlType});
// getVendorTypeNumber() returns the same constant integer values as in java.sql.Types
- registerOutParameter(index, sqlType.getVendorTypeNumber().intValue());
+ registerOutParameter(index, sqlType.getVendorTypeNumber());
loggerExternal.exiting(getClassNameLogging(), "registerOutParameter");
}
@@ -47,10 +47,10 @@ public void registerOutParameter(int index,
DriverJDBCVersion.checkSupportsJDBC42();
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
- loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {new Integer(index), sqlType, typeName});
+ loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {index, sqlType, typeName});
// getVendorTypeNumber() returns the same constant integer values as in java.sql.Types
- registerOutParameter(index, sqlType.getVendorTypeNumber().intValue(), typeName);
+ registerOutParameter(index, sqlType.getVendorTypeNumber(), typeName);
loggerExternal.exiting(getClassNameLogging(), "registerOutParameter");
}
@@ -61,10 +61,10 @@ public void registerOutParameter(int index,
DriverJDBCVersion.checkSupportsJDBC42();
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
- loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {new Integer(index), sqlType, new Integer(scale)});
+ loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {index, sqlType, scale});
// getVendorTypeNumber() returns the same constant integer values as in java.sql.Types
- registerOutParameter(index, sqlType.getVendorTypeNumber().intValue(), scale);
+ registerOutParameter(index, sqlType.getVendorTypeNumber(), scale);
loggerExternal.exiting(getClassNameLogging(), "registerOutParameter");
}
@@ -76,10 +76,10 @@ public void registerOutParameter(int index,
DriverJDBCVersion.checkSupportsJDBC42();
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
- loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {new Integer(index), sqlType, new Integer(scale)});
+ loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {index, sqlType, scale});
// getVendorTypeNumber() returns the same constant integer values as in java.sql.Types
- registerOutParameter(index, sqlType.getVendorTypeNumber().intValue(), precision, scale);
+ registerOutParameter(index, sqlType.getVendorTypeNumber(), precision, scale);
loggerExternal.exiting(getClassNameLogging(), "registerOutParameter");
}
@@ -93,7 +93,7 @@ public void setObject(String sCol,
loggerExternal.entering(getClassNameLogging(), "setObject", new Object[] {sCol, obj, jdbcType});
// getVendorTypeNumber() returns the same constant integer values as in java.sql.Types
- setObject(sCol, obj, jdbcType.getVendorTypeNumber().intValue());
+ setObject(sCol, obj, jdbcType.getVendorTypeNumber());
loggerExternal.exiting(getClassNameLogging(), "setObject");
}
@@ -108,7 +108,7 @@ public void setObject(String sCol,
loggerExternal.entering(getClassNameLogging(), "setObject", new Object[] {sCol, obj, jdbcType, scale});
// getVendorTypeNumber() returns the same constant integer values as in java.sql.Types
- setObject(sCol, obj, jdbcType.getVendorTypeNumber().intValue(), scale);
+ setObject(sCol, obj, jdbcType.getVendorTypeNumber(), scale);
loggerExternal.exiting(getClassNameLogging(), "setObject");
}
@@ -124,7 +124,7 @@ public void setObject(String sCol,
loggerExternal.entering(getClassNameLogging(), "setObject", new Object[] {sCol, obj, jdbcType, scale, forceEncrypt});
// getVendorTypeNumber() returns the same constant integer values as in java.sql.Types
- setObject(sCol, obj, jdbcType.getVendorTypeNumber().intValue(), scale, forceEncrypt);
+ setObject(sCol, obj, jdbcType.getVendorTypeNumber(), scale, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setObject");
}
@@ -138,7 +138,7 @@ public void registerOutParameter(String parameterName,
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().intValue(), typeName);
+ registerOutParameter(parameterName, sqlType.getVendorTypeNumber(), typeName);
loggerExternal.exiting(getClassNameLogging(), "registerOutParameter");
}
@@ -149,10 +149,10 @@ public void registerOutParameter(String parameterName,
DriverJDBCVersion.checkSupportsJDBC42();
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
- loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {parameterName, sqlType, new Integer(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().intValue(), scale);
+ registerOutParameter(parameterName, sqlType.getVendorTypeNumber(), scale);
loggerExternal.exiting(getClassNameLogging(), "registerOutParameter");
}
@@ -164,10 +164,10 @@ public void registerOutParameter(String parameterName,
DriverJDBCVersion.checkSupportsJDBC42();
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
- loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {parameterName, sqlType, new Integer(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().intValue(), precision, scale);
+ registerOutParameter(parameterName, sqlType.getVendorTypeNumber(), precision, scale);
loggerExternal.exiting(getClassNameLogging(), "registerOutParameter");
}
@@ -180,7 +180,7 @@ public void registerOutParameter(String parameterName,
loggerExternal.entering(getClassNameLogging(), "registerOutParameter", new Object[] {parameterName, sqlType});
// getVendorTypeNumber() returns the same constant integer values as in java.sql.Types
- registerOutParameter(parameterName, sqlType.getVendorTypeNumber().intValue());
+ registerOutParameter(parameterName, sqlType.getVendorTypeNumber());
loggerExternal.exiting(getClassNameLogging(), "registerOutParameter");
}
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerClob.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerClob.java
index 3accc9e204..f933727cfe 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerClob.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerClob.java
@@ -275,13 +275,13 @@ public String getSubString(long pos,
getStringFromStream();
if (pos < 1) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidPositionIndex"));
- Object[] msgArgs = {new Long(pos)};
+ Object[] msgArgs = {pos};
SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true);
}
if (length < 0) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidLength"));
- Object[] msgArgs = {new Integer(length)};
+ Object[] msgArgs = {length};
SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true);
}
@@ -350,7 +350,7 @@ public long position(Clob searchstr,
getStringFromStream();
if (start < 1) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidPositionIndex"));
- Object[] msgArgs = {new Long(start)};
+ Object[] msgArgs = {start};
SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true);
}
@@ -379,7 +379,7 @@ public long position(String searchstr,
getStringFromStream();
if (start < 1) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidPositionIndex"));
- Object[] msgArgs = {new Long(start)};
+ Object[] msgArgs = {start};
SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true);
}
@@ -411,7 +411,7 @@ public void truncate(long len) throws SQLException {
getStringFromStream();
if (len < 0) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidLength"));
- Object[] msgArgs = {new Long(len)};
+ Object[] msgArgs = {len};
SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true);
}
@@ -433,7 +433,7 @@ public java.io.OutputStream setAsciiStream(long pos) throws SQLException {
if (pos < 1) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidPositionIndex"));
- Object[] msgArgs = {new Long(pos)};
+ Object[] msgArgs = {pos};
SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true);
}
@@ -454,7 +454,7 @@ public java.io.Writer setCharacterStream(long pos) throws SQLException {
if (pos < 1) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidPositionIndex"));
- Object[] msgArgs = {new Long(pos)};
+ Object[] msgArgs = {pos};
SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true);
}
@@ -514,14 +514,14 @@ public int setString(long pos,
// Offset must be within incoming string str boundary.
if (offset < 0 || offset > str.length()) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidOffset"));
- Object[] msgArgs = {new Integer(offset)};
+ Object[] msgArgs = {offset};
SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true);
}
// len must be within incoming string str boundary.
if (len < 0 || len > str.length() - offset) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidLength"));
- Object[] msgArgs = {new Integer(len)};
+ Object[] msgArgs = {len};
SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true);
}
@@ -530,7 +530,7 @@ public int setString(long pos,
// past the end of data to request "append" mode.
if (pos < 1 || pos > value.length() + 1) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidPositionIndex"));
- Object[] msgArgs = {new Long(pos)};
+ Object[] msgArgs = {pos};
SQLServerException.makeFromDriverError(con, null, form.format(msgArgs), null, true);
}
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncryptionAzureKeyVaultProvider.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncryptionAzureKeyVaultProvider.java
index 9a1d89677a..c6e168a855 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncryptionAzureKeyVaultProvider.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerColumnEncryptionAzureKeyVaultProvider.java
@@ -17,15 +17,13 @@
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.MessageFormat;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-
-import org.apache.http.impl.client.HttpClientBuilder;
+import java.util.Locale;
import com.microsoft.azure.keyvault.KeyVaultClient;
-import com.microsoft.azure.keyvault.KeyVaultClientImpl;
import com.microsoft.azure.keyvault.models.KeyBundle;
import com.microsoft.azure.keyvault.models.KeyOperationResult;
+import com.microsoft.azure.keyvault.models.KeyVerifyResult;
+import com.microsoft.azure.keyvault.webkey.JsonWebKeyEncryptionAlgorithm;
import com.microsoft.azure.keyvault.webkey.JsonWebKeySignatureAlgorithm;
/**
@@ -66,26 +64,20 @@ 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
+ * Constructor that authenticates to AAD. This is used by KeyVaultClient at runtime to authenticate to Azure Key
* Vault.
*
- * @param authenticationCallback
- * - Callback function used for authenticating to AAD.
- * @param executorService
- * - The ExecutorService used to create the keyVaultClient
+ * @param clientId
+ * Identifier of the client requesting the token.
+ * @param clientKey
+ * Key of the client requesting the token.
* @throws SQLServerException
* when an error occurs
*/
- public SQLServerColumnEncryptionAzureKeyVaultProvider(SQLServerKeyVaultAuthenticationCallback authenticationCallback,
- ExecutorService executorService) throws SQLServerException {
- if (null == authenticationCallback) {
- MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_NullValue"));
- Object[] msgArgs1 = {"SQLServerKeyVaultAuthenticationCallback"};
- throw new SQLServerException(form.format(msgArgs1), null);
- }
- credential = new KeyVaultCredential(authenticationCallback);
- HttpClientBuilder builder = HttpClientBuilder.create();
- keyVaultClient = new KeyVaultClientImpl(builder, executorService, credential);
+ public SQLServerColumnEncryptionAzureKeyVaultProvider(String clientId,
+ String clientKey) throws SQLServerException {
+ credential = new KeyVaultCredential(clientId, clientKey);
+ keyVaultClient = new KeyVaultClient(credential);
}
/**
@@ -263,7 +255,7 @@ public byte[] encryptColumnEncryptionKey(String masterKeyPath,
byte[] version = new byte[] {firstVersion[0]};
// Get the Unicode encoded bytes of cultureinvariant lower case masterKeyPath
- byte[] masterKeyPathBytes = masterKeyPath.toLowerCase().getBytes(UTF_16LE);
+ byte[] masterKeyPathBytes = masterKeyPath.toLowerCase(Locale.ENGLISH).getBytes(UTF_16LE);
byte[] keyPathLength = new byte[2];
keyPathLength[0] = (byte) (((short) masterKeyPathBytes.length) & 0xff);
@@ -308,7 +300,7 @@ public byte[] encryptColumnEncryptionKey(String masterKeyPath,
byte dataToSign[] = md.digest();
// Sign the hash
- byte[] signedHash = AzureKeyVaultSignHashedData(dataToSign, masterKeyPath);
+ byte[] signedHash = AzureKeyVaultSignHashedData(dataToSign, masterKeyPath);
if (signedHash.length != keySizeInBytes) {
throw new SQLServerException(SQLServerException.getErrString("R_SignedHashLengthError"), null);
@@ -405,7 +397,7 @@ private void ValidateNonEmptyAKVPath(String masterKeyPath) throws SQLServerExcep
// A valid URI.
// Check if it is pointing to AKV.
- if (!parsedUri.getHost().toLowerCase().endsWith(azureKeyVaultDomainName)) {
+ if (!parsedUri.getHost().toLowerCase(Locale.ENGLISH).endsWith(azureKeyVaultDomainName)) {
// Return an error indicating that the AKV url is invalid.
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_AKVMasterKeyPathInvalid"));
Object[] msgArgs = {masterKeyPath};
@@ -433,14 +425,10 @@ private byte[] AzureKeyVaultWrap(String masterKeyPath,
throw new SQLServerException(SQLServerException.getErrString("R_CEKNull"), null);
}
- KeyOperationResult wrappedKey = null;
- try {
- wrappedKey = keyVaultClient.wrapKeyAsync(masterKeyPath, encryptionAlgorithm, columnEncryptionKey).get();
- }
- catch (InterruptedException | ExecutionException e) {
- throw new SQLServerException(SQLServerException.getErrString("R_EncryptCEKError"), e);
- }
- return wrappedKey.getResult();
+ JsonWebKeyEncryptionAlgorithm jsonEncryptionAlgorithm = new JsonWebKeyEncryptionAlgorithm(encryptionAlgorithm);
+ KeyOperationResult wrappedKey = keyVaultClient.wrapKey(masterKeyPath, jsonEncryptionAlgorithm, columnEncryptionKey);
+
+ return wrappedKey.result();
}
/**
@@ -466,14 +454,10 @@ private byte[] AzureKeyVaultUnWrap(String masterKeyPath,
throw new SQLServerException(SQLServerException.getErrString("R_EmptyEncryptedCEK"), null);
}
- KeyOperationResult unwrappedKey;
- try {
- unwrappedKey = keyVaultClient.unwrapKeyAsync(masterKeyPath, encryptionAlgorithm, encryptedColumnEncryptionKey).get();
- }
- catch (InterruptedException | ExecutionException e) {
- throw new SQLServerException(SQLServerException.getErrString("R_DecryptCEKError"), e);
- }
- return unwrappedKey.getResult();
+ JsonWebKeyEncryptionAlgorithm jsonEncryptionAlgorithm = new JsonWebKeyEncryptionAlgorithm(encryptionAlgorithm);
+ KeyOperationResult unwrappedKey = keyVaultClient.unwrapKey(masterKeyPath, jsonEncryptionAlgorithm, encryptedColumnEncryptionKey);
+
+ return unwrappedKey.result();
}
/**
@@ -490,14 +474,9 @@ private byte[] AzureKeyVaultSignHashedData(byte[] dataToSign,
String masterKeyPath) throws SQLServerException {
assert ((null != dataToSign) && (0 != dataToSign.length));
- KeyOperationResult signedData = null;
- try {
- signedData = keyVaultClient.signAsync(masterKeyPath, JsonWebKeySignatureAlgorithm.RS256, dataToSign).get();
- }
- catch (InterruptedException | ExecutionException e) {
- throw new SQLServerException(SQLServerException.getErrString("R_GenerateSignature"), e);
- }
- return signedData.getResult();
+ KeyOperationResult signedData = keyVaultClient.sign(masterKeyPath, JsonWebKeySignatureAlgorithm.RS256, dataToSign);
+
+ return signedData.result();
}
/**
@@ -516,15 +495,9 @@ private boolean AzureKeyVaultVerifySignature(byte[] dataToVerify,
assert ((null != dataToVerify) && (0 != dataToVerify.length));
assert ((null != signature) && (0 != signature.length));
- boolean valid = false;
- try {
- valid = keyVaultClient.verifyAsync(masterKeyPath, JsonWebKeySignatureAlgorithm.RS256, dataToVerify, signature).get();
- }
- catch (InterruptedException | ExecutionException e) {
- throw new SQLServerException(SQLServerException.getErrString("R_VerifySignature"), e);
- }
+ KeyVerifyResult valid = keyVaultClient.verify(masterKeyPath, JsonWebKeySignatureAlgorithm.RS256, dataToVerify, signature);
- return valid;
+ return valid.value();
}
/**
@@ -537,21 +510,22 @@ private boolean AzureKeyVaultVerifySignature(byte[] dataToVerify,
* when an error occurs
*/
private int getAKVKeySize(String masterKeyPath) throws SQLServerException {
+ KeyBundle retrievedKey = keyVaultClient.getKey(masterKeyPath);
- KeyBundle retrievedKey = null;
- try {
- retrievedKey = keyVaultClient.getKeyAsync(masterKeyPath).get();
- }
- catch (InterruptedException | ExecutionException e) {
- throw new SQLServerException(SQLServerException.getErrString("R_GetAKVKeySize"), e);
+ if (null == retrievedKey) {
+ String[] keyTokens = masterKeyPath.split("/");
+
+ MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_AKVKeyNotFound"));
+ Object[] msgArgs = {keyTokens[keyTokens.length - 1]};
+ throw new SQLServerException(null, form.format(msgArgs), null, 0, false);
}
- if (!"RSA".equalsIgnoreCase(retrievedKey.getKey().getKty()) && !"RSA-HSM".equalsIgnoreCase(retrievedKey.getKey().getKty())) {
+ 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.getKey().getKty()};
+ Object[] msgArgs = {retrievedKey.key().kty().toString()};
throw new SQLServerException(null, form.format(msgArgs), null, 0, false);
}
- return retrievedKey.getKey().getN().length;
+ return retrievedKey.key().n().length;
}
}
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java
index a243203754..487c99c389 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java
@@ -1357,7 +1357,7 @@ Connection connectInternal(Properties propsIn,
if (sPropValue == null)
sPropValue = SQLServerDriverStringProperty.SELECT_METHOD.getDefaultValue();
if ("cursor".equalsIgnoreCase(sPropValue) || "direct".equalsIgnoreCase(sPropValue)) {
- activeConnectionProperties.setProperty(sPropKey, sPropValue.toLowerCase());
+ activeConnectionProperties.setProperty(sPropKey, sPropValue.toLowerCase(Locale.ENGLISH));
}
else {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidselectMethod"));
@@ -1370,7 +1370,7 @@ Connection connectInternal(Properties propsIn,
if (sPropValue == null)
sPropValue = SQLServerDriverStringProperty.RESPONSE_BUFFERING.getDefaultValue();
if ("full".equalsIgnoreCase(sPropValue) || "adaptive".equalsIgnoreCase(sPropValue)) {
- activeConnectionProperties.setProperty(sPropKey, sPropValue.toLowerCase());
+ activeConnectionProperties.setProperty(sPropKey, sPropValue.toLowerCase(Locale.ENGLISH));
}
else {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidresponseBuffering"));
@@ -1398,7 +1398,7 @@ Connection connectInternal(Properties propsIn,
sPropKey = SQLServerDriverIntProperty.STATEMENT_POOLING_CACHE_SIZE.toString();
if (activeConnectionProperties.getProperty(sPropKey) != null && activeConnectionProperties.getProperty(sPropKey).length() > 0) {
try {
- int n = (new Integer(activeConnectionProperties.getProperty(sPropKey))).intValue();
+ int n = new Integer(activeConnectionProperties.getProperty(sPropKey));
this.setStatementPoolingCacheSize(n);
}
catch (NumberFormatException e) {
@@ -1514,7 +1514,7 @@ Connection connectInternal(Properties propsIn,
throw new SQLServerException(SQLServerException.getErrString("R_AccessTokenWithUserPassword"), null);
}
- if ((!System.getProperty("os.name").toLowerCase().startsWith("windows"))
+ if ((!System.getProperty("os.name").toLowerCase(Locale.ENGLISH).startsWith("windows"))
&& (authenticationString.equalsIgnoreCase(SqlAuthentication.ActiveDirectoryIntegrated.toString()))) {
throw new SQLServerException(SQLServerException.getErrString("R_AADIntegratedOnNonWindows"), null);
}
@@ -1535,7 +1535,7 @@ Connection connectInternal(Properties propsIn,
try {
String strPort = activeConnectionProperties.getProperty(sPropKey);
if (null != strPort) {
- nPort = (new Integer(strPort)).intValue();
+ nPort = new Integer(strPort);
if ((nPort < 0) || (nPort > 65535)) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidPortNumber"));
@@ -1615,7 +1615,7 @@ else if (0 == requestedPacketSize)
nLockTimeout = defaultLockTimeOut; // Wait forever
if (activeConnectionProperties.getProperty(sPropKey) != null && activeConnectionProperties.getProperty(sPropKey).length() > 0) {
try {
- int n = (new Integer(activeConnectionProperties.getProperty(sPropKey))).intValue();
+ int n = new Integer(activeConnectionProperties.getProperty(sPropKey));
if (n >= defaultLockTimeOut)
nLockTimeout = n;
else {
@@ -1636,7 +1636,7 @@ else if (0 == requestedPacketSize)
queryTimeoutSeconds = defaultQueryTimeout; // Wait forever
if (activeConnectionProperties.getProperty(sPropKey) != null && activeConnectionProperties.getProperty(sPropKey).length() > 0) {
try {
- int n = (new Integer(activeConnectionProperties.getProperty(sPropKey))).intValue();
+ int n = new Integer(activeConnectionProperties.getProperty(sPropKey));
if (n >= defaultQueryTimeout) {
queryTimeoutSeconds = n;
}
@@ -1658,7 +1658,7 @@ else if (0 == requestedPacketSize)
socketTimeoutMilliseconds = defaultSocketTimeout; // Wait forever
if (activeConnectionProperties.getProperty(sPropKey) != null && activeConnectionProperties.getProperty(sPropKey).length() > 0) {
try {
- int n = (new Integer(activeConnectionProperties.getProperty(sPropKey))).intValue();
+ int n = new Integer(activeConnectionProperties.getProperty(sPropKey));
if (n >= defaultSocketTimeout) {
socketTimeoutMilliseconds = n;
}
@@ -1678,7 +1678,7 @@ else if (0 == requestedPacketSize)
sPropKey = SQLServerDriverIntProperty.SERVER_PREPARED_STATEMENT_DISCARD_THRESHOLD.toString();
if (activeConnectionProperties.getProperty(sPropKey) != null && activeConnectionProperties.getProperty(sPropKey).length() > 0) {
try {
- int n = (new Integer(activeConnectionProperties.getProperty(sPropKey))).intValue();
+ int n = new Integer(activeConnectionProperties.getProperty(sPropKey));
setServerPreparedStatementDiscardThreshold(n);
}
catch (NumberFormatException e) {
@@ -2128,7 +2128,7 @@ ServerPortPlaceHolder primaryPermissionCheck(String primary,
connectionlogger.fine(toString() + " SQL Server port returned by SQL Browser: " + instancePort);
try {
if (null != instancePort) {
- primaryPortNumber = (new Integer(instancePort)).intValue();
+ primaryPortNumber = new Integer(instancePort);
if ((primaryPortNumber < 0) || (primaryPortNumber > 65535)) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidPortNumber"));
@@ -2838,7 +2838,7 @@ static String sqlStatementToSetCommit(boolean autoCommit) {
public void setAutoCommit(boolean newAutoCommitMode) throws SQLServerException {
if (loggerExternal.isLoggable(Level.FINER)) {
- loggerExternal.entering(getClassNameLogging(), "setAutoCommit", Boolean.valueOf(newAutoCommitMode));
+ loggerExternal.entering(getClassNameLogging(), "setAutoCommit", newAutoCommitMode);
if (Util.IsActivityTraceOn())
loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
}
@@ -2868,7 +2868,7 @@ public void setAutoCommit(boolean newAutoCommitMode) throws SQLServerException {
checkClosed();
boolean res = !inXATransaction && databaseAutoCommitMode;
if (loggerExternal.isLoggable(Level.FINER))
- loggerExternal.exiting(getClassNameLogging(), "getAutoCommit", Boolean.valueOf(res));
+ loggerExternal.exiting(getClassNameLogging(), "getAutoCommit", res);
return res;
}
@@ -2971,10 +2971,10 @@ public void close() throws SQLServerException {
}
// Invalidate statement caches.
- if(null != preparedStatementHandleCache)
+ if (null != preparedStatementHandleCache)
preparedStatementHandleCache.clear();
- if(null != parameterMetadataCache)
+ if (null != parameterMetadataCache)
parameterMetadataCache.clear();
// Clean-up queue etc. related to batching of prepared statement discard actions (sp_unprepare).
@@ -3008,7 +3008,7 @@ final void poolCloseEventNotify() throws SQLServerException {
/* L0 */ public boolean isClosed() throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "isClosed");
- loggerExternal.exiting(getClassNameLogging(), "isClosed", Boolean.valueOf(isSessionUnAvailable()));
+ loggerExternal.exiting(getClassNameLogging(), "isClosed", isSessionUnAvailable());
return isSessionUnAvailable();
}
@@ -3024,7 +3024,7 @@ final void poolCloseEventNotify() throws SQLServerException {
/* L0 */ public void setReadOnly(boolean readOnly) throws SQLServerException {
if (loggerExternal.isLoggable(Level.FINER))
- loggerExternal.entering(getClassNameLogging(), "setReadOnly", Boolean.valueOf(readOnly));
+ loggerExternal.entering(getClassNameLogging(), "setReadOnly", readOnly);
checkClosed();
// do nothing per spec
loggerExternal.exiting(getClassNameLogging(), "setReadOnly");
@@ -3034,7 +3034,7 @@ final void poolCloseEventNotify() throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "isReadOnly");
checkClosed();
if (loggerExternal.isLoggable(Level.FINER))
- loggerExternal.exiting(getClassNameLogging(), "isReadOnly", Boolean.valueOf(false));
+ loggerExternal.exiting(getClassNameLogging(), "isReadOnly", Boolean.FALSE);
return false;
}
@@ -3060,7 +3060,7 @@ final void poolCloseEventNotify() throws SQLServerException {
/* L0 */ public void setTransactionIsolation(int level) throws SQLServerException {
if (loggerExternal.isLoggable(Level.FINER)) {
- loggerExternal.entering(getClassNameLogging(), "setTransactionIsolation", new Integer(level));
+ loggerExternal.entering(getClassNameLogging(), "setTransactionIsolation", level);
if (Util.IsActivityTraceOn()) {
loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
}
@@ -3080,7 +3080,7 @@ final void poolCloseEventNotify() throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "getTransactionIsolation");
checkClosed();
if (loggerExternal.isLoggable(Level.FINER))
- loggerExternal.exiting(getClassNameLogging(), "getTransactionIsolation", new Integer(transactionIsolationLevel));
+ loggerExternal.exiting(getClassNameLogging(), "getTransactionIsolation", transactionIsolationLevel);
return transactionIsolationLevel;
}
@@ -3124,7 +3124,7 @@ public Statement createStatement(int resultSetType,
int resultSetConcurrency) throws SQLServerException {
if (loggerExternal.isLoggable(Level.FINER))
loggerExternal.entering(getClassNameLogging(), "createStatement",
- new Object[] {new Integer(resultSetType), new Integer(resultSetConcurrency)});
+ new Object[] {resultSetType, resultSetConcurrency});
checkClosed();
Statement st = new SQLServerStatement(this, resultSetType, resultSetConcurrency,
SQLServerStatementColumnEncryptionSetting.UseConnectionSetting);
@@ -3137,7 +3137,7 @@ public PreparedStatement prepareStatement(String sql,
int resultSetConcurrency) throws SQLServerException {
if (loggerExternal.isLoggable(Level.FINER))
loggerExternal.entering(getClassNameLogging(), "prepareStatement",
- new Object[] {sql, new Integer(resultSetType), new Integer(resultSetConcurrency)});
+ new Object[] {sql, resultSetType, resultSetConcurrency});
checkClosed();
PreparedStatement st;
@@ -3161,7 +3161,7 @@ private PreparedStatement prepareStatement(String sql,
SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException {
if (loggerExternal.isLoggable(Level.FINER))
loggerExternal.entering(getClassNameLogging(), "prepareStatement",
- new Object[] {sql, new Integer(resultSetType), new Integer(resultSetConcurrency), stmtColEncSetting});
+ new Object[] {sql, resultSetType, resultSetConcurrency, stmtColEncSetting});
checkClosed();
PreparedStatement st;
@@ -3182,7 +3182,7 @@ public CallableStatement prepareCall(String sql,
int resultSetConcurrency) throws SQLServerException {
if (loggerExternal.isLoggable(Level.FINER))
loggerExternal.entering(getClassNameLogging(), "prepareCall",
- new Object[] {sql, new Integer(resultSetType), new Integer(resultSetConcurrency)});
+ new Object[] {sql, resultSetType, resultSetConcurrency});
checkClosed();
CallableStatement st;
@@ -4539,7 +4539,7 @@ public Statement createStatement(int nType,
int nConcur,
int resultSetHoldability) throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "createStatement",
- new Object[] {new Integer(nType), new Integer(nConcur), resultSetHoldability});
+ new Object[] {nType, nConcur, resultSetHoldability});
Statement st = createStatement(nType, nConcur, resultSetHoldability, SQLServerStatementColumnEncryptionSetting.UseConnectionSetting);
loggerExternal.exiting(getClassNameLogging(), "createStatement", st);
return st;
@@ -4550,7 +4550,7 @@ public Statement createStatement(int nType,
int resultSetHoldability,
SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "createStatement",
- new Object[] {new Integer(nType), new Integer(nConcur), resultSetHoldability, stmtColEncSetting});
+ new Object[] {nType, nConcur, resultSetHoldability, stmtColEncSetting});
checkClosed();
checkValidHoldability(resultSetHoldability);
checkMatchesCurrentHoldability(resultSetHoldability);
@@ -4564,7 +4564,7 @@ public Statement createStatement(int nType,
int nConcur,
int resultSetHoldability) throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "prepareStatement",
- new Object[] {new Integer(nType), new Integer(nConcur), resultSetHoldability});
+ new Object[] {nType, nConcur, resultSetHoldability});
PreparedStatement st = prepareStatement(sql, nType, nConcur, resultSetHoldability,
SQLServerStatementColumnEncryptionSetting.UseConnectionSetting);
loggerExternal.exiting(getClassNameLogging(), "prepareStatement", st);
@@ -4603,7 +4603,7 @@ public PreparedStatement prepareStatement(java.lang.String sql,
int resultSetHoldability,
SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "prepareStatement",
- new Object[] {new Integer(nType), new Integer(nConcur), resultSetHoldability, stmtColEncSetting});
+ new Object[] {nType, nConcur, resultSetHoldability, stmtColEncSetting});
checkClosed();
checkValidHoldability(resultSetHoldability);
checkMatchesCurrentHoldability(resultSetHoldability);
@@ -4626,7 +4626,7 @@ public PreparedStatement prepareStatement(java.lang.String sql,
int nConcur,
int resultSetHoldability) throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "prepareStatement",
- new Object[] {new Integer(nType), new Integer(nConcur), resultSetHoldability});
+ new Object[] {nType, nConcur, resultSetHoldability});
CallableStatement st = prepareCall(sql, nType, nConcur, resultSetHoldability, SQLServerStatementColumnEncryptionSetting.UseConnectionSetting);
loggerExternal.exiting(getClassNameLogging(), "prepareCall", st);
return st;
@@ -4638,7 +4638,7 @@ public CallableStatement prepareCall(String sql,
int resultSetHoldability,
SQLServerStatementColumnEncryptionSetting stmtColEncSetiing) throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "prepareStatement",
- new Object[] {new Integer(nType), new Integer(nConcur), resultSetHoldability, stmtColEncSetiing});
+ new Object[] {nType, nConcur, resultSetHoldability, stmtColEncSetiing});
checkClosed();
checkValidHoldability(resultSetHoldability);
checkMatchesCurrentHoldability(resultSetHoldability);
@@ -4660,7 +4660,7 @@ public CallableStatement prepareCall(String sql,
/* L3 */ public PreparedStatement prepareStatement(String sql,
int flag) throws SQLServerException {
- loggerExternal.entering(getClassNameLogging(), "prepareStatement", new Object[] {sql, new Integer(flag)});
+ loggerExternal.entering(getClassNameLogging(), "prepareStatement", new Object[] {sql, flag});
SQLServerPreparedStatement ps = (SQLServerPreparedStatement) prepareStatement(sql, flag,
SQLServerStatementColumnEncryptionSetting.UseConnectionSetting);
@@ -4699,7 +4699,7 @@ public CallableStatement prepareCall(String sql,
public PreparedStatement prepareStatement(String sql,
int flag,
SQLServerStatementColumnEncryptionSetting stmtColEncSetting) throws SQLServerException {
- loggerExternal.entering(getClassNameLogging(), "prepareStatement", new Object[] {sql, new Integer(flag), stmtColEncSetting});
+ loggerExternal.entering(getClassNameLogging(), "prepareStatement", new Object[] {sql, flag, stmtColEncSetting});
checkClosed();
SQLServerPreparedStatement ps = (SQLServerPreparedStatement) prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY,
stmtColEncSetting);
@@ -5184,7 +5184,7 @@ public boolean isValid(int timeout) throws SQLException {
public boolean isWrapperFor(Class> iface) throws SQLException {
loggerExternal.entering(getClassNameLogging(), "isWrapperFor", iface);
boolean f = iface.isInstance(this);
- loggerExternal.exiting(getClassNameLogging(), "isWrapperFor", Boolean.valueOf(f));
+ loggerExternal.exiting(getClassNameLogging(), "isWrapperFor", f);
return f;
}
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java
index b94bb4d6f8..25c269f83c 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java
@@ -686,16 +686,16 @@ public void setEnablePrepareOnFirstPreparedStatementCall(boolean enablePrepareOn
}
/**
- * 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.
+ * 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() {
boolean defaultValue = SQLServerDriverBooleanProperty.ENABLE_PREPARE_ON_FIRST_PREPARED_STATEMENT.getDefaultValue();
- return getBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.ENABLE_PREPARE_ON_FIRST_PREPARED_STATEMENT.toString(), defaultValue);
+ return getBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.ENABLE_PREPARE_ON_FIRST_PREPARED_STATEMENT.toString(),
+ defaultValue);
}
/**
@@ -728,7 +728,7 @@ public int getServerPreparedStatementDiscardThreshold() {
* Specifies the size of the prepared statement cache for this conection. 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) {
setIntProperty(connectionProps, SQLServerDriverIntProperty.STATEMENT_POOLING_CACHE_SIZE.toString(), statementPoolingCacheSize);
@@ -844,7 +844,7 @@ private void setIntProperty(Properties props,
String propKey,
int propValue) {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
- loggerExternal.entering(getClassNameLogging(), "set" + propKey, new Integer(propValue));
+ loggerExternal.entering(getClassNameLogging(), "set" + propKey, propValue);
props.setProperty(propKey, new Integer(propValue).toString());
loggerExternal.exiting(getClassNameLogging(), "set" + propKey);
}
@@ -870,7 +870,7 @@ private int getIntProperty(Properties props,
}
}
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
- loggerExternal.exiting(getClassNameLogging(), "get" + propKey, new Integer(value));
+ loggerExternal.exiting(getClassNameLogging(), "get" + propKey, value);
return value;
}
@@ -880,7 +880,7 @@ private void setBooleanProperty(Properties props,
String propKey,
boolean propValue) {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
- loggerExternal.entering(getClassNameLogging(), "set" + propKey, Boolean.valueOf(propValue));
+ loggerExternal.entering(getClassNameLogging(), "set" + propKey, propValue);
props.setProperty(propKey, (propValue) ? "true" : "false");
loggerExternal.exiting(getClassNameLogging(), "set" + propKey);
}
@@ -904,7 +904,7 @@ private boolean getBooleanProperty(Properties props,
value = Boolean.valueOf(propValue);
}
loggerExternal.exiting(getClassNameLogging(), "get" + propKey, value);
- return value.booleanValue();
+ return value;
}
private void setObjectProperty(Properties props,
@@ -1069,7 +1069,7 @@ else if (!"class".equals(propertyName)) {
public boolean isWrapperFor(Class> iface) throws SQLException {
loggerExternal.entering(getClassNameLogging(), "isWrapperFor", iface);
boolean f = iface.isInstance(this);
- loggerExternal.exiting(getClassNameLogging(), "isWrapperFor", Boolean.valueOf(f));
+ loggerExternal.exiting(getClassNameLogging(), "isWrapperFor", f);
return f;
}
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataTable.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataTable.java
index 30085ed25b..f1436ceb56 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataTable.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataTable.java
@@ -116,139 +116,13 @@ public synchronized void addRow(Object... values) throws SQLServerException {
int currentColumn = 0;
while (columnsIterator.hasNext()) {
Object val = null;
- boolean bValueNull;
- int nValueLen;
if ((null != values) && (currentColumn < values.length) && (null != values[currentColumn]))
val = (null == values[currentColumn]) ? null : values[currentColumn];
currentColumn++;
Map.Entry pair = columnsIterator.next();
- SQLServerDataColumn currentColumnMetadata = pair.getValue();
JDBCType jdbcType = JDBCType.of(pair.getValue().javaSqlType);
-
- boolean isColumnMetadataUpdated = false;
- switch (jdbcType) {
- case BIGINT:
- rowValues[pair.getKey()] = (null == val) ? null : Long.parseLong(val.toString());
- break;
-
- case BIT:
- rowValues[pair.getKey()] = (null == val) ? null : Boolean.parseBoolean(val.toString());
- break;
-
- case INTEGER:
- rowValues[pair.getKey()] = (null == val) ? null : Integer.parseInt(val.toString());
- break;
-
- case SMALLINT:
- case TINYINT:
- rowValues[pair.getKey()] = (null == val) ? null : Short.parseShort(val.toString());
- break;
-
- case DECIMAL:
- case NUMERIC:
- BigDecimal bd = null;
- if (null != val) {
- bd = new BigDecimal(val.toString());
- // BigDecimal#precision returns number of digits in the unscaled value.
- // Say, for value 0.01, it returns 1 but the precision should be 3 for SQLServer
- int precision = Util.getValueLengthBaseOnJavaType(bd, JavaType.of(bd), null, null, jdbcType);
- if (bd.scale() > currentColumnMetadata.scale) {
- currentColumnMetadata.scale = bd.scale();
- isColumnMetadataUpdated = true;
- }
- if (precision > currentColumnMetadata.precision) {
- currentColumnMetadata.precision = precision;
- isColumnMetadataUpdated = true;
- }
-
- // precision equal: the maximum number of digits in integer part + the maximum scale
- int numberOfDigitsIntegerPart = precision - bd.scale();
- if (numberOfDigitsIntegerPart > currentColumnMetadata.numberOfDigitsIntegerPart) {
- currentColumnMetadata.numberOfDigitsIntegerPart = numberOfDigitsIntegerPart;
- isColumnMetadataUpdated = true;
- }
-
- if (isColumnMetadataUpdated) {
- currentColumnMetadata.precision = currentColumnMetadata.scale + currentColumnMetadata.numberOfDigitsIntegerPart;
- columnMetadata.put(pair.getKey(), currentColumnMetadata);
- }
- }
- rowValues[pair.getKey()] = bd;
- break;
-
- case DOUBLE:
- rowValues[pair.getKey()] = (null == val) ? null : Double.parseDouble(val.toString());
- break;
-
- case FLOAT:
- case REAL:
- rowValues[pair.getKey()] = (null == val) ? null : Float.parseFloat(val.toString());
- break;
-
- case TIMESTAMP_WITH_TIMEZONE:
- case TIME_WITH_TIMEZONE:
- DriverJDBCVersion.checkSupportsJDBC42();
- case DATE:
- case TIME:
- case TIMESTAMP:
- case DATETIMEOFFSET:
- // 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
-
- if (null == val)
- rowValues[pair.getKey()] = null;
- // java.sql.Date, java.sql.Time and java.sql.Timestamp are subclass of java.util.Date
- else if (val instanceof java.util.Date)
- rowValues[pair.getKey()] = val.toString();
- else if (val instanceof microsoft.sql.DateTimeOffset)
- rowValues[pair.getKey()] = val.toString();
- else if (val instanceof OffsetDateTime)
- rowValues[pair.getKey()] = val.toString();
- else if (val instanceof OffsetTime)
- rowValues[pair.getKey()] = val.toString();
- else
- rowValues[pair.getKey()] = (null == val) ? null : (String) val;
- break;
-
- case BINARY:
- case VARBINARY:
- case LONGVARBINARY:
- bValueNull = (null == val);
- nValueLen = bValueNull ? 0 : ((byte[]) val).length;
-
- if (nValueLen > currentColumnMetadata.precision) {
- currentColumnMetadata.precision = nValueLen;
- columnMetadata.put(pair.getKey(), currentColumnMetadata);
- }
- rowValues[pair.getKey()] = (bValueNull) ? null : (byte[]) val;
-
- break;
-
- case CHAR:
- if (val instanceof UUID && (val != null))
- val = val.toString();
- case VARCHAR:
- case NCHAR:
- case NVARCHAR:
- case LONGVARCHAR:
- case LONGNVARCHAR:
- case SQLXML:
- bValueNull = (null == val);
- nValueLen = bValueNull ? 0 : (2 * ((String) val).length());
-
- if (nValueLen > currentColumnMetadata.precision) {
- currentColumnMetadata.precision = nValueLen;
- columnMetadata.put(pair.getKey(), currentColumnMetadata);
- }
- rowValues[pair.getKey()] = (bValueNull) ? null : (String) val;
- break;
-
- default:
- MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_unsupportedDataTypeTVP"));
- Object[] msgArgs = {jdbcType};
- throw new SQLServerException(null, form.format(msgArgs), null, 0, false);
- }
+ internalAddrow(jdbcType, val, rowValues, pair);
}
rows.put(rowCount++, rowValues);
}
@@ -260,11 +134,160 @@ else if (val instanceof OffsetTime)
}
}
-
+
+ /**
+ * Adding rows one row of data to data table.
+ * @param jdbcType The jdbcType
+ * @param val The data value
+ * @param rowValues Row of data
+ * @param pair pair to be added to data table
+ * @throws SQLServerException
+ */
+ private void internalAddrow(JDBCType jdbcType,
+ Object val,
+ Object[] rowValues,
+ Map.Entry pair) throws SQLServerException {
+
+ SQLServerDataColumn currentColumnMetadata = pair.getValue();
+ boolean isColumnMetadataUpdated = false;
+ boolean bValueNull;
+ int nValueLen;
+ switch (jdbcType) {
+ case BIGINT:
+ rowValues[pair.getKey()] = (null == val) ? null : Long.parseLong(val.toString());
+ break;
+
+ case BIT:
+ rowValues[pair.getKey()] = (null == val) ? null : Boolean.parseBoolean(val.toString());
+ break;
+
+ case INTEGER:
+ rowValues[pair.getKey()] = (null == val) ? null : Integer.parseInt(val.toString());
+ break;
+
+ case SMALLINT:
+ case TINYINT:
+ rowValues[pair.getKey()] = (null == val) ? null : Short.parseShort(val.toString());
+ break;
+
+ case DECIMAL:
+ case NUMERIC:
+ BigDecimal bd = null;
+ if (null != val) {
+ bd = new BigDecimal(val.toString());
+ // BigDecimal#precision returns number of digits in the unscaled value.
+ // Say, for value 0.01, it returns 1 but the precision should be 3 for SQLServer
+ int precision = Util.getValueLengthBaseOnJavaType(bd, JavaType.of(bd), null, null, jdbcType);
+ if (bd.scale() > currentColumnMetadata.scale) {
+ currentColumnMetadata.scale = bd.scale();
+ isColumnMetadataUpdated = true;
+ }
+ if (precision > currentColumnMetadata.precision) {
+ currentColumnMetadata.precision = precision;
+ isColumnMetadataUpdated = true;
+ }
+
+ // precision equal: the maximum number of digits in integer part + the maximum scale
+ int numberOfDigitsIntegerPart = precision - bd.scale();
+ if (numberOfDigitsIntegerPart > currentColumnMetadata.numberOfDigitsIntegerPart) {
+ currentColumnMetadata.numberOfDigitsIntegerPart = numberOfDigitsIntegerPart;
+ isColumnMetadataUpdated = true;
+ }
+
+ if (isColumnMetadataUpdated) {
+ currentColumnMetadata.precision = currentColumnMetadata.scale + currentColumnMetadata.numberOfDigitsIntegerPart;
+ columnMetadata.put(pair.getKey(), currentColumnMetadata);
+ }
+ }
+ rowValues[pair.getKey()] = bd;
+ break;
+
+ case DOUBLE:
+ rowValues[pair.getKey()] = (null == val) ? null : Double.parseDouble(val.toString());
+ break;
+
+ case FLOAT:
+ case REAL:
+ rowValues[pair.getKey()] = (null == val) ? null : Float.parseFloat(val.toString());
+ break;
+
+ case TIMESTAMP_WITH_TIMEZONE:
+ case TIME_WITH_TIMEZONE:
+ DriverJDBCVersion.checkSupportsJDBC42();
+ case DATE:
+ case TIME:
+ case TIMESTAMP:
+ case DATETIMEOFFSET:
+ // 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
+
+ if (null == val)
+ rowValues[pair.getKey()] = null;
+ // java.sql.Date, java.sql.Time and java.sql.Timestamp are subclass of java.util.Date
+ else if (val instanceof java.util.Date)
+ rowValues[pair.getKey()] = val.toString();
+ else if (val instanceof microsoft.sql.DateTimeOffset)
+ rowValues[pair.getKey()] = val.toString();
+ else if (val instanceof OffsetDateTime)
+ rowValues[pair.getKey()] = val.toString();
+ else if (val instanceof OffsetTime)
+ rowValues[pair.getKey()] = val.toString();
+ else
+ rowValues[pair.getKey()] = (null == val) ? null : (String) val;
+ break;
+
+ case BINARY:
+ case VARBINARY:
+ case LONGVARBINARY:
+ bValueNull = (null == val);
+ nValueLen = bValueNull ? 0 : ((byte[]) val).length;
+
+ if (nValueLen > currentColumnMetadata.precision) {
+ currentColumnMetadata.precision = nValueLen;
+ columnMetadata.put(pair.getKey(), currentColumnMetadata);
+ }
+ rowValues[pair.getKey()] = (bValueNull) ? null : (byte[]) val;
+
+ break;
+
+ case CHAR:
+ if (val instanceof UUID && (val != null))
+ val = val.toString();
+ case VARCHAR:
+ case NCHAR:
+ case NVARCHAR:
+ case LONGVARCHAR:
+ case LONGNVARCHAR:
+ case SQLXML:
+ bValueNull = (null == val);
+ nValueLen = bValueNull ? 0 : (2 * ((String) val).length());
+
+ if (nValueLen > currentColumnMetadata.precision) {
+ currentColumnMetadata.precision = nValueLen;
+ columnMetadata.put(pair.getKey(), currentColumnMetadata);
+ }
+ rowValues[pair.getKey()] = (bValueNull) ? null : (String) val;
+ break;
+ case SQL_VARIANT:
+ JDBCType internalJDBCType;
+ if (null == val) { // TODO:Check this later
+ throw new SQLServerException(SQLServerException.getErrString("R_invalidValueForTVPWithSQLVariant"), null);
+ }
+ JavaType javaType = JavaType.of(val);
+ internalJDBCType = javaType.getJDBCType(SSType.UNKNOWN, jdbcType);
+ internalAddrow(internalJDBCType, val, rowValues, pair);
+ break;
+ default:
+ MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_unsupportedDataTypeTVP"));
+ Object[] msgArgs = {jdbcType};
+ throw new SQLServerException(null, form.format(msgArgs), null, 0, false);
+ }
+ }
+
public synchronized Map getColumnMetadata() {
return columnMetadata;
}
-
+
public String getTvpName() {
return tvpName;
}
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDatabaseMetaData.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDatabaseMetaData.java
index fd732343c3..25e7a7c146 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDatabaseMetaData.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDatabaseMetaData.java
@@ -1917,7 +1917,7 @@ else if (name.equals(SQLServerDriverIntProperty.PORT_NUMBER.toString())) {
}
// if the value is outside of the valid values throw error.
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidArgument"));
- Object[] msgArgs = {new Integer(type)};
+ Object[] msgArgs = {type};
throw new SQLServerException(null, form.format(msgArgs), null, 0, true);
}
@@ -1933,7 +1933,7 @@ else if (name.equals(SQLServerDriverIntProperty.PORT_NUMBER.toString())) {
}
// if the value is outside of the valid values throw error.
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidArgument"));
- Object[] msgArgs = {new Integer(type)};
+ Object[] msgArgs = {type};
throw new SQLServerException(null, form.format(msgArgs), null, 0, true);
}
@@ -1988,7 +1988,7 @@ else if (name.equals(SQLServerDriverIntProperty.PORT_NUMBER.toString())) {
if (p > 0)
s = s.substring(0, p);
try {
- return new Integer(s).intValue();
+ return new Integer(s);
}
catch (NumberFormatException e) {
return 0;
@@ -2003,7 +2003,7 @@ else if (name.equals(SQLServerDriverIntProperty.PORT_NUMBER.toString())) {
if (p > 0 && q > 0)
s = s.substring(p + 1, q);
try {
- return new Integer(s).intValue();
+ return new Integer(s);
}
catch (NumberFormatException e) {
return 0;
@@ -2038,7 +2038,7 @@ public RowIdLifetime getRowIdLifetime() throws SQLException {
// if the value is outside of the valid values throw error.
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidArgument"));
- Object[] msgArgs = {new Integer(holdability)};
+ Object[] msgArgs = {holdability};
throw new SQLServerException(null, form.format(msgArgs), null, 0, true);
}
@@ -2202,12 +2202,12 @@ final Object apply(Object value,
switch (asJDBCType) {
case INTEGER:
- return new Integer(oneValueToAnother(((Integer) value).intValue()));
+ return oneValueToAnother((Integer) value);
case SMALLINT: // small and tinyint returned as short
case TINYINT:
- return new Short((short) oneValueToAnother(((Short) value).intValue()));
+ return (short) oneValueToAnother(((Short) value).intValue());
case BIGINT:
- return new Long(oneValueToAnother(((Long) value).intValue()));
+ return (long) oneValueToAnother(((Long) value).intValue());
case CHAR:
case VARCHAR:
case LONGVARCHAR:
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java
index d3fe42c615..bfe9612202 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java
@@ -268,12 +268,12 @@ 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),
;
@@ -298,19 +298,19 @@ public String toString() {
enum SQLServerDriverBooleanProperty
{
- DISABLE_STATEMENT_POOLING ("disableStatementPooling", false),
- 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);
+ DISABLE_STATEMENT_POOLING ("disableStatementPooling", false),
+ 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);
private final String name;
private final boolean defaultValue;
@@ -356,7 +356,7 @@ public final class SQLServerDriver implements java.sql.Driver {
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(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),
@@ -382,7 +382,7 @@ public final class SQLServerDriver implements java.sql.Driver {
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(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),
};
@@ -639,13 +639,13 @@ static final DriverPropertyInfo[] getPropertyInfoFromProperties(Properties props
public int getMajorVersion() {
loggerExternal.entering(getClassNameLogging(), "getMajorVersion");
- loggerExternal.exiting(getClassNameLogging(), "getMajorVersion", new Integer(SQLJdbcVersion.major));
+ loggerExternal.exiting(getClassNameLogging(), "getMajorVersion", SQLJdbcVersion.major);
return SQLJdbcVersion.major;
}
public int getMinorVersion() {
loggerExternal.entering(getClassNameLogging(), "getMinorVersion");
- loggerExternal.exiting(getClassNameLogging(), "getMinorVersion", new Integer(SQLJdbcVersion.minor));
+ loggerExternal.exiting(getClassNameLogging(), "getMinorVersion", SQLJdbcVersion.minor);
return SQLJdbcVersion.minor;
}
@@ -655,7 +655,7 @@ public Logger getParentLogger() throws SQLFeatureNotSupportedException {
/* L0 */ public boolean jdbcCompliant() {
loggerExternal.entering(getClassNameLogging(), "jdbcCompliant");
- loggerExternal.exiting(getClassNameLogging(), "jdbcCompliant", Boolean.valueOf(true));
+ loggerExternal.exiting(getClassNameLogging(), "jdbcCompliant", Boolean.TRUE);
return true;
}
}
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerException.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerException.java
index 7d758420d2..2f4dfd06ca 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerException.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerException.java
@@ -125,10 +125,11 @@ static String getErrString(String errCode) {
* Make a new SQLException
*
* @param errText
- * the excception message
- * @param errState
- * the excpeption state
+ * the exception message
+ * @param sqlState
+ * the statement
* @param driverError
+ * the driver error object
* @param cause
* The exception that caused this exception
*/
@@ -171,6 +172,7 @@ public SQLServerException(String errText,
* Make a new SQLException
*
* @param obj
+ * the object
* @param errText
* the exception message
* @param errState
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerKeyVaultAuthenticationCallback.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerKeyVaultAuthenticationCallback.java
deleted file mode 100644
index c940dd8ebc..0000000000
--- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerKeyVaultAuthenticationCallback.java
+++ /dev/null
@@ -1,27 +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 com.microsoft.sqlserver.jdbc;
-
-public interface SQLServerKeyVaultAuthenticationCallback {
-
- /**
- * The authentication callback delegate which is to be implemented by the client code
- *
- * @param authority
- * - Identifier of the authority, a URL.
- * @param resource
- * - Identifier of the target resource that is the recipient of the requested token, a URL.
- * @param scope
- * - The scope of the authentication request.
- * @return access token
- */
- public String getAccessToken(String authority,
- String resource,
- String scope);
-}
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerMetaData.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerMetaData.java
index c2ee1460d6..00614ff8bb 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerMetaData.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerMetaData.java
@@ -26,7 +26,8 @@ public class SQLServerMetaData {
boolean isUniqueKey = false;
SQLServerSortOrder sortOrder = SQLServerSortOrder.Unspecified;
int sortOrdinal;
-
+ private SQLCollation collation;
+
static final int defaultSortOrdinal = -1;
/**
@@ -186,6 +187,10 @@ public SQLServerSortOrder getSortOrder() {
public int getSortOrdinal() {
return sortOrdinal;
}
+
+ SQLCollation getCollation() {
+ return this.collation;
+ }
void validateSortOrder() throws SQLServerException {
// should specify both sort order and ordinal, or neither
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerParameterMetaData.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerParameterMetaData.java
index 5d8fc51104..04df112ea8 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerParameterMetaData.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerParameterMetaData.java
@@ -15,6 +15,7 @@
import java.sql.SQLException;
import java.sql.Statement;
import java.text.MessageFormat;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.StringTokenizer;
@@ -51,6 +52,9 @@ public final class SQLServerParameterMetaData implements ParameterMetaData {
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;
// Returns unique id for each instance.
private static int nextInstanceID() {
@@ -73,10 +77,11 @@ final public String toString() {
* the list of columns
* @param columnStartToken
* the token that prfixes the column set
+ * @throws SQLServerException
*/
/* L2 */ private String parseColumns(String columnSet,
- String columnStartToken) {
- StringTokenizer st = new StringTokenizer(columnSet, " =?<>!", true);
+ String columnStartToken) throws SQLServerException {
+ StringTokenizer st = new StringTokenizer(columnSet, " =?<>!\r\n\t\f", true);
final int START = 0;
final int PARAMNAME = 1;
final int PARAMVALUE = 2;
@@ -85,9 +90,12 @@ final public String toString() {
String sLastField = null;
StringBuilder sb = new StringBuilder();
+ int sTokenIndex = 0;
while (st.hasMoreTokens()) {
String sToken = st.nextToken();
+ sTokenIndex = sTokenIndex + sToken.length();
+
if (sToken.equalsIgnoreCase(columnStartToken)) {
nState = PARAMNAME;
continue;
@@ -120,6 +128,7 @@ final public String toString() {
}
}
+ indexToBeginParse = sTokenIndex;
return sb.toString();
}
@@ -130,16 +139,20 @@ final public String toString() {
* the sql syntax
* @param columnMarker
* the token that denotes the start of the column set
+ * @throws SQLServerException
*/
/* L2 */ private String parseInsertColumns(String sql,
- String columnMarker) {
+ String columnMarker) throws SQLServerException {
StringTokenizer st = new StringTokenizer(sql, " (),", true);
int nState = 0;
String sLastField = null;
StringBuilder sb = new StringBuilder();
+ int sTokenIndex = 0;
while (st.hasMoreTokens()) {
String sToken = st.nextToken();
+ sTokenIndex = sTokenIndex + sToken.length();
+
if (sToken.equalsIgnoreCase(columnMarker)) {
nState = 1;
continue;
@@ -163,12 +176,18 @@ final public String toString() {
}
if (nState == 1) {
if (sToken.trim().length() > 0) {
- if (sToken.charAt(0) != ',')
+ 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
+ // contains [c2_nvarchar, sLastField actually has the whole name [c2_nvarchar(max)]
+ sTokenIndex = sTokenIndex + (sLastField.length() - sToken.length());
+ }
}
}
}
+ indexToBeginParse = sTokenIndex;
return sb.toString();
}
@@ -233,7 +252,7 @@ else if (SSType.Category.CHARACTER == ssType.category || SSType.Category.BINARY
}
catch (NumberFormatException e) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_metaDataErrorForParameter"));
- Object[] msgArgs = {new Integer(paramOrdinal)};
+ Object[] msgArgs = {paramOrdinal};
SQLServerException.makeFromDriverError(con, stmtParent, form.format(msgArgs) + " " + e.toString(), null, false);
}
}
@@ -322,23 +341,29 @@ private void parseQueryMetaFor2008(ResultSet rsQueryMeta) throws SQLServerExcept
* @param st
* string tokenizer
* @param firstToken
+ * @throws SQLServerException
* @returns the full token
*/
private String escapeParse(StringTokenizer st,
- String firstToken) {
- String nameFragment;
- String fullName;
- nameFragment = firstToken;
+ String firstToken) throws SQLServerException {
+
+ if (null == firstToken) {
+ MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_NullValue"));
+ Object[] msgArgs1 = {"firstToken"};
+ throw new SQLServerException(form.format(msgArgs1), null);
+ }
+
// skip spaces
- while (" ".equals(nameFragment) && st.hasMoreTokens()) {
- nameFragment = st.nextToken();
+ while ((0 == firstToken.trim().length()) && st.hasMoreTokens()) {
+ firstToken = st.nextToken();
}
- fullName = nameFragment;
- if (nameFragment.charAt(0) == '[' && nameFragment.charAt(nameFragment.length() - 1) != ']') {
+
+ String fullName = firstToken;
+ if (firstToken.charAt(0) == '[' && firstToken.charAt(firstToken.length() - 1) != ']') {
while (st.hasMoreTokens()) {
- nameFragment = st.nextToken();
- fullName = fullName.concat(nameFragment);
- if (nameFragment.charAt(nameFragment.length() - 1) == ']') {
+ firstToken = st.nextToken();
+ fullName = fullName.concat(firstToken);
+ if (firstToken.charAt(firstToken.length() - 1) == ']') {
break;
}
@@ -366,10 +391,11 @@ private class MetaInfo {
* String
* @param sTableMarker
* the location of the table in the syntax
+ * @throws SQLServerException
*/
private MetaInfo parseStatement(String sql,
- String sTableMarker) {
- StringTokenizer st = new StringTokenizer(sql, " ,\r\n", true);
+ String sTableMarker) throws SQLServerException {
+ StringTokenizer st = new StringTokenizer(sql, " ,\r\n\t\f(", true);
/* Find the table */
@@ -391,12 +417,24 @@ private MetaInfo parseStatement(String sql,
}
if (null != metaTable) {
- if (sTableMarker.equalsIgnoreCase("UPDATE"))
+ if (sTableMarker.equalsIgnoreCase("UPDATE")) {
metaFields = parseColumns(sql, "SET"); // Get the set fields
- else if (sTableMarker.equalsIgnoreCase("INTO")) // insert
+ stringToParse = "";
+ }
+ else if (sTableMarker.equalsIgnoreCase("INTO")) { // insert
metaFields = parseInsertColumns(sql, "("); // Get the value fields
- else
+ stringToParse = sql.substring(indexToBeginParse); // the index of ')'
+
+ // skip VALUES() clause
+ if (stringToParse.trim().toLowerCase().startsWith("values")) {
+ parseInsertColumns(stringToParse, "(");
+ stringToParse = stringToParse.substring(indexToBeginParse); // the index of ')'
+ }
+ }
+ else {
metaFields = parseColumns(sql, "WHERE"); // Get the where fields
+ stringToParse = "";
+ }
return new MetaInfo(metaTable, metaFields);
}
@@ -412,7 +450,7 @@ else if (sTableMarker.equalsIgnoreCase("INTO")) // insert
* @throws SQLServerException
*/
private MetaInfo parseStatement(String sql) throws SQLServerException {
- StringTokenizer st = new StringTokenizer(sql, " ");
+ StringTokenizer st = new StringTokenizer(sql, " \r\n\t\f");
if (st.hasMoreTokens()) {
String sToken = st.nextToken().trim();
@@ -577,20 +615,54 @@ private void checkClosed() throws SQLServerException {
}
else {
// old implementation for SQL server 2008
- MetaInfo metaInfo = parseStatement(sProcString);
- if (null == metaInfo) {
- MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_cantIdentifyTableMetadata"));
- Object[] msgArgs = {sProcString};
- SQLServerException.makeFromDriverError(con, stmtParent, form.format(msgArgs), null, false);
- }
+ 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"));
+ Object[] msgArgs = {stringToParse};
+ SQLServerException.makeFromDriverError(con, stmtParent, form.format(msgArgs), null, false);
+ }
- if (metaInfo.fields.length() <= 0)
+ metaInfoList.add(metaInfo);
+ }
+ if (metaInfoList.size() <= 0 || metaInfoList.get(0).fields.length() <= 0) {
return;
+ }
+
+ StringBuilder sbColumns = new StringBuilder();
+
+ for (MetaInfo mi : metaInfoList) {
+ sbColumns = sbColumns.append(mi.fields + ",");
+ }
+ sbColumns.deleteCharAt(sbColumns.length() - 1);
+
+ String columns = sbColumns.toString();
+
+ StringBuilder sbTablesAndJoins = new StringBuilder();
+ for (int i = 0; i < metaInfoList.size(); i++) {
+ if (i == 0) {
+ sbTablesAndJoins = sbTablesAndJoins.append(metaInfoList.get(i).table);
+ }
+ 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);
+ }
+ }
+
+ String tablesAndJoins = sbTablesAndJoins.toString();
Statement stmt = con.createStatement();
- String sCom = "sp_executesql N'SET FMTONLY ON SELECT " + metaInfo.fields + " FROM " + metaInfo.table + " WHERE 1 = 2'";
- ResultSet rs = stmt.executeQuery(sCom);
+ String sCom = "sp_executesql N'SET FMTONLY ON SELECT " + columns + " FROM " + tablesAndJoins + " '";
+ ResultSet rs = stmt.executeQuery(sCom);
parseQueryMetaFor2008(rs);
stmt.close();
rs.close();
@@ -637,12 +709,12 @@ public T unwrap(Class iface) throws SQLException {
}
catch (SQLException e) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_metaDataErrorForParameter"));
- Object[] msgArgs = {new Integer(param)};
+ Object[] msgArgs = {param};
SQLServerException.makeFromDriverError(con, stmtParent, form.format(msgArgs) + " " + e.toString(), null, false);
}
if (!bFound) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidParameterNumber"));
- Object[] msgArgs = {new Integer(param)};
+ Object[] msgArgs = {param};
SQLServerException.makeFromDriverError(con, stmtParent, form.format(msgArgs), null, false);
}
}
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement.java
index 4bfcb58e2f..2b9350e490 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement.java
@@ -235,7 +235,7 @@ final boolean doExecute() throws SQLServerException {
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, new Integer(handleToClose), false);
+ tdsWriter.writeRPCInt(null, handleToClose, false);
TDSParser.parse(startResponse(), getLogContext());
return true;
}
@@ -355,7 +355,7 @@ private String buildParamTypeDefinitions(Parameter[] params,
String typeDefinition = params[i].getTypeDefinition(connection, resultsReader());
if (null == typeDefinition) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_valueNotSetForParameter"));
- Object[] msgArgs = {new Integer(i + 1)};
+ Object[] msgArgs = {i + 1};
SQLServerException.makeFromDriverError(connection, this, form.format(msgArgs), null, false);
}
@@ -411,7 +411,7 @@ public int executeUpdate() throws SQLServerException {
if (updateCount < Integer.MIN_VALUE || updateCount > Integer.MAX_VALUE)
SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_updateCountOutofRange"), null, true);
- loggerExternal.exiting(getClassNameLogging(), "executeUpdate", new Long(updateCount));
+ loggerExternal.exiting(getClassNameLogging(), "executeUpdate", updateCount);
return (int) updateCount;
}
@@ -425,7 +425,7 @@ public long executeLargeUpdate() throws SQLServerException {
}
checkClosed();
executeStatement(new PrepStmtExecCmd(this, EXECUTE_UPDATE));
- loggerExternal.exiting(getClassNameLogging(), "executeLargeUpdate", new Long(updateCount));
+ loggerExternal.exiting(getClassNameLogging(), "executeLargeUpdate", updateCount);
return updateCount;
}
@@ -443,7 +443,7 @@ public boolean execute() throws SQLServerException {
}
checkClosed();
executeStatement(new PrepStmtExecCmd(this, EXECUTE));
- loggerExternal.exiting(getClassNameLogging(), "execute", Boolean.valueOf(null != resultSet));
+ loggerExternal.exiting(getClassNameLogging(), "execute", null != resultSet);
return null != resultSet;
}
@@ -577,7 +577,7 @@ boolean onRetValue(TDSReader tdsReader) throws SQLServerException {
setPreparedStatementHandle(param.getInt(tdsReader));
// Cache the reference to the newly created handle, NOT for cursorable handles.
- if (null == cachedPreparedStatementHandle && !isCursorable(executeMethod)) {
+ if (null == cachedPreparedStatementHandle && !isCursorable(executeMethod)) {
cachedPreparedStatementHandle = connection.registerCachedPreparedStatementHandle(new Sha1HashKey(preparedSQL, preparedTypeDefinitions), prepStmtHandle, executedSqlDirectly);
}
@@ -631,11 +631,11 @@ private void buildServerCursorPrepExecParams(TDSWriter tdsWriter) throws SQLServ
//
// IN (reprepare): Old handle to unprepare before repreparing
// OUT: The newly prepared handle
- tdsWriter.writeRPCInt(null, new Integer(getPreparedStatementHandle()), true);
+ tdsWriter.writeRPCInt(null, getPreparedStatementHandle(), true);
resetPrepStmtHandle();
// OUT
- tdsWriter.writeRPCInt(null, new Integer(0), true); // cursor ID (OUTPUT)
+ tdsWriter.writeRPCInt(null, 0, true); // cursor ID (OUTPUT)
// IN
tdsWriter.writeRPCStringUnicode((preparedTypeDefinitions.length() > 0) ? preparedTypeDefinitions : null);
@@ -647,13 +647,13 @@ private void buildServerCursorPrepExecParams(TDSWriter tdsWriter) throws SQLServ
// Note: we must strip out SCROLLOPT_PARAMETERIZED_STMT if we don't
// actually have any parameters.
tdsWriter.writeRPCInt(null,
- new Integer(getResultSetScrollOpt() & ~((0 == preparedTypeDefinitions.length()) ? TDS.SCROLLOPT_PARAMETERIZED_STMT : 0)), false);
+ getResultSetScrollOpt() & ~((0 == preparedTypeDefinitions.length()) ? TDS.SCROLLOPT_PARAMETERIZED_STMT : 0), false);
// IN
- tdsWriter.writeRPCInt(null, new Integer(getResultSetCCOpt()), false);
+ tdsWriter.writeRPCInt(null, getResultSetCCOpt(), false);
// OUT
- tdsWriter.writeRPCInt(null, new Integer(0), true);
+ tdsWriter.writeRPCInt(null, 0, true);
}
private void buildPrepExecParams(TDSWriter tdsWriter) throws SQLServerException {
@@ -673,7 +673,7 @@ private void buildPrepExecParams(TDSWriter tdsWriter) throws SQLServerException
//
// IN (reprepare): Old handle to unprepare before repreparing
// OUT: The newly prepared handle
- tdsWriter.writeRPCInt(null, new Integer(getPreparedStatementHandle()), true);
+ tdsWriter.writeRPCInt(null, getPreparedStatementHandle(), true);
resetPrepStmtHandle();
// IN
@@ -704,7 +704,8 @@ private void buildExecSQLParams(TDSWriter tdsWriter) throws SQLServerException {
tdsWriter.writeRPCStringUnicode(preparedSQL);
// IN
- tdsWriter.writeRPCStringUnicode((preparedTypeDefinitions.length() > 0) ? preparedTypeDefinitions : null);
+ if (preparedTypeDefinitions.length() > 0)
+ tdsWriter.writeRPCStringUnicode(preparedTypeDefinitions);
}
private void buildServerCursorExecParams(TDSWriter tdsWriter) throws SQLServerException {
@@ -723,19 +724,19 @@ private void buildServerCursorExecParams(TDSWriter tdsWriter) throws SQLServerEx
// IN
assert hasPreparedStatementHandle();
- tdsWriter.writeRPCInt(null, new Integer(getPreparedStatementHandle()), false);
+ tdsWriter.writeRPCInt(null, getPreparedStatementHandle(), false);
// OUT
- tdsWriter.writeRPCInt(null, new Integer(0), true);
+ tdsWriter.writeRPCInt(null, 0, true);
// IN
- tdsWriter.writeRPCInt(null, new Integer(getResultSetScrollOpt() & ~TDS.SCROLLOPT_PARAMETERIZED_STMT), false);
+ tdsWriter.writeRPCInt(null, getResultSetScrollOpt() & ~TDS.SCROLLOPT_PARAMETERIZED_STMT, false);
// IN
- tdsWriter.writeRPCInt(null, new Integer(getResultSetCCOpt()), false);
+ tdsWriter.writeRPCInt(null, getResultSetCCOpt(), false);
// OUT
- tdsWriter.writeRPCInt(null, new Integer(0), true);
+ tdsWriter.writeRPCInt(null, 0, true);
}
private void buildExecParams(TDSWriter tdsWriter) throws SQLServerException {
@@ -754,7 +755,7 @@ private void buildExecParams(TDSWriter tdsWriter) throws SQLServerException {
// IN
assert hasPreparedStatementHandle();
- tdsWriter.writeRPCInt(null, new Integer(getPreparedStatementHandle()), false);
+ tdsWriter.writeRPCInt(null, getPreparedStatementHandle(), false);
}
private void getParameterEncryptionMetadata(Parameter[] params) throws SQLServerException {
@@ -922,15 +923,17 @@ private boolean reuseCachedHandle(boolean hasNewTypeDefinitions, boolean discard
if(hasNewTypeDefinitions) {
if (null != cachedPreparedStatementHandle && hasPreparedStatementHandle() && prepStmtHandle == cachedPreparedStatementHandle.getHandle()) {
cachedPreparedStatementHandle.removeReference();
+ cachedPreparedStatementHandle.setIsExplicitlyDiscarded();
}
- cachedPreparedStatementHandle = null;
+ cachedPreparedStatementHandle = null;
}
- // Check for new cache reference.
+ // 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, or if it is on, make sure encryptionMetadataIsRetrieved is retrieved.
+ // 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)) {
@@ -943,7 +946,7 @@ private boolean reuseCachedHandle(boolean hasNewTypeDefinitions, boolean discard
}
}
return false;
- }
+ }
private boolean doPrepExec(TDSWriter tdsWriter,
Parameter[] params,
@@ -1049,7 +1052,7 @@ else if (resultSet != null) {
/* L0 */ final Parameter setterGetParam(int index) throws SQLServerException {
if (index < 1 || index > inOutParam.length) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_indexOutOfRange"));
- Object[] msgArgs = {new Integer(index)};
+ Object[] msgArgs = {index};
SQLServerException.makeFromDriverError(connection, this, form.format(msgArgs), "07009", false);
}
@@ -1144,7 +1147,7 @@ private Parameter getParam(int index) throws SQLServerException {
index--;
if (index < 0 || index >= inOutParam.length) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_indexOutOfRange"));
- Object[] msgArgs = {new Integer(index + 1)};
+ Object[] msgArgs = {index + 1};
SQLServerException.makeFromDriverError(connection, this, form.format(msgArgs), "07009", false);
}
return inOutParam[index];
@@ -1340,7 +1343,7 @@ public final void setBoolean(int n,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setBoolean", new Object[] {n, x});
checkClosed();
- setValue(n, JDBCType.BIT, Boolean.valueOf(x), JavaType.BOOLEAN, false);
+ setValue(n, JDBCType.BIT, x, JavaType.BOOLEAN, false);
loggerExternal.exiting(getClassNameLogging(), "setBoolean");
}
@@ -1365,7 +1368,7 @@ public final void setBoolean(int n,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setBoolean", new Object[] {n, x, forceEncrypt});
checkClosed();
- setValue(n, JDBCType.BIT, Boolean.valueOf(x), JavaType.BOOLEAN, forceEncrypt);
+ setValue(n, JDBCType.BIT, x, JavaType.BOOLEAN, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setBoolean");
}
@@ -1374,7 +1377,7 @@ public final void setByte(int n,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setByte", new Object[] {n, x});
checkClosed();
- setValue(n, JDBCType.TINYINT, Byte.valueOf(x), JavaType.BYTE, false);
+ setValue(n, JDBCType.TINYINT, x, JavaType.BYTE, false);
loggerExternal.exiting(getClassNameLogging(), "setByte");
}
@@ -1399,7 +1402,7 @@ public final void setByte(int n,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setByte", new Object[] {n, x, forceEncrypt});
checkClosed();
- setValue(n, JDBCType.TINYINT, Byte.valueOf(x), JavaType.BYTE, forceEncrypt);
+ setValue(n, JDBCType.TINYINT, x, JavaType.BYTE, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setByte");
}
@@ -1486,7 +1489,7 @@ public final void setDouble(int n,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setDouble", new Object[] {n, x});
checkClosed();
- setValue(n, JDBCType.DOUBLE, Double.valueOf(x), JavaType.DOUBLE, false);
+ setValue(n, JDBCType.DOUBLE, x, JavaType.DOUBLE, false);
loggerExternal.exiting(getClassNameLogging(), "setDouble");
}
@@ -1511,7 +1514,7 @@ public final void setDouble(int n,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setDouble", new Object[] {n, x, forceEncrypt});
checkClosed();
- setValue(n, JDBCType.DOUBLE, Double.valueOf(x), JavaType.DOUBLE, forceEncrypt);
+ setValue(n, JDBCType.DOUBLE, x, JavaType.DOUBLE, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setDouble");
}
@@ -1520,7 +1523,7 @@ public final void setFloat(int n,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setFloat", new Object[] {n, x});
checkClosed();
- setValue(n, JDBCType.REAL, Float.valueOf(x), JavaType.FLOAT, false);
+ setValue(n, JDBCType.REAL, x, JavaType.FLOAT, false);
loggerExternal.exiting(getClassNameLogging(), "setFloat");
}
@@ -1545,7 +1548,7 @@ public final void setFloat(int n,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setFloat", new Object[] {n, x, forceEncrypt});
checkClosed();
- setValue(n, JDBCType.REAL, Float.valueOf(x), JavaType.FLOAT, forceEncrypt);
+ setValue(n, JDBCType.REAL, x, JavaType.FLOAT, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setFloat");
}
@@ -1554,7 +1557,7 @@ public final void setInt(int n,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setInt", new Object[] {n, value});
checkClosed();
- setValue(n, JDBCType.INTEGER, Integer.valueOf(value), JavaType.INTEGER, false);
+ setValue(n, JDBCType.INTEGER, value, JavaType.INTEGER, false);
loggerExternal.exiting(getClassNameLogging(), "setInt");
}
@@ -1579,7 +1582,7 @@ public final void setInt(int n,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setInt", new Object[] {n, value, forceEncrypt});
checkClosed();
- setValue(n, JDBCType.INTEGER, Integer.valueOf(value), JavaType.INTEGER, forceEncrypt);
+ setValue(n, JDBCType.INTEGER, value, JavaType.INTEGER, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setInt");
}
@@ -1588,7 +1591,7 @@ public final void setLong(int n,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setLong", new Object[] {n, x});
checkClosed();
- setValue(n, JDBCType.BIGINT, Long.valueOf(x), JavaType.LONG, false);
+ setValue(n, JDBCType.BIGINT, x, JavaType.LONG, false);
loggerExternal.exiting(getClassNameLogging(), "setLong");
}
@@ -1613,7 +1616,7 @@ public final void setLong(int n,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setLong", new Object[] {n, x, forceEncrypt});
checkClosed();
- setValue(n, JDBCType.BIGINT, Long.valueOf(x), JavaType.LONG, forceEncrypt);
+ setValue(n, JDBCType.BIGINT, x, JavaType.LONG, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setLong");
}
@@ -1703,7 +1706,7 @@ public final void setObject(int parameterIndex,
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)) ? Integer.valueOf(scaleOrLength) : null,
+ || InputStream.class.isInstance(x) || Reader.class.isInstance(x)) ? scaleOrLength : null,
null, false, parameterIndex, null);
loggerExternal.exiting(getClassNameLogging(), "setObject");
@@ -1753,7 +1756,7 @@ public final void setObject(int parameterIndex,
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)) ? Integer.valueOf(scale) : null,
+ || InputStream.class.isInstance(x) || Reader.class.isInstance(x)) ? scale : null,
precision, false, parameterIndex, null);
loggerExternal.exiting(getClassNameLogging(), "setObject");
@@ -1809,7 +1812,7 @@ public final void setObject(int parameterIndex,
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)) ? Integer.valueOf(scale) : null,
+ || InputStream.class.isInstance(x) || Reader.class.isInstance(x)) ? scale : null,
precision, forceEncrypt, parameterIndex, null);
loggerExternal.exiting(getClassNameLogging(), "setObject");
@@ -1880,7 +1883,7 @@ public final void setShort(int index,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setShort", new Object[] {index, x});
checkClosed();
- setValue(index, JDBCType.SMALLINT, Short.valueOf(x), JavaType.SHORT, false);
+ setValue(index, JDBCType.SMALLINT, x, JavaType.SHORT, false);
loggerExternal.exiting(getClassNameLogging(), "setShort");
}
@@ -1905,7 +1908,7 @@ public final void setShort(int index,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "setShort", new Object[] {index, x, forceEncrypt});
checkClosed();
- setValue(index, JDBCType.SMALLINT, Short.valueOf(x), JavaType.SHORT, forceEncrypt);
+ setValue(index, JDBCType.SMALLINT, x, JavaType.SHORT, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "setShort");
}
@@ -2584,10 +2587,9 @@ final void doExecutePreparedStatementBatch(PrepStmtBatchExecCmd batchCommand) th
}
// Retry execution if existing handle could not be re-used.
- for(int attempt = 1; attempt <= 2; ++attempt) {
-
+ for(int attempt = 1; attempt <= 2; ++attempt) {
try {
-
+
// Re-use handle if available, requires parameter definitions which are not available until here.
if (reuseCachedHandle(hasNewTypeDefinitions, 1 < attempt)) {
hasNewTypeDefinitions = false;
@@ -2647,9 +2649,9 @@ final void doExecutePreparedStatementBatch(PrepStmtBatchExecCmd batchCommand) th
// Retry if invalid handle exception.
if (retryBasedOnFailedReuseOfCachedHandle(e, attempt)) {
- // Reset number of batches prepared.
+ //reset number of batches prepare
numBatchesPrepared = numBatchesExecuted;
- retry = true;
+ retry = true;
break;
}
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement42Helper.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement42Helper.java
index 702f3e2051..efd9c1774c 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement42Helper.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerPreparedStatement42Helper.java
@@ -28,7 +28,7 @@ static final void setObject(SQLServerPreparedStatement ps,
SQLServerStatement.loggerExternal.entering(ps.getClassNameLogging(), "setObject", new Object[] {index, obj, jdbcType});
// getVendorTypeNumber() returns the same constant integer values as in java.sql.Types
- ps.setObject(index, obj, jdbcType.getVendorTypeNumber().intValue());
+ ps.setObject(index, obj, jdbcType.getVendorTypeNumber());
SQLServerStatement.loggerExternal.exiting(ps.getClassNameLogging(), "setObject");
}
@@ -45,7 +45,7 @@ static final void setObject(SQLServerPreparedStatement ps,
new Object[] {parameterIndex, x, targetSqlType, scaleOrLength});
// getVendorTypeNumber() returns the same constant integer values as in java.sql.Types
- ps.setObject(parameterIndex, x, targetSqlType.getVendorTypeNumber().intValue(), scaleOrLength);
+ ps.setObject(parameterIndex, x, targetSqlType.getVendorTypeNumber(), scaleOrLength);
SQLServerStatement.loggerExternal.exiting(ps.getClassNameLogging(), "setObject");
}
@@ -63,7 +63,7 @@ static final void setObject(SQLServerPreparedStatement ps,
new Object[] {parameterIndex, x, targetSqlType, precision, scale});
// getVendorTypeNumber() returns the same constant integer values as in java.sql.Types
- ps.setObject(parameterIndex, x, targetSqlType.getVendorTypeNumber().intValue(), precision, scale, false);
+ ps.setObject(parameterIndex, x, targetSqlType.getVendorTypeNumber(), precision, scale, false);
SQLServerStatement.loggerExternal.exiting(ps.getClassNameLogging(), "setObject");
}
@@ -82,7 +82,7 @@ static final void setObject(SQLServerPreparedStatement ps,
new Object[] {parameterIndex, x, targetSqlType, precision, scale, forceEncrypt});
// getVendorTypeNumber() returns the same constant integer values as in java.sql.Types
- ps.setObject(parameterIndex, x, targetSqlType.getVendorTypeNumber().intValue(), precision, scale, forceEncrypt);
+ ps.setObject(parameterIndex, x, targetSqlType.getVendorTypeNumber(), precision, scale, forceEncrypt);
SQLServerStatement.loggerExternal.exiting(ps.getClassNameLogging(), "setObject");
}
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java
index 4386a6c5c7..3945a2096c 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java
@@ -33,7 +33,7 @@ protected Object[][] getContents() {
{"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_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}."},
@@ -96,7 +96,6 @@ protected Object[][] getContents() {
{"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_variantNotSupported", "The \"variant\" data type is not supported."},
{"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."},
@@ -104,6 +103,7 @@ protected Object[][] getContents() {
{"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."},
@@ -190,7 +190,7 @@ protected Object[][] getContents() {
{"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 conection. A value less than 1 means no cache."},
+ {"R_statementPoolingCacheSizePropertyDescription", "This setting specifies the size of the prepared statement cache for a conection. 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."},
@@ -203,7 +203,7 @@ protected Object[][] getContents() {
{"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_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."},
@@ -372,7 +372,7 @@ protected Object[][] getContents() {
{"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_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 enable FIPS compilant SSL connection between the client and the server."},
@@ -385,5 +385,10 @@ protected Object[][] getContents() {
{"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 datatype is not supported in pre-SQL 2008 version."},
+ {"R_invalidProbbytes", "SQL_VARIANT: invalid probBytes for {0} type."},
+ {"R_invalidStringValue", "SQL_VARIANT does not support string values more than 8000 length."},
+ {"R_invalidValueForTVPWithSQLVariant", "Inserting null value with column type sql_variant in TVP is not supported."},
};
}
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSet.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSet.java
index 98da7f11d0..936e4727e4 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSet.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSet.java
@@ -27,6 +27,7 @@
import java.sql.SQLXML;
import java.text.MessageFormat;
import java.util.Calendar;
+import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
@@ -395,7 +396,7 @@ boolean onDone(TDSReader tdsReader) throws SQLServerException {
public boolean isWrapperFor(Class> iface) throws SQLException {
loggerExternal.entering(getClassNameLogging(), "isWrapperFor");
boolean f = iface.isInstance(this);
- loggerExternal.exiting(getClassNameLogging(), "isWrapperFor", Boolean.valueOf(f));
+ loggerExternal.exiting(getClassNameLogging(), "isWrapperFor", f);
return f;
}
@@ -539,7 +540,7 @@ private void verifyValidColumnIndex(int index) throws SQLServerException {
if (index < 1 || index > nCols) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_indexOutOfRange"));
- Object[] msgArgs = {new Integer(index)};
+ Object[] msgArgs = {index};
SQLServerException.makeFromDriverError(stmt.connection, stmt, form.format(msgArgs), "07009", false);
}
}
@@ -1818,7 +1819,7 @@ public void setFetchDirection(int direction) throws SQLServerException {
(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 = {new Integer(direction)};
+ Object[] msgArgs = {direction};
SQLServerException.makeFromDriverError(stmt.connection, stmt, form.format(msgArgs), null, false);
}
@@ -1926,7 +1927,15 @@ private Object getValue(int columnIndex,
lastValueWasNull = (null == o);
return o;
}
-
+
+ void setInternalVariantType(int columnIndex, SqlVariant type) throws SQLServerException{
+ getterGetColumn(columnIndex).setInternalVariant(type);
+ }
+
+ 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(),
@@ -2008,7 +2017,7 @@ public boolean getBoolean(int columnIndex) throws SQLServerException {
checkClosed();
Boolean value = (Boolean) getValue(columnIndex, JDBCType.BIT);
loggerExternal.exiting(getClassNameLogging(), "getBoolean", value);
- return null != value ? value.booleanValue() : false;
+ return null != value ? value : false;
}
public boolean getBoolean(String columnName) throws SQLServerException {
@@ -2016,7 +2025,7 @@ public boolean getBoolean(String columnName) throws SQLServerException {
checkClosed();
Boolean value = (Boolean) getValue(findColumn(columnName), JDBCType.BIT);
loggerExternal.exiting(getClassNameLogging(), "getBoolean", value);
- return null != value ? value.booleanValue() : false;
+ return null != value ? value : false;
}
public byte getByte(int columnIndex) throws SQLServerException {
@@ -2092,7 +2101,7 @@ public double getDouble(int columnIndex) throws SQLServerException {
checkClosed();
Double value = (Double) getValue(columnIndex, JDBCType.DOUBLE);
loggerExternal.exiting(getClassNameLogging(), "getDouble", value);
- return null != value ? value.doubleValue() : 0;
+ return null != value ? value : 0;
}
public double getDouble(String columnName) throws SQLServerException {
@@ -2100,7 +2109,7 @@ public double getDouble(String columnName) throws SQLServerException {
checkClosed();
Double value = (Double) getValue(findColumn(columnName), JDBCType.DOUBLE);
loggerExternal.exiting(getClassNameLogging(), "getDouble", value);
- return null != value ? value.doubleValue() : 0;
+ return null != value ? value : 0;
}
public float getFloat(int columnIndex) throws SQLServerException {
@@ -2108,7 +2117,7 @@ public float getFloat(int columnIndex) throws SQLServerException {
checkClosed();
Float value = (Float) getValue(columnIndex, JDBCType.REAL);
loggerExternal.exiting(getClassNameLogging(), "getFloat", value);
- return null != value ? value.floatValue() : 0;
+ return null != value ? value : 0;
}
public float getFloat(String columnName) throws SQLServerException {
@@ -2116,7 +2125,7 @@ public float getFloat(String columnName) throws SQLServerException {
checkClosed();
Float value = (Float) getValue(findColumn(columnName), JDBCType.REAL);
loggerExternal.exiting(getClassNameLogging(), "getFloat", value);
- return null != value ? value.floatValue() : 0;
+ return null != value ? value : 0;
}
public int getInt(int columnIndex) throws SQLServerException {
@@ -2124,7 +2133,7 @@ public int getInt(int columnIndex) throws SQLServerException {
checkClosed();
Integer value = (Integer) getValue(columnIndex, JDBCType.INTEGER);
loggerExternal.exiting(getClassNameLogging(), "getInt", value);
- return null != value ? value.intValue() : 0;
+ return null != value ? value : 0;
}
public int getInt(String columnName) throws SQLServerException {
@@ -2132,7 +2141,7 @@ public int getInt(String columnName) throws SQLServerException {
checkClosed();
Integer value = (Integer) getValue(findColumn(columnName), JDBCType.INTEGER);
loggerExternal.exiting(getClassNameLogging(), "getInt", value);
- return null != value ? value.intValue() : 0;
+ return null != value ? value : 0;
}
public long getLong(int columnIndex) throws SQLServerException {
@@ -2140,7 +2149,7 @@ public long getLong(int columnIndex) throws SQLServerException {
checkClosed();
Long value = (Long) getValue(columnIndex, JDBCType.BIGINT);
loggerExternal.exiting(getClassNameLogging(), "getLong", value);
- return null != value ? value.longValue() : 0;
+ return null != value ? value : 0;
}
public long getLong(String columnName) throws SQLServerException {
@@ -2148,7 +2157,7 @@ public long getLong(String columnName) throws SQLServerException {
checkClosed();
Long value = (Long) getValue(findColumn(columnName), JDBCType.BIGINT);
loggerExternal.exiting(getClassNameLogging(), "getLong", value);
- return null != value ? value.longValue() : 0;
+ return null != value ? value : 0;
}
public java.sql.ResultSetMetaData getMetaData() throws SQLServerException {
@@ -2170,8 +2179,84 @@ public Object getObject(int columnIndex) throws SQLServerException {
public T getObject(int columnIndex,
Class type) throws SQLException {
- // The driver currently does not implement the optional JDBC APIs
- throw new SQLFeatureNotSupportedException(SQLServerException.getErrString("R_notSupported"));
+ loggerExternal.entering(getClassNameLogging(), "getObject", columnIndex);
+ checkClosed();
+ Object returnValue;
+ if (type == String.class) {
+ returnValue = getString(columnIndex);
+ }
+ else if (type == Byte.class) {
+ byte byteValue = getByte(columnIndex);
+ returnValue = wasNull() ? null : byteValue;
+ }
+ else if (type == Short.class) {
+ short shortValue = getShort(columnIndex);
+ returnValue = wasNull() ? null : shortValue;
+ }
+ else if (type == Integer.class) {
+ int intValue = getInt(columnIndex);
+ returnValue = wasNull() ? null : intValue;
+ }
+ else if (type == Long.class) {
+ long longValue = getLong(columnIndex);
+ returnValue = wasNull() ? null : longValue;
+ }
+ else if (type == BigDecimal.class) {
+ returnValue = getBigDecimal(columnIndex);
+ }
+ else if (type == Boolean.class) {
+ boolean booleanValue = getBoolean(columnIndex);
+ returnValue = wasNull() ? null : booleanValue;
+ }
+ else if (type == java.sql.Date.class) {
+ returnValue = getDate(columnIndex);
+ }
+ else if (type == java.sql.Time.class) {
+ returnValue = getTime(columnIndex);
+ }
+ else if (type == java.sql.Timestamp.class) {
+ returnValue = getTimestamp(columnIndex);
+ }
+ else if (type == microsoft.sql.DateTimeOffset.class) {
+ returnValue = getDateTimeOffset(columnIndex);
+ }
+ 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) {
+ returnValue = getSQLXML(columnIndex);
+ }
+ else if (type == Blob.class) {
+ returnValue = getBlob(columnIndex);
+ }
+ else if (type == Clob.class) {
+ returnValue = getClob(columnIndex);
+ }
+ else if (type == NClob.class) {
+ returnValue = getNClob(columnIndex);
+ }
+ else if (type == byte[].class) {
+ returnValue = getBytes(columnIndex);
+ }
+ else if (type == Float.class) {
+ float floatValue = getFloat(columnIndex);
+ returnValue = wasNull() ? null : floatValue;
+ }
+ else if (type == Double.class) {
+ double doubleValue = getDouble(columnIndex);
+ returnValue = wasNull() ? null : doubleValue;
+ }
+ 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);
+ }
+ loggerExternal.exiting(getClassNameLogging(), "getObject", columnIndex);
+ return type.cast(returnValue);
}
public Object getObject(String columnName) throws SQLServerException {
@@ -2184,8 +2269,11 @@ public Object getObject(String columnName) throws SQLServerException {
public T getObject(String columnName,
Class type) throws SQLException {
- // The driver currently does not implement the optional JDBC APIs
- throw new SQLFeatureNotSupportedException(SQLServerException.getErrString("R_notSupported"));
+ loggerExternal.entering(getClassNameLogging(), "getObject", columnName);
+ checkClosed();
+ T value = getObject(findColumn(columnName), type);
+ loggerExternal.exiting(getClassNameLogging(), "getObject", value);
+ return value;
}
public short getShort(int columnIndex) throws SQLServerException {
@@ -2193,7 +2281,7 @@ public short getShort(int columnIndex) throws SQLServerException {
checkClosed();
Short value = (Short) getValue(columnIndex, JDBCType.SMALLINT);
loggerExternal.exiting(getClassNameLogging(), "getShort", value);
- return null != value ? value.shortValue() : 0;
+ return null != value ? value : 0;
}
public short getShort(String columnName) throws SQLServerException {
@@ -2201,7 +2289,7 @@ public short getShort(String columnName) throws SQLServerException {
checkClosed();
Short value = (Short) getValue(findColumn(columnName), JDBCType.SMALLINT);
loggerExternal.exiting(getClassNameLogging(), "getShort", value);
- return null != value ? value.shortValue() : 0;
+ return null != value ? value : 0;
}
public String getString(int columnIndex) throws SQLServerException {
@@ -2946,7 +3034,7 @@ public void updateBoolean(int index,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "updateBoolean", new Object[] {index, x});
checkClosed();
- updateValue(index, JDBCType.BIT, Boolean.valueOf(x), JavaType.BOOLEAN, false);
+ updateValue(index, JDBCType.BIT, x, JavaType.BOOLEAN, false);
loggerExternal.exiting(getClassNameLogging(), "updateBoolean");
}
@@ -2973,7 +3061,7 @@ public void updateBoolean(int index,
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
loggerExternal.entering(getClassNameLogging(), "updateBoolean", new Object[] {index, x, forceEncrypt});
checkClosed();
- updateValue(index, JDBCType.BIT, Boolean.valueOf(x), JavaType.BOOLEAN, forceEncrypt);
+ updateValue(index, JDBCType.BIT, x, JavaType.BOOLEAN, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "updateBoolean");
}
@@ -2984,7 +3072,7 @@ public void updateByte(int index,
loggerExternal.entering(getClassNameLogging(), "updateByte", new Object[] {index, x});
checkClosed();
- updateValue(index, JDBCType.TINYINT, Byte.valueOf(x), JavaType.BYTE, false);
+ updateValue(index, JDBCType.TINYINT, x, JavaType.BYTE, false);
loggerExternal.exiting(getClassNameLogging(), "updateByte");
}
@@ -3012,7 +3100,7 @@ public void updateByte(int index,
loggerExternal.entering(getClassNameLogging(), "updateByte", new Object[] {index, x, forceEncrypt});
checkClosed();
- updateValue(index, JDBCType.TINYINT, Byte.valueOf(x), JavaType.BYTE, forceEncrypt);
+ updateValue(index, JDBCType.TINYINT, x, JavaType.BYTE, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "updateByte");
}
@@ -3023,7 +3111,7 @@ public void updateShort(int index,
loggerExternal.entering(getClassNameLogging(), "updateShort", new Object[] {index, x});
checkClosed();
- updateValue(index, JDBCType.SMALLINT, Short.valueOf(x), JavaType.SHORT, false);
+ updateValue(index, JDBCType.SMALLINT, x, JavaType.SHORT, false);
loggerExternal.exiting(getClassNameLogging(), "updateShort");
}
@@ -3051,7 +3139,7 @@ public void updateShort(int index,
loggerExternal.entering(getClassNameLogging(), "updateShort", new Object[] {index, x, forceEncrypt});
checkClosed();
- updateValue(index, JDBCType.SMALLINT, Short.valueOf(x), JavaType.SHORT, forceEncrypt);
+ updateValue(index, JDBCType.SMALLINT, x, JavaType.SHORT, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "updateShort");
}
@@ -3062,7 +3150,7 @@ public void updateInt(int index,
loggerExternal.entering(getClassNameLogging(), "updateInt", new Object[] {index, x});
checkClosed();
- updateValue(index, JDBCType.INTEGER, Integer.valueOf(x), JavaType.INTEGER, false);
+ updateValue(index, JDBCType.INTEGER, x, JavaType.INTEGER, false);
loggerExternal.exiting(getClassNameLogging(), "updateInt");
}
@@ -3090,7 +3178,7 @@ public void updateInt(int index,
loggerExternal.entering(getClassNameLogging(), "updateInt", new Object[] {index, x, forceEncrypt});
checkClosed();
- updateValue(index, JDBCType.INTEGER, Integer.valueOf(x), JavaType.INTEGER, forceEncrypt);
+ updateValue(index, JDBCType.INTEGER, x, JavaType.INTEGER, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "updateInt");
}
@@ -3101,7 +3189,7 @@ public void updateLong(int index,
loggerExternal.entering(getClassNameLogging(), "updateLong", new Object[] {index, x});
checkClosed();
- updateValue(index, JDBCType.BIGINT, Long.valueOf(x), JavaType.LONG, false);
+ updateValue(index, JDBCType.BIGINT, x, JavaType.LONG, false);
loggerExternal.exiting(getClassNameLogging(), "updateLong");
}
@@ -3129,7 +3217,7 @@ public void updateLong(int index,
loggerExternal.entering(getClassNameLogging(), "updateLong", new Object[] {index, x, forceEncrypt});
checkClosed();
- updateValue(index, JDBCType.BIGINT, Long.valueOf(x), JavaType.LONG, forceEncrypt);
+ updateValue(index, JDBCType.BIGINT, x, JavaType.LONG, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "updateLong");
}
@@ -3140,7 +3228,7 @@ public void updateFloat(int index,
loggerExternal.entering(getClassNameLogging(), "updateFloat", new Object[] {index, x});
checkClosed();
- updateValue(index, JDBCType.REAL, Float.valueOf(x), JavaType.FLOAT, false);
+ updateValue(index, JDBCType.REAL, x, JavaType.FLOAT, false);
loggerExternal.exiting(getClassNameLogging(), "updateFloat");
}
@@ -3168,7 +3256,7 @@ public void updateFloat(int index,
loggerExternal.entering(getClassNameLogging(), "updateFloat", new Object[] {index, x, forceEncrypt});
checkClosed();
- updateValue(index, JDBCType.REAL, Float.valueOf(x), JavaType.FLOAT, forceEncrypt);
+ updateValue(index, JDBCType.REAL, x, JavaType.FLOAT, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "updateFloat");
}
@@ -3179,7 +3267,7 @@ public void updateDouble(int index,
loggerExternal.entering(getClassNameLogging(), "updateDouble", new Object[] {index, x});
checkClosed();
- updateValue(index, JDBCType.DOUBLE, Double.valueOf(x), JavaType.DOUBLE, false);
+ updateValue(index, JDBCType.DOUBLE, x, JavaType.DOUBLE, false);
loggerExternal.exiting(getClassNameLogging(), "updateDouble");
}
@@ -3207,7 +3295,7 @@ public void updateDouble(int index,
loggerExternal.entering(getClassNameLogging(), "updateDouble", new Object[] {index, x, forceEncrypt});
checkClosed();
- updateValue(index, JDBCType.DOUBLE, Double.valueOf(x), JavaType.DOUBLE, forceEncrypt);
+ updateValue(index, JDBCType.DOUBLE, x, JavaType.DOUBLE, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "updateDouble");
}
@@ -4364,7 +4452,7 @@ public void updateObject(int index,
loggerExternal.entering(getClassNameLogging(), "updateObject", new Object[] {index, x, scale});
checkClosed();
- updateObject(index, x, Integer.valueOf(scale), null, null, false);
+ updateObject(index, x, scale, null, null, false);
loggerExternal.exiting(getClassNameLogging(), "updateObject");
}
@@ -4394,7 +4482,7 @@ public void updateObject(int index,
loggerExternal.entering(getClassNameLogging(), "updateObject", new Object[] {index, x, scale});
checkClosed();
- updateObject(index, x, Integer.valueOf(scale), null, precision, false);
+ updateObject(index, x, scale, null, precision, false);
loggerExternal.exiting(getClassNameLogging(), "updateObject");
}
@@ -4429,7 +4517,7 @@ public void updateObject(int index,
loggerExternal.entering(getClassNameLogging(), "updateObject", new Object[] {index, x, scale, forceEncrypt});
checkClosed();
- updateObject(index, x, Integer.valueOf(scale), null, precision, forceEncrypt);
+ updateObject(index, x, scale, null, precision, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "updateObject");
}
@@ -4507,7 +4595,7 @@ public void updateBoolean(String columnName,
loggerExternal.entering(getClassNameLogging(), "updateBoolean", new Object[] {columnName, x});
checkClosed();
- updateValue(findColumn(columnName), JDBCType.BIT, Boolean.valueOf(x), JavaType.BOOLEAN, false);
+ updateValue(findColumn(columnName), JDBCType.BIT, x, JavaType.BOOLEAN, false);
loggerExternal.exiting(getClassNameLogging(), "updateBoolean");
}
@@ -4535,7 +4623,7 @@ public void updateBoolean(String columnName,
loggerExternal.entering(getClassNameLogging(), "updateBoolean", new Object[] {columnName, x, forceEncrypt});
checkClosed();
- updateValue(findColumn(columnName), JDBCType.BIT, Boolean.valueOf(x), JavaType.BOOLEAN, forceEncrypt);
+ updateValue(findColumn(columnName), JDBCType.BIT, x, JavaType.BOOLEAN, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "updateBoolean");
}
@@ -4586,7 +4674,7 @@ public void updateShort(String columnName,
loggerExternal.entering(getClassNameLogging(), "updateShort", new Object[] {columnName, x});
checkClosed();
- updateValue(findColumn(columnName), JDBCType.SMALLINT, Short.valueOf(x), JavaType.SHORT, false);
+ updateValue(findColumn(columnName), JDBCType.SMALLINT, x, JavaType.SHORT, false);
loggerExternal.exiting(getClassNameLogging(), "updateShort");
}
@@ -4614,7 +4702,7 @@ public void updateShort(String columnName,
loggerExternal.entering(getClassNameLogging(), "updateShort", new Object[] {columnName, x, forceEncrypt});
checkClosed();
- updateValue(findColumn(columnName), JDBCType.SMALLINT, Short.valueOf(x), JavaType.SHORT, forceEncrypt);
+ updateValue(findColumn(columnName), JDBCType.SMALLINT, x, JavaType.SHORT, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "updateShort");
}
@@ -4625,7 +4713,7 @@ public void updateInt(String columnName,
loggerExternal.entering(getClassNameLogging(), "updateInt", new Object[] {columnName, x});
checkClosed();
- updateValue(findColumn(columnName), JDBCType.INTEGER, Integer.valueOf(x), JavaType.INTEGER, false);
+ updateValue(findColumn(columnName), JDBCType.INTEGER, x, JavaType.INTEGER, false);
loggerExternal.exiting(getClassNameLogging(), "updateInt");
}
@@ -4653,7 +4741,7 @@ public void updateInt(String columnName,
loggerExternal.entering(getClassNameLogging(), "updateInt", new Object[] {columnName, x, forceEncrypt});
checkClosed();
- updateValue(findColumn(columnName), JDBCType.INTEGER, Integer.valueOf(x), JavaType.INTEGER, forceEncrypt);
+ updateValue(findColumn(columnName), JDBCType.INTEGER, x, JavaType.INTEGER, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "updateInt");
}
@@ -4664,7 +4752,7 @@ public void updateLong(String columnName,
loggerExternal.entering(getClassNameLogging(), "updateLong", new Object[] {columnName, x});
checkClosed();
- updateValue(findColumn(columnName), JDBCType.BIGINT, Long.valueOf(x), JavaType.LONG, false);
+ updateValue(findColumn(columnName), JDBCType.BIGINT, x, JavaType.LONG, false);
loggerExternal.exiting(getClassNameLogging(), "updateLong");
}
@@ -4692,7 +4780,7 @@ public void updateLong(String columnName,
loggerExternal.entering(getClassNameLogging(), "updateLong", new Object[] {columnName, x, forceEncrypt});
checkClosed();
- updateValue(findColumn(columnName), JDBCType.BIGINT, Long.valueOf(x), JavaType.LONG, forceEncrypt);
+ updateValue(findColumn(columnName), JDBCType.BIGINT, x, JavaType.LONG, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "updateLong");
}
@@ -4703,7 +4791,7 @@ public void updateFloat(String columnName,
loggerExternal.entering(getClassNameLogging(), "updateFloat", new Object[] {columnName, x});
checkClosed();
- updateValue(findColumn(columnName), JDBCType.REAL, Float.valueOf(x), JavaType.FLOAT, false);
+ updateValue(findColumn(columnName), JDBCType.REAL, x, JavaType.FLOAT, false);
loggerExternal.exiting(getClassNameLogging(), "updateFloat");
}
@@ -4731,7 +4819,7 @@ public void updateFloat(String columnName,
loggerExternal.entering(getClassNameLogging(), "updateFloat", new Object[] {columnName, x, forceEncrypt});
checkClosed();
- updateValue(findColumn(columnName), JDBCType.REAL, Float.valueOf(x), JavaType.FLOAT, forceEncrypt);
+ updateValue(findColumn(columnName), JDBCType.REAL, x, JavaType.FLOAT, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "updateFloat");
}
@@ -4742,7 +4830,7 @@ public void updateDouble(String columnName,
loggerExternal.entering(getClassNameLogging(), "updateDouble", new Object[] {columnName, x});
checkClosed();
- updateValue(findColumn(columnName), JDBCType.DOUBLE, Double.valueOf(x), JavaType.DOUBLE, false);
+ updateValue(findColumn(columnName), JDBCType.DOUBLE, x, JavaType.DOUBLE, false);
loggerExternal.exiting(getClassNameLogging(), "updateDouble");
}
@@ -4770,7 +4858,7 @@ public void updateDouble(String columnName,
loggerExternal.entering(getClassNameLogging(), "updateDouble", new Object[] {columnName, x, forceEncrypt});
checkClosed();
- updateValue(findColumn(columnName), JDBCType.DOUBLE, Double.valueOf(x), JavaType.DOUBLE, forceEncrypt);
+ updateValue(findColumn(columnName), JDBCType.DOUBLE, x, JavaType.DOUBLE, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "updateDouble");
}
@@ -5415,7 +5503,7 @@ public void updateObject(String columnName,
loggerExternal.entering(getClassNameLogging(), "updateObject", new Object[] {columnName, x, scale});
checkClosed();
- updateObject(findColumn(columnName), x, Integer.valueOf(scale), null, null, false);
+ updateObject(findColumn(columnName), x, scale, null, null, false);
loggerExternal.exiting(getClassNameLogging(), "updateObject");
}
@@ -5445,7 +5533,7 @@ public void updateObject(String columnName,
loggerExternal.entering(getClassNameLogging(), "updateObject", new Object[] {columnName, x, precision, scale});
checkClosed();
- updateObject(findColumn(columnName), x, Integer.valueOf(scale), null, precision, false);
+ updateObject(findColumn(columnName), x, scale, null, precision, false);
loggerExternal.exiting(getClassNameLogging(), "updateObject");
}
@@ -5480,7 +5568,7 @@ public void updateObject(String columnName,
loggerExternal.entering(getClassNameLogging(), "updateObject", new Object[] {columnName, x, precision, scale, forceEncrypt});
checkClosed();
- updateObject(findColumn(columnName), x, Integer.valueOf(scale), null, precision, forceEncrypt);
+ updateObject(findColumn(columnName), x, scale, null, precision, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "updateObject");
}
@@ -5631,9 +5719,9 @@ private void doInsertRowRPC(TDSCommand command,
tdsWriter.writeShort(TDS.PROCID_SP_CURSOR);
tdsWriter.writeByte((byte) 0); // RPC procedure option 1
tdsWriter.writeByte((byte) 0); // RPC procedure option 2
- tdsWriter.writeRPCInt(null, new Integer(serverCursorId), false);
- tdsWriter.writeRPCInt(null, new Integer(TDS.SP_CURSOR_OP_INSERT), false);
- tdsWriter.writeRPCInt(null, new Integer(fetchBufferGetRow()), false);
+ tdsWriter.writeRPCInt(null, serverCursorId, false);
+ tdsWriter.writeRPCInt(null, (int) TDS.SP_CURSOR_OP_INSERT, false);
+ tdsWriter.writeRPCInt(null, fetchBufferGetRow(), false);
if (hasUpdatedColumns()) {
tdsWriter.writeRPCStringUnicode(tableName);
@@ -5706,9 +5794,9 @@ private void doUpdateRowRPC(TDSCommand command) throws SQLServerException {
tdsWriter.writeShort(TDS.PROCID_SP_CURSOR);
tdsWriter.writeByte((byte) 0); // RPC procedure option 1
tdsWriter.writeByte((byte) 0); // RPC procedure option 2
- tdsWriter.writeRPCInt(null, new Integer(serverCursorId), false);
- tdsWriter.writeRPCInt(null, new Integer(TDS.SP_CURSOR_OP_UPDATE | TDS.SP_CURSOR_OP_SETPOSITION), false);
- tdsWriter.writeRPCInt(null, new Integer(fetchBufferGetRow()), false);
+ tdsWriter.writeRPCInt(null, serverCursorId, false);
+ tdsWriter.writeRPCInt(null, TDS.SP_CURSOR_OP_UPDATE | TDS.SP_CURSOR_OP_SETPOSITION, false);
+ tdsWriter.writeRPCInt(null, fetchBufferGetRow(), false);
tdsWriter.writeRPCStringUnicode("");
assert hasUpdatedColumns();
@@ -5779,9 +5867,9 @@ private void doDeleteRowRPC(TDSCommand command) throws SQLServerException {
tdsWriter.writeShort(TDS.PROCID_SP_CURSOR);
tdsWriter.writeByte((byte) 0); // RPC procedure option 1
tdsWriter.writeByte((byte) 0); // RPC procedure option 2
- tdsWriter.writeRPCInt(null, new Integer(serverCursorId), false);
- tdsWriter.writeRPCInt(null, new Integer(TDS.SP_CURSOR_OP_DELETE | TDS.SP_CURSOR_OP_SETPOSITION), false);
- tdsWriter.writeRPCInt(null, new Integer(fetchBufferGetRow()), false);
+ tdsWriter.writeRPCInt(null, serverCursorId, false);
+ tdsWriter.writeRPCInt(null, TDS.SP_CURSOR_OP_DELETE | TDS.SP_CURSOR_OP_SETPOSITION, false);
+ tdsWriter.writeRPCInt(null, fetchBufferGetRow(), false);
tdsWriter.writeRPCStringUnicode("");
TDSParser.parse(command.startResponse(), command.getLogContext());
@@ -6337,10 +6425,10 @@ final boolean doExecute() throws SQLServerException {
tdsWriter.writeShort(TDS.PROCID_SP_CURSORFETCH);
tdsWriter.writeByte(TDS.RPC_OPTION_NO_METADATA);
tdsWriter.writeByte((byte) 0); // RPC procedure option 2
- tdsWriter.writeRPCInt(null, new Integer(serverCursorId), false);
- tdsWriter.writeRPCInt(null, new Integer(fetchType), false);
- tdsWriter.writeRPCInt(null, new Integer(startRow), false);
- tdsWriter.writeRPCInt(null, new Integer(numRows), false);
+ tdsWriter.writeRPCInt(null, serverCursorId, false);
+ tdsWriter.writeRPCInt(null, fetchType, false);
+ tdsWriter.writeRPCInt(null, startRow, false);
+ tdsWriter.writeRPCInt(null, numRows, false);
// To free up the thread on the server that is feeding us these results,
// read the entire response off the wire UNLESS this is a forward only
@@ -6489,7 +6577,7 @@ final boolean doExecute() throws SQLServerException {
tdsWriter.writeShort(TDS.PROCID_SP_CURSORCLOSE);
tdsWriter.writeByte((byte) 0); // RPC procedure option 1
tdsWriter.writeByte((byte) 0); // RPC procedure option 2
- tdsWriter.writeRPCInt(null, new Integer(serverCursorId), false);
+ tdsWriter.writeRPCInt(null, serverCursorId, false);
TDSParser.parse(startResponse(), getLogContext());
return true;
}
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSet42.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSet42.java
index a780e7e39c..cc900e65f3 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSet42.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSet42.java
@@ -57,7 +57,7 @@ public void updateObject(int index,
checkClosed();
// getVendorTypeNumber() returns the same constant integer values as in java.sql.Types
- updateObject(index, obj, Integer.valueOf(scale), JDBCType.of(targetSqlType.getVendorTypeNumber()), null, false);
+ updateObject(index, obj, scale, JDBCType.of(targetSqlType.getVendorTypeNumber()), null, false);
loggerExternal.exiting(getClassNameLogging(), "updateObject");
}
@@ -74,7 +74,7 @@ public void updateObject(int index,
checkClosed();
// getVendorTypeNumber() returns the same constant integer values as in java.sql.Types
- updateObject(index, obj, Integer.valueOf(scale), JDBCType.of(targetSqlType.getVendorTypeNumber()), null, forceEncrypt);
+ updateObject(index, obj, scale, JDBCType.of(targetSqlType.getVendorTypeNumber()), null, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "updateObject");
}
@@ -91,7 +91,7 @@ public void updateObject(String columnName,
checkClosed();
// getVendorTypeNumber() returns the same constant integer values as in java.sql.Types
- updateObject(findColumn(columnName), obj, Integer.valueOf(scale), JDBCType.of(targetSqlType.getVendorTypeNumber()), null, false);
+ updateObject(findColumn(columnName), obj, scale, JDBCType.of(targetSqlType.getVendorTypeNumber()), null, false);
loggerExternal.exiting(getClassNameLogging(), "updateObject");
}
@@ -109,7 +109,7 @@ public void updateObject(String columnName,
checkClosed();
// getVendorTypeNumber() returns the same constant integer values as in java.sql.Types
- updateObject(findColumn(columnName), obj, Integer.valueOf(scale), JDBCType.of(targetSqlType.getVendorTypeNumber()), null, forceEncrypt);
+ updateObject(findColumn(columnName), obj, scale, JDBCType.of(targetSqlType.getVendorTypeNumber()), null, forceEncrypt);
loggerExternal.exiting(getClassNameLogging(), "updateObject");
}
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSetMetaData.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSetMetaData.java
index 7efb83bad1..693f3fe0cd 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSetMetaData.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResultSetMetaData.java
@@ -120,8 +120,12 @@ public int getColumnType(int column) throws SQLServerException {
if (null != cryptoMetadata) {
typeInfo = cryptoMetadata.getBaseTypeInfo();
}
-
+
JDBCType jdbcType = typeInfo.getSSType().getJDBCType();
+ // 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 == typeInfo.getSSType()){
+ jdbcType = JDBCType.SQL_VARIANT;
+ }
int r = jdbcType.asJavaSqlType();
if (con.isKatmaiOrLater()) {
SSType sqlType = typeInfo.getSSType();
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerStatement.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerStatement.java
index 3ae799ab92..632edf9e64 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerStatement.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerStatement.java
@@ -688,7 +688,7 @@ public int executeUpdate(String sql) throws SQLServerException {
if (updateCount < Integer.MIN_VALUE || updateCount > Integer.MAX_VALUE)
SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_updateCountOutofRange"), null, true);
- loggerExternal.exiting(getClassNameLogging(), "executeUpdate", new Long(updateCount));
+ loggerExternal.exiting(getClassNameLogging(), "executeUpdate", updateCount);
return (int) updateCount;
}
@@ -712,7 +712,7 @@ public long executeLargeUpdate(String sql) throws SQLServerException {
checkClosed();
executeStatement(new StmtExecCmd(this, sql, EXECUTE_UPDATE, NO_GENERATED_KEYS));
- loggerExternal.exiting(getClassNameLogging(), "executeLargeUpdate", new Long(updateCount));
+ loggerExternal.exiting(getClassNameLogging(), "executeLargeUpdate", updateCount);
return updateCount;
}
@@ -732,7 +732,7 @@ public boolean execute(String sql) throws SQLServerException {
}
checkClosed();
executeStatement(new StmtExecCmd(this, sql, EXECUTE, NO_GENERATED_KEYS));
- loggerExternal.exiting(getClassNameLogging(), "execute", Boolean.valueOf(null != resultSet));
+ loggerExternal.exiting(getClassNameLogging(), "execute", null != resultSet);
return null != resultSet;
}
@@ -1032,16 +1032,16 @@ final void resetForReexecute() throws SQLServerException {
/* L0 */ public final int getMaxFieldSize() throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "getMaxFieldSize");
checkClosed();
- loggerExternal.exiting(getClassNameLogging(), "getMaxFieldSize", new Integer(maxFieldSize));
+ loggerExternal.exiting(getClassNameLogging(), "getMaxFieldSize", maxFieldSize);
return maxFieldSize;
}
/* L0 */ public final void setMaxFieldSize(int max) throws SQLServerException {
- loggerExternal.entering(getClassNameLogging(), "setMaxFieldSize", new Integer(max));
+ loggerExternal.entering(getClassNameLogging(), "setMaxFieldSize", max);
checkClosed();
if (max < 0) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidLength"));
- Object[] msgArgs = {new Integer(max)};
+ Object[] msgArgs = {max};
SQLServerException.makeFromDriverError(connection, this, form.format(msgArgs), null, true);
}
maxFieldSize = max;
@@ -1051,7 +1051,7 @@ final void resetForReexecute() throws SQLServerException {
/* L0 */ public final int getMaxRows() throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "getMaxRows");
checkClosed();
- loggerExternal.exiting(getClassNameLogging(), "getMaxRows", new Integer(maxRows));
+ loggerExternal.exiting(getClassNameLogging(), "getMaxRows", maxRows);
return maxRows;
}
@@ -1062,18 +1062,18 @@ public final long getLargeMaxRows() throws SQLServerException {
// SQL Server only supports integer limits for setting max rows.
// So, getLargeMaxRows() and getMaxRows() will return the same value.
- loggerExternal.exiting(getClassNameLogging(), "getLargeMaxRows", new Long(maxRows));
+ loggerExternal.exiting(getClassNameLogging(), "getLargeMaxRows", (long) maxRows);
return (long) getMaxRows();
}
/* L0 */ public final void setMaxRows(int max) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
- loggerExternal.entering(getClassNameLogging(), "setMaxRows", new Integer(max));
+ loggerExternal.entering(getClassNameLogging(), "setMaxRows", max);
checkClosed();
if (max < 0) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidRowcount"));
- Object[] msgArgs = {new Integer(max)};
+ Object[] msgArgs = {max};
SQLServerException.makeFromDriverError(connection, this, form.format(msgArgs), null, true);
}
@@ -1089,7 +1089,7 @@ public final void setLargeMaxRows(long max) throws SQLServerException {
DriverJDBCVersion.checkSupportsJDBC42();
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
- loggerExternal.entering(getClassNameLogging(), "setLargeMaxRows", new Long(max));
+ loggerExternal.entering(getClassNameLogging(), "setLargeMaxRows", max);
// SQL server only supports integer limits for setting max rows.
// If is bigger than integer limits then throw an exception, otherwise call setMaxRows(int)
@@ -1102,7 +1102,7 @@ public final void setLargeMaxRows(long max) throws SQLServerException {
/* L0 */ public final void setEscapeProcessing(boolean enable) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
- loggerExternal.entering(getClassNameLogging(), "setEscapeProcessing", Boolean.valueOf(enable));
+ loggerExternal.entering(getClassNameLogging(), "setEscapeProcessing", enable);
checkClosed();
escapeProcessing = enable;
loggerExternal.exiting(getClassNameLogging(), "setEscapeProcessing");
@@ -1111,16 +1111,16 @@ public final void setLargeMaxRows(long max) throws SQLServerException {
/* L0 */ public final int getQueryTimeout() throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "getQueryTimeout");
checkClosed();
- loggerExternal.exiting(getClassNameLogging(), "getQueryTimeout", new Integer(queryTimeout));
+ loggerExternal.exiting(getClassNameLogging(), "getQueryTimeout", queryTimeout);
return queryTimeout;
}
/* L0 */ public final void setQueryTimeout(int seconds) throws SQLServerException {
- loggerExternal.entering(getClassNameLogging(), "setQueryTimeout", new Integer(seconds));
+ loggerExternal.entering(getClassNameLogging(), "setQueryTimeout", seconds);
checkClosed();
if (seconds < 0) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidQueryTimeOutValue"));
- Object[] msgArgs = {new Integer(seconds)};
+ Object[] msgArgs = {seconds};
SQLServerException.makeFromDriverError(connection, this, form.format(msgArgs), null, true);
}
queryTimeout = seconds;
@@ -1183,7 +1183,7 @@ public final java.sql.ResultSet getResultSet() throws SQLServerException {
if (updateCount < Integer.MIN_VALUE || updateCount > Integer.MAX_VALUE)
SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_updateCountOutofRange"), null, true);
- loggerExternal.exiting(getClassNameLogging(), "getUpdateCount", new Long(updateCount));
+ loggerExternal.exiting(getClassNameLogging(), "getUpdateCount", updateCount);
return (int) updateCount;
}
@@ -1193,7 +1193,7 @@ public final long getLargeUpdateCount() throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "getUpdateCount");
checkClosed();
- loggerExternal.exiting(getClassNameLogging(), "getUpdateCount", new Long(updateCount));
+ loggerExternal.exiting(getClassNameLogging(), "getUpdateCount", updateCount);
return updateCount;
}
@@ -1268,7 +1268,7 @@ final void processResults() throws SQLServerException {
// Don't just return the value from the getNextResult() call, however.
// The getMoreResults method has a subtle spec for its return value (see above).
getNextResult();
- loggerExternal.exiting(getClassNameLogging(), "getMoreResults", Boolean.valueOf(null != resultSet));
+ loggerExternal.exiting(getClassNameLogging(), "getMoreResults", null != resultSet);
return null != resultSet;
}
@@ -1609,14 +1609,14 @@ boolean consumeExecOutParam(TDSReader tdsReader) throws SQLServerException {
public final void setFetchDirection(int nDir) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
- loggerExternal.entering(getClassNameLogging(), "setFetchDirection", new Integer(nDir));
+ loggerExternal.entering(getClassNameLogging(), "setFetchDirection", nDir);
checkClosed();
if ((ResultSet.FETCH_FORWARD != nDir && ResultSet.FETCH_REVERSE != nDir && ResultSet.FETCH_UNKNOWN != nDir) ||
(ResultSet.FETCH_FORWARD != nDir && (SQLServerResultSet.TYPE_SS_DIRECT_FORWARD_ONLY == resultSetType
|| SQLServerResultSet.TYPE_SS_SERVER_CURSOR_FORWARD_ONLY == resultSetType))) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidFetchDirection"));
- Object[] msgArgs = {new Integer(nDir)};
+ Object[] msgArgs = {nDir};
SQLServerException.makeFromDriverError(connection, this, form.format(msgArgs), null, false);
}
@@ -1627,13 +1627,13 @@ public final void setFetchDirection(int nDir) throws SQLServerException {
public final int getFetchDirection() throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "getFetchDirection");
checkClosed();
- loggerExternal.exiting(getClassNameLogging(), "getFetchDirection", new Integer(nFetchDirection));
+ loggerExternal.exiting(getClassNameLogging(), "getFetchDirection", nFetchDirection);
return nFetchDirection;
}
/* L0 */ public final void setFetchSize(int rows) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
- loggerExternal.entering(getClassNameLogging(), "setFetchSize", new Integer(rows));
+ loggerExternal.entering(getClassNameLogging(), "setFetchSize", rows);
checkClosed();
if (rows < 0)
SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_invalidFetchSize"), null, false);
@@ -1645,21 +1645,21 @@ public final int getFetchDirection() throws SQLServerException {
/* L0 */ public final int getFetchSize() throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "getFetchSize");
checkClosed();
- loggerExternal.exiting(getClassNameLogging(), "getFetchSize", new Integer(nFetchSize));
+ loggerExternal.exiting(getClassNameLogging(), "getFetchSize", nFetchSize);
return nFetchSize;
}
/* L0 */ public final int getResultSetConcurrency() throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "getResultSetConcurrency");
checkClosed();
- loggerExternal.exiting(getClassNameLogging(), "getResultSetConcurrency", new Integer(resultSetConcurrency));
+ loggerExternal.exiting(getClassNameLogging(), "getResultSetConcurrency", resultSetConcurrency);
return resultSetConcurrency;
}
/* L0 */ public final int getResultSetType() throws SQLServerException {
loggerExternal.entering(getClassNameLogging(), "getResultSetType");
checkClosed();
- loggerExternal.exiting(getClassNameLogging(), "getResultSetType", new Integer(appResultSetType));
+ loggerExternal.exiting(getClassNameLogging(), "getResultSetType", appResultSetType);
return appResultSetType;
}
@@ -1929,19 +1929,19 @@ private void doExecuteCursored(StmtExecCmd execCmd,
tdsWriter.writeByte((byte) 0); // RPC procedure option 2
// OUT
- tdsWriter.writeRPCInt(null, new Integer(0), true);
+ tdsWriter.writeRPCInt(null, 0, true);
// IN
tdsWriter.writeRPCStringUnicode(sql);
// IN
- tdsWriter.writeRPCInt(null, new Integer(getResultSetScrollOpt()), false);
+ tdsWriter.writeRPCInt(null, getResultSetScrollOpt(), false);
// IN
- tdsWriter.writeRPCInt(null, new Integer(getResultSetCCOpt()), false);
+ tdsWriter.writeRPCInt(null, getResultSetCCOpt(), false);
// OUT
- tdsWriter.writeRPCInt(null, new Integer(0), true);
+ tdsWriter.writeRPCInt(null, 0, true);
ensureExecuteResultsReader(execCmd.startResponse(isResponseBufferingAdaptive));
startResults();
@@ -1954,14 +1954,14 @@ private void doExecuteCursored(StmtExecCmd execCmd,
loggerExternal.entering(getClassNameLogging(), "getResultSetHoldability");
checkClosed();
int holdability = connection.getHoldability(); // For SQL Server must be the same as the connection
- loggerExternal.exiting(getClassNameLogging(), "getResultSetHoldability", new Integer(holdability));
+ loggerExternal.exiting(getClassNameLogging(), "getResultSetHoldability", holdability);
return holdability;
}
public final boolean execute(java.lang.String sql,
int autoGeneratedKeys) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) {
- loggerExternal.entering(getClassNameLogging(), "execute", new Object[] {sql, new Integer(autoGeneratedKeys)});
+ loggerExternal.entering(getClassNameLogging(), "execute", new Object[] {sql, autoGeneratedKeys});
if (Util.IsActivityTraceOn()) {
loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
}
@@ -1969,12 +1969,12 @@ public final boolean execute(java.lang.String sql,
checkClosed();
if (autoGeneratedKeys != Statement.RETURN_GENERATED_KEYS && autoGeneratedKeys != Statement.NO_GENERATED_KEYS) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidAutoGeneratedKeys"));
- Object[] msgArgs = {new Integer(autoGeneratedKeys)};
+ Object[] msgArgs = {autoGeneratedKeys};
SQLServerException.makeFromDriverError(connection, this, form.format(msgArgs), null, false);
}
executeStatement(new StmtExecCmd(this, sql, EXECUTE, autoGeneratedKeys));
- loggerExternal.exiting(getClassNameLogging(), "execute", Boolean.valueOf(null != resultSet));
+ loggerExternal.exiting(getClassNameLogging(), "execute", null != resultSet);
return null != resultSet;
}
@@ -1987,7 +1987,7 @@ public final boolean execute(java.lang.String sql,
SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_invalidColumnArrayLength"), null, false);
}
boolean fSuccess = execute(sql, Statement.RETURN_GENERATED_KEYS);
- loggerExternal.exiting(getClassNameLogging(), "execute", Boolean.valueOf(fSuccess));
+ loggerExternal.exiting(getClassNameLogging(), "execute", fSuccess);
return fSuccess;
}
@@ -2000,14 +2000,14 @@ public final boolean execute(java.lang.String sql,
SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_invalidColumnArrayLength"), null, false);
}
boolean fSuccess = execute(sql, Statement.RETURN_GENERATED_KEYS);
- loggerExternal.exiting(getClassNameLogging(), "execute", Boolean.valueOf(fSuccess));
+ loggerExternal.exiting(getClassNameLogging(), "execute", fSuccess);
return fSuccess;
}
public final int executeUpdate(String sql,
int autoGeneratedKeys) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) {
- loggerExternal.entering(getClassNameLogging(), "executeUpdate", new Object[] {sql, new Integer(autoGeneratedKeys)});
+ loggerExternal.entering(getClassNameLogging(), "executeUpdate", new Object[] {sql, autoGeneratedKeys});
if (Util.IsActivityTraceOn()) {
loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
}
@@ -2015,7 +2015,7 @@ public final int executeUpdate(String sql,
checkClosed();
if (autoGeneratedKeys != Statement.RETURN_GENERATED_KEYS && autoGeneratedKeys != Statement.NO_GENERATED_KEYS) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidAutoGeneratedKeys"));
- Object[] msgArgs = {new Integer(autoGeneratedKeys)};
+ Object[] msgArgs = {autoGeneratedKeys};
SQLServerException.makeFromDriverError(connection, this, form.format(msgArgs), null, false);
}
executeStatement(new StmtExecCmd(this, sql, EXECUTE_UPDATE, autoGeneratedKeys));
@@ -2024,7 +2024,7 @@ public final int executeUpdate(String sql,
if (updateCount < Integer.MIN_VALUE || updateCount > Integer.MAX_VALUE)
SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_updateCountOutofRange"), null, true);
- loggerExternal.exiting(getClassNameLogging(), "executeUpdate", new Long(updateCount));
+ loggerExternal.exiting(getClassNameLogging(), "executeUpdate", updateCount);
return (int) updateCount;
}
@@ -2034,7 +2034,7 @@ public final long executeLargeUpdate(String sql,
DriverJDBCVersion.checkSupportsJDBC42();
if (loggerExternal.isLoggable(java.util.logging.Level.FINER)) {
- loggerExternal.entering(getClassNameLogging(), "executeLargeUpdate", new Object[] {sql, new Integer(autoGeneratedKeys)});
+ loggerExternal.entering(getClassNameLogging(), "executeLargeUpdate", new Object[] {sql, autoGeneratedKeys});
if (Util.IsActivityTraceOn()) {
loggerExternal.finer(toString() + " ActivityId: " + ActivityCorrelator.getNext().toString());
}
@@ -2042,11 +2042,11 @@ public final long executeLargeUpdate(String sql,
checkClosed();
if (autoGeneratedKeys != Statement.RETURN_GENERATED_KEYS && autoGeneratedKeys != Statement.NO_GENERATED_KEYS) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidAutoGeneratedKeys"));
- Object[] msgArgs = {new Integer(autoGeneratedKeys)};
+ Object[] msgArgs = {autoGeneratedKeys};
SQLServerException.makeFromDriverError(connection, this, form.format(msgArgs), null, false);
}
executeStatement(new StmtExecCmd(this, sql, EXECUTE_UPDATE, autoGeneratedKeys));
- loggerExternal.exiting(getClassNameLogging(), "executeLargeUpdate", new Long(updateCount));
+ loggerExternal.exiting(getClassNameLogging(), "executeLargeUpdate", updateCount);
return updateCount;
}
@@ -2059,7 +2059,7 @@ public final int executeUpdate(java.lang.String sql,
SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_invalidColumnArrayLength"), null, false);
}
int count = executeUpdate(sql, Statement.RETURN_GENERATED_KEYS);
- loggerExternal.exiting(getClassNameLogging(), "executeUpdate", new Integer(count));
+ loggerExternal.exiting(getClassNameLogging(), "executeUpdate", count);
return count;
}
@@ -2074,7 +2074,7 @@ public final long executeLargeUpdate(java.lang.String sql,
SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_invalidColumnArrayLength"), null, false);
}
long count = executeLargeUpdate(sql, Statement.RETURN_GENERATED_KEYS);
- loggerExternal.exiting(getClassNameLogging(), "executeLargeUpdate", new Long(count));
+ loggerExternal.exiting(getClassNameLogging(), "executeLargeUpdate", count);
return count;
}
@@ -2087,7 +2087,7 @@ public final int executeUpdate(java.lang.String sql,
SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_invalidColumnArrayLength"), null, false);
}
int count = executeUpdate(sql, Statement.RETURN_GENERATED_KEYS);
- loggerExternal.exiting(getClassNameLogging(), "executeUpdate", new Integer(count));
+ loggerExternal.exiting(getClassNameLogging(), "executeUpdate", count);
return count;
}
@@ -2102,7 +2102,7 @@ public final long executeLargeUpdate(java.lang.String sql,
SQLServerException.makeFromDriverError(connection, this, SQLServerException.getErrString("R_invalidColumnArrayLength"), null, false);
}
long count = executeLargeUpdate(sql, Statement.RETURN_GENERATED_KEYS);
- loggerExternal.exiting(getClassNameLogging(), "executeLargeUpdate", new Long(count));
+ loggerExternal.exiting(getClassNameLogging(), "executeLargeUpdate", count);
return count;
}
@@ -2129,7 +2129,7 @@ public final ResultSet getGeneratedKeys() throws SQLServerException {
/* L3 */ public final boolean getMoreResults(int mode) throws SQLServerException {
if (loggerExternal.isLoggable(java.util.logging.Level.FINER))
- loggerExternal.entering(getClassNameLogging(), "getMoreResults", new Integer(mode));
+ loggerExternal.entering(getClassNameLogging(), "getMoreResults", mode);
checkClosed();
if (KEEP_CURRENT_RESULT == mode)
NotImplemented();
@@ -2148,7 +2148,7 @@ public final ResultSet getGeneratedKeys() throws SQLServerException {
}
}
- loggerExternal.exiting(getClassNameLogging(), "getMoreResults", Boolean.valueOf(fResults));
+ loggerExternal.exiting(getClassNameLogging(), "getMoreResults", fResults);
return fResults;
}
@@ -2183,7 +2183,7 @@ public void setPoolable(boolean poolable) throws SQLException {
public boolean isWrapperFor(Class> iface) throws SQLException {
loggerExternal.entering(getClassNameLogging(), "isWrapperFor");
boolean f = iface.isInstance(this);
- loggerExternal.exiting(getClassNameLogging(), "isWrapperFor", Boolean.valueOf(f));
+ loggerExternal.exiting(getClassNameLogging(), "isWrapperFor", f);
return f;
}
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SqlVariant.java b/src/main/java/com/microsoft/sqlserver/jdbc/SqlVariant.java
new file mode 100644
index 0000000000..2d4c134361
--- /dev/null
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/SqlVariant.java
@@ -0,0 +1,211 @@
+/*
+ * Microsoft JDBC Driver for SQL Server
+ *
+ * Copyright(c) Microsoft Corporation All rights reserved.
+ *
+ * This program is made 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 = {new Integer(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;
+ }
+}
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/TVP.java b/src/main/java/com/microsoft/sqlserver/jdbc/TVP.java
index 7896215a3d..5113f1fc05 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/TVP.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/TVP.java
@@ -47,7 +47,6 @@ class TVP {
Map columnMetadata = null;
Iterator> sourceDataTableRowIterator = null;
ISQLServerDataRecord sourceRecord = null;
-
TVPType tvpType = null;
// MultiPartIdentifierState
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/Util.java b/src/main/java/com/microsoft/sqlserver/jdbc/Util.java
index 625a52797f..d630d6e48a 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/Util.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/Util.java
@@ -244,7 +244,7 @@ static BigDecimal readBigDecimal(byte valueBytes[],
String name = "";
String value = "";
StringBuilder builder;
-
+
if (!tmpUrl.startsWith(sPrefix))
return null;
@@ -390,7 +390,7 @@ else if (ch == ':')
if (null != name) {
if (logger.isLoggable(Level.FINE)) {
if (false == name.equals(SQLServerDriverStringProperty.USER.toString())) {
- if (!name.toLowerCase().contains("password")) {
+ if (!name.toLowerCase(Locale.ENGLISH).contains("password")) {
logger.fine("Property:" + name + " Value:" + value);
}
else {
@@ -605,7 +605,7 @@ static String readUnicodeString(byte[] b,
catch (IndexOutOfBoundsException ex) {
String txtMsg = SQLServerException.checkAndAppendClientConnId(SQLServerException.getErrString("R_stringReadError"), conn);
MessageFormat form = new MessageFormat(txtMsg);
- Object[] msgArgs = {new Integer(offset)};
+ Object[] msgArgs = {offset};
// Re-throw SQLServerException if conversion fails.
throw new SQLServerException(form.format(msgArgs), null, 0, ex);
}
@@ -714,6 +714,46 @@ static final byte[] asGuidByteArray(UUID aId) {
return buffer;
}
+ static final UUID readGUIDtoUUID(byte[] inputGUID) throws SQLServerException {
+ if (inputGUID.length != 16) {
+ throw new SQLServerException("guid length must be 16", null);
+ }
+
+ // For the first three fields, UUID uses network byte order,
+ // Guid uses native byte order. So we need to reverse
+ // the first three fields before creating a UUID.
+
+ byte tmpByte;
+
+ // Reverse the first 4 bytes
+ tmpByte = inputGUID[0];
+ inputGUID[0] = inputGUID[3];
+ inputGUID[3] = tmpByte;
+ tmpByte = inputGUID[1];
+ inputGUID[1] = inputGUID[2];
+ inputGUID[2] = tmpByte;
+
+ // Reverse the 5th and the 6th
+ tmpByte = inputGUID[4];
+ inputGUID[4] = inputGUID[5];
+ inputGUID[5] = tmpByte;
+
+ // Reverse the 7th and the 8th
+ tmpByte = inputGUID[6];
+ inputGUID[6] = inputGUID[7];
+ inputGUID[7] = tmpByte;
+
+ long msb = 0L;
+ for (int i = 0; i < 8; i++) {
+ msb = msb << 8 | ((long) inputGUID[i] & 0xFFL);
+ }
+ long lsb = 0L;
+ for (int i = 8; i < 16; i++) {
+ lsb = lsb << 8 | ((long) inputGUID[i] & 0xFFL);
+ }
+ return new UUID(msb, lsb);
+ }
+
static final String readGUID(byte[] inputGUID) throws SQLServerException {
String guidTemplate = "NNNNNNNN-NNNN-NNNN-NNNN-NNNNNNNNNNNN";
byte guid[] = inputGUID;
@@ -911,7 +951,7 @@ else if (("" + value).contains("E")) {
case TIME:
case DATETIMEOFFSET:
return ((null == scale) ? TDS.MAX_FRACTIONAL_SECONDS_SCALE : scale);
-
+
case CLOB:
return ((null == value) ? 0 : (DataTypes.NTEXT_MAX_CHARS * 2));
@@ -953,7 +993,7 @@ static synchronized boolean checkIfNeedNewAccessToken(SQLServerConnection connec
}
static final boolean use42Wrapper;
-
+
static {
boolean supportJDBC42 = true;
try {
diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/dtv.java b/src/main/java/com/microsoft/sqlserver/jdbc/dtv.java
index 113f580594..c836c031db 100644
--- a/src/main/java/com/microsoft/sqlserver/jdbc/dtv.java
+++ b/src/main/java/com/microsoft/sqlserver/jdbc/dtv.java
@@ -139,6 +139,9 @@ abstract void execute(DTV dtv,
abstract void execute(DTV dtv,
TVP tvpValue) throws SQLServerException;
+
+ abstract void execute(DTV dtv,
+ SqlVariant sqlVariantValue) throws SQLServerException;
}
/**
@@ -290,6 +293,10 @@ Object getSetterValue() {
return impl.getSetterValue();
}
+ SqlVariant getInternalVariant() {
+ return impl.getInternalVariant();
+ }
+
/**
* Called by DTV implementation instances to change to a different DTV implementation.
*/
@@ -1070,7 +1077,7 @@ void execute(DTV dtv,
* simply the assignment in the Java runtime). So the only way found is to convert the float to a string and init the double with that
* string
*/
- Double doubleValue = (null == floatValue) ? null : new Double(floatValue.floatValue());
+ Double doubleValue = (null == floatValue) ? null : (double) floatValue;
tdsWriter.writeRPCDouble(name, doubleValue, isOutParam);
}
}
@@ -1436,6 +1443,18 @@ void execute(DTV dtv,
// Write the reader value as a stream of Unicode characters
tdsWriter.writeRPCReaderUnicode(name, readerValue, dtv.getStreamSetterArgs().getLength(), isOutParam, collation);
}
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.microsoft.sqlserver.jdbc.DTVExecuteOp#execute(com.microsoft.sqlserver.jdbc.DTV, microsoft.sql.SqlVariant)
+ */
+ @Override
+ void execute(DTV dtv,
+ SqlVariant sqlVariantValue) throws SQLServerException {
+ tdsWriter.writeRPCSqlVariant(name, sqlVariantValue, isOutParam);
+
+ }
}
/**
@@ -1577,6 +1596,10 @@ final void executeOp(DTVExecuteOp op) throws SQLServerException {
case STRUCT:
unsupportedConversion = true;
break;
+
+ case SQL_VARIANT:
+ op.execute(this, (SqlVariant) null);
+ break;
case UNKNOWN:
default:
@@ -1599,6 +1622,9 @@ final void executeOp(DTVExecuteOp op) throws SQLServerException {
byte[] bArray = Util.asGuidByteArray((UUID) value);
op.execute(this, bArray);
}
+ else if (jdbcType.SQL_VARIANT == jdbcType) {
+ op.execute(this, String.valueOf(value));
+ }
else {
if (null != cryptoMeta) {
// if streaming types check for allowed data length in AE
@@ -1956,6 +1982,8 @@ abstract void skipValue(TypeInfo typeInfo,
boolean isDiscard) throws SQLServerException;
abstract void initFromCompressedNull();
+
+ abstract SqlVariant getInternalVariant();
}
/**
@@ -1969,7 +1997,8 @@ final class AppDTVImpl extends DTVImpl {
private Calendar cal;
private Integer scale;
private boolean forceEncrypt;
-
+ private SqlVariant internalVariant;
+
final void skipValue(TypeInfo typeInfo,
TDSReader tdsReader,
boolean isDiscard) throws SQLServerException {
@@ -2172,8 +2201,8 @@ void execute(DTV dtv,
// Rescale the value if necessary
if (null != bigDecimalValue) {
Integer inScale = dtv.getScale();
- if (null != inScale && inScale.intValue() != bigDecimalValue.scale())
- bigDecimalValue = bigDecimalValue.setScale(inScale.intValue(), BigDecimal.ROUND_DOWN);
+ if (null != inScale && inScale != bigDecimalValue.scale())
+ bigDecimalValue = bigDecimalValue.setScale(inScale, BigDecimal.ROUND_DOWN);
}
dtv.setValue(bigDecimalValue, JavaType.BIGDECIMAL);
@@ -2261,7 +2290,7 @@ void execute(DTV dtv,
// the actual stream length did not match then cancel the request.
if (DataTypes.UNKNOWN_STREAM_LENGTH != readerLength && stringValue.length() != readerLength) {
MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_mismatchedStreamLength"));
- Object[] msgArgs = {Long.valueOf(readerLength), Integer.valueOf(stringValue.length())};
+ Object[] msgArgs = {readerLength, stringValue.length()};
SQLServerException.makeFromDriverError(null, null, form.format(msgArgs), "", true);
}
@@ -2281,6 +2310,17 @@ else if (null != collation
execute(dtv, streamValue);
}
}
+
+ /*
+ * (non-Javadoc)
+ *
+ * @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 setValue(DTV dtv,
@@ -2371,6 +2411,26 @@ Object getValue(DTV dtv,
Object getSetterValue() {
return value;
}
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see com.microsoft.sqlserver.jdbc.DTVImpl#getInternalVariant()
+ */
+ @Override
+ SqlVariant getInternalVariant() {
+ return this.internalVariant;
+ }
+
+ /**
+ * Sets the internal datatype of variant type
+ *
+ * @param type
+ * sql_variant internal type
+ */
+ void setInternalVariant(SqlVariant type) {
+ this.internalVariant = type;
+ }
}
/**
@@ -2398,10 +2458,18 @@ final class TypeInfo {
SSType getSSType() {
return ssType;
}
+
+ void setSSType(SSType ssType) {
+ this.ssType = ssType;
+ }
SSLenType getSSLenType() {
return ssLenType;
}
+
+ void setSSLenType(SSLenType ssLenType){
+ this.ssLenType = ssLenType;
+ }
String getSSTypeName() {
return (SSType.UDT == ssType) ? udtTypeName : ssType.toString();
@@ -2410,14 +2478,25 @@ String getSSTypeName() {
int getMaxLength() {
return maxLength;
}
-
+
+ void setMaxLength(int maxLength) {
+ this.maxLength = maxLength;
+ }
int getPrecision() {
return precision;
}
+
+ void setPrecision(int precision) {
+ this.precision = precision;
+ }
int getDisplaySize() {
return displaySize;
}
+
+ void setDisplaySize(int displaySize){
+ this.displaySize = displaySize;
+ }
int getScale() {
return scale;
@@ -2434,6 +2513,10 @@ void setSQLCollation(SQLCollation collation) {
Charset getCharset() {
return charset;
}
+
+ void setCharset(Charset charset){
+ this.charset = charset;
+ }
boolean isNullable() {
return 0x0001 == (flags & 0x0001);
@@ -2477,6 +2560,10 @@ short getFlagsAsShort() {
void setFlags(Short flags) {
this.flags = flags;
}
+
+ void setScale(int scale){
+ this.scale = scale;
+ }
//TypeInfo Builder enum defines a set of builders used to construct TypeInfo instances
//for the various data types. Each builder builds a TypeInfo instance using a builder Strategy.
@@ -3011,37 +3098,10 @@ public void apply(TypeInfo typeInfo,
*/
public void apply(TypeInfo typeInfo,
TDSReader tdsReader) throws SQLServerException {
- try {
- SQLServerException.makeFromDriverError(tdsReader.getConnection(), null, SQLServerException.getErrString("R_variantNotSupported"),
- null, false);
- }
- finally {
- /*
- * As the driver doesn't know how to process or skip the VARIANT type in TDS token stream, we send an interrupt Signal to server,
- * and skips all the data received while waiting for the interrupt acknowledgment.
- */
- int remainingPackets = 0;
-
- // Skip the current buffered packet
- remainingPackets = tdsReader.availableCurrentPacket();
- tdsReader.skip(remainingPackets);
-
- // send interrupt to server
- tdsReader.getCommand().interrupt(SQLServerException.getErrString("R_variantNotSupported"));
-
- /*
- * Skip all data only if waiting for attention ack and until interrupt acknowledgment is received.
- *
- * Interrupt acknowledgment is a DONE token with the DONE_ATTN(0x0020) bit set.
- */
- while (tdsReader.getCommand().attentionPending() && (TDS.TDS_DONE != tdsReader.peekTokenType())
- && (0 != (tdsReader.peekStatusFlag() & 0x0020))) {
- remainingPackets = tdsReader.availableCurrentPacket();
- tdsReader.skip(remainingPackets);
- }
- tdsReader.getCommand().close();
+ typeInfo.ssLenType = SSLenType.LONGLENTYPE; //Variant type should be LONGLENTYPE length.
+ typeInfo.maxLength = tdsReader.readInt();
+ typeInfo.ssType = SSType.SQL_VARIANT;
}
- }
});
private final TDSType tdsType;
@@ -3312,7 +3372,7 @@ final class ServerDTVImpl extends DTVImpl {
private int valueLength;
private TDSReaderMark valueMark;
private boolean isNull;
-
+ private SqlVariant internalVariant;
/**
* Sets the value of the DTV to an app-specified Java type.
*
@@ -3494,9 +3554,11 @@ private void getValuePrep(TypeInfo typeInfo,
valueLength = tdsReader.readInt();
}
}
- else {
+
+ else if (SSType.SQL_VARIANT == typeInfo.getSSType()) {
valueLength = tdsReader.readInt();
isNull = (0 == valueLength);
+ typeInfo.setSSType(SSType.SQL_VARIANT);
}
break;
}
@@ -3934,7 +3996,26 @@ Object getValue(DTV dtv,
case GUID:
convertedValue = tdsReader.readGUID(valueLength, jdbcType, streamGetterArgs.streamType);
break;
+
+ case SQL_VARIANT:
+ /**
+ * SQL_Variant has the following structure:
+ * 1- basetype: the underlying type
+ * 2- probByte: holds count of property bytes expected for a sql_variant structure
+ * 3- properties: For example VARCHAR type has 5 byte collation and 2 byte max length
+ * 4- dataValue: the data value
+ */
+ int baseType = tdsReader.readUnsignedByte();
+ int cbPropsActual = tdsReader.readUnsignedByte();
+ // don't create new one, if we have already created an internalVariant object. For example, in bulkcopy
+ // when we are reading time column, we update the same internalvarianttype's JDBC to be timestamp
+ if (null == internalVariant) {
+ internalVariant = new SqlVariant(baseType);
+ }
+ convertedValue = readSqlVariant(baseType, cbPropsActual, valueLength, tdsReader, baseSSType, typeInfo, jdbcType, streamGetterArgs,
+ cal);
+ break;
// Unknown SSType should have already been rejected by TypeInfo.setFromTDS()
default:
assert false : "Unexpected SSType " + typeInfo.getSSType();
@@ -3946,6 +4027,270 @@ Object getValue(DTV dtv,
assert isNull || null != convertedValue;
return convertedValue;
}
+
+ SqlVariant getInternalVariant() {
+ return internalVariant;
+ }
+
+ /**
+ * Read the value inside sqlVariant. The reading differs based on what the internal baseType is.
+ *
+ * @return sql_variant value
+ * @since 6.3.0
+ * @throws SQLServerException
+ */
+ private Object readSqlVariant(int intbaseType,
+ int cbPropsActual,
+ int valueLength,
+ TDSReader tdsReader,
+ SSType baseSSType,
+ TypeInfo typeInfo,
+ JDBCType jdbcType,
+ InputStreamGetterArgs streamGetterArgs,
+ Calendar cal) throws SQLServerException {
+ Object convertedValue = null;
+ int lengthConsumed = 2 + cbPropsActual; // We have already read 2bytes for baseType earlier.
+ int expectedValueLength = valueLength - lengthConsumed;
+ SQLCollation collation = null;
+ int precision;
+ int scale;
+ int maxLength;
+ TDSType baseType = TDSType.valueOf(intbaseType);
+ switch (baseType) {
+ case INT8:
+ jdbcType = JDBCType.BIGINT;
+ convertedValue = DDC.convertLongToObject(tdsReader.readLong(), jdbcType, baseSSType, streamGetterArgs.streamType);
+ break;
+
+ case INT4:
+ jdbcType = JDBCType.INTEGER;
+ convertedValue = DDC.convertIntegerToObject(tdsReader.readInt(), valueLength, jdbcType, streamGetterArgs.streamType);
+ break;
+
+ case INT2:
+ jdbcType = JDBCType.SMALLINT;
+ convertedValue = DDC.convertIntegerToObject(tdsReader.readShort(), valueLength, jdbcType, streamGetterArgs.streamType);
+ break;
+
+ case INT1:
+ jdbcType = JDBCType.TINYINT;
+ convertedValue = DDC.convertIntegerToObject(tdsReader.readUnsignedByte(), valueLength, jdbcType, streamGetterArgs.streamType);
+ break;
+
+ case DECIMALN:
+ case NUMERICN:
+ if (TDSType.DECIMALN == baseType)
+ jdbcType = JDBCType.DECIMAL;
+ else if (TDSType.NUMERICN == baseType)
+ jdbcType = JDBCType.NUMERIC;
+ if (cbPropsActual != sqlVariantProbBytes.DECIMALN.getIntValue()) { // Numeric and decimal have the same probbytes value
+ MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidProbbytes"));
+ throw new SQLServerException(form.format(new Object[] {baseType}), null, 0, null);
+ }
+ jdbcType = JDBCType.DECIMAL;
+ precision = tdsReader.readUnsignedByte();
+ scale = tdsReader.readUnsignedByte();
+ typeInfo.setScale(scale); // typeInfo needs to be updated. typeInfo is usually set when reading columnMetaData, but for sql_variant
+ // type the actual columnMetaData is is set when reading the data rows.
+ internalVariant.setPrecision(precision);
+ internalVariant.setScale(scale);
+ convertedValue = tdsReader.readDecimal(expectedValueLength, typeInfo, jdbcType, streamGetterArgs.streamType);
+ break;
+
+ case FLOAT4:
+ jdbcType = JDBCType.REAL;
+ convertedValue = tdsReader.readReal(expectedValueLength, jdbcType, streamGetterArgs.streamType);
+ break;
+
+ case FLOAT8:
+ jdbcType = JDBCType.FLOAT;
+ convertedValue = tdsReader.readFloat(expectedValueLength, jdbcType, streamGetterArgs.streamType);
+ break;
+
+ case MONEY4:
+ jdbcType = JDBCType.SMALLMONEY;
+ typeInfo.setMaxLength(4);
+ precision = Long.toString(Long.MAX_VALUE).length();
+ typeInfo.setPrecision(precision);
+ scale = 4;
+ typeInfo.setDisplaySize(("-" + "." + Integer.toString(Integer.MAX_VALUE)).length());
+ typeInfo.setScale(scale);
+ internalVariant.setPrecision(precision);
+ internalVariant.setScale(scale);
+ convertedValue = tdsReader.readMoney(expectedValueLength, jdbcType, streamGetterArgs.streamType);
+ break;
+
+ case MONEY8:
+ jdbcType = JDBCType.MONEY;
+ typeInfo.setMaxLength(8);
+ precision = Long.toString(Long.MAX_VALUE).length();
+ scale = 4;
+ typeInfo.setPrecision(precision);
+ typeInfo.setDisplaySize(("-" + "." + Integer.toString(Integer.MAX_VALUE)).length());
+ typeInfo.setScale(scale);
+ internalVariant.setPrecision(precision);
+ internalVariant.setScale(scale);
+ convertedValue = tdsReader.readMoney(expectedValueLength, jdbcType, streamGetterArgs.streamType);
+ break;
+
+ case BIT1:
+ case BITN:
+ jdbcType = JDBCType.BIT;
+ switch (expectedValueLength) {
+ case 8:
+ convertedValue = DDC.convertLongToObject(tdsReader.readLong(), jdbcType, baseSSType, streamGetterArgs.streamType);
+ break;
+
+ case 4:
+ convertedValue = DDC.convertIntegerToObject(tdsReader.readInt(), expectedValueLength, jdbcType, streamGetterArgs.streamType);
+ break;
+
+ case 2:
+ convertedValue = DDC.convertIntegerToObject(tdsReader.readShort(), expectedValueLength, jdbcType,
+ streamGetterArgs.streamType);
+ break;
+
+ case 1:
+ convertedValue = DDC.convertIntegerToObject(tdsReader.readUnsignedByte(), expectedValueLength, jdbcType,
+ streamGetterArgs.streamType);
+ break;
+
+ default:
+ assert false : "Unexpected valueLength" + expectedValueLength;
+ break;
+ }
+ break;
+
+ case BIGVARCHAR:
+ case BIGCHAR:
+ if (cbPropsActual != sqlVariantProbBytes.BIGCHAR.getIntValue()) {
+ MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidProbbytes"));
+ throw new SQLServerException(form.format(new Object[] {baseType}), null, 0, null);
+ }
+ if (TDSType.BIGVARCHAR == baseType)
+ jdbcType = JDBCType.VARCHAR;
+ else if (TDSType.BIGCHAR == baseType)
+ jdbcType = JDBCType.CHAR;
+ collation = tdsReader.readCollation();
+ typeInfo.setSQLCollation(collation);
+ typeInfo.setSSLenType(SSLenType.USHORTLENTYPE);
+ maxLength = tdsReader.readUnsignedShort();
+ typeInfo.setMaxLength(maxLength);
+ if (maxLength > DataTypes.SHORT_VARTYPE_MAX_BYTES)
+ tdsReader.throwInvalidTDS();
+ typeInfo.setDisplaySize(maxLength);
+ typeInfo.setPrecision(maxLength);
+ internalVariant.setPrecision(maxLength);
+ internalVariant.setCollation(collation);
+ typeInfo.setCharset(collation.getCharset());
+ convertedValue = DDC.convertStreamToObject(new SimpleInputStream(tdsReader, expectedValueLength, streamGetterArgs, this), typeInfo,
+ jdbcType, streamGetterArgs);
+ break;
+
+ case NCHAR:
+ case NVARCHAR:
+ if (cbPropsActual != sqlVariantProbBytes.NCHAR.getIntValue()) {
+ MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidProbbytes"));
+ throw new SQLServerException(form.format(new Object[] {baseType}), null, 0, null);
+ }
+ if (TDSType.NCHAR == baseType)
+ jdbcType = JDBCType.NCHAR;
+ else if (TDSType.NVARCHAR == baseType)
+ jdbcType = JDBCType.NVARCHAR;
+ collation = tdsReader.readCollation();
+ typeInfo.setSQLCollation(collation);
+ typeInfo.setSSLenType(SSLenType.USHORTLENTYPE);
+ maxLength = tdsReader.readUnsignedShort();
+ if (maxLength > DataTypes.SHORT_VARTYPE_MAX_BYTES || 0 != maxLength % 2)
+ tdsReader.throwInvalidTDS();
+ typeInfo.setDisplaySize(maxLength / 2);
+ typeInfo.setPrecision(maxLength / 2);
+ internalVariant.setPrecision(maxLength / 2);
+ internalVariant.setCollation(collation);
+ typeInfo.setCharset(Encoding.UNICODE.charset());
+ convertedValue = DDC.convertStreamToObject(new SimpleInputStream(tdsReader, expectedValueLength, streamGetterArgs, this), typeInfo,
+ jdbcType, streamGetterArgs);
+ break;
+
+ case DATETIME8:
+ jdbcType = JDBCType.DATETIME;
+ convertedValue = tdsReader.readDateTime(expectedValueLength, cal, jdbcType, streamGetterArgs.streamType);
+ break;
+
+ case DATETIME4:
+ jdbcType = JDBCType.SMALLDATETIME;
+ convertedValue = tdsReader.readDateTime(expectedValueLength, cal, jdbcType, streamGetterArgs.streamType);
+ break;
+
+ case DATEN:
+ jdbcType = JDBCType.DATE;
+ convertedValue = tdsReader.readDate(expectedValueLength, cal, jdbcType);
+ break;
+
+ case TIMEN:
+ if (cbPropsActual != sqlVariantProbBytes.TIMEN.getIntValue()) {
+ MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidProbbytes"));
+ throw new SQLServerException(form.format(new Object[] {baseType}), null, 0, null);
+ }
+ jdbcType = JDBCType.CHAR; // The reason we use char is to return nanoseconds
+ if (internalVariant.isBaseTypeTimeValue()) {
+ jdbcType = JDBCType.TIMESTAMP;
+ }
+ scale = tdsReader.readUnsignedByte();
+ typeInfo.setScale(scale);
+ internalVariant.setScale(scale);
+ convertedValue = tdsReader.readTime(expectedValueLength, typeInfo, cal, jdbcType);
+ break;
+
+ case DATETIME2N:
+ if (cbPropsActual != sqlVariantProbBytes.DATETIME2N.getIntValue()) {
+ MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidProbbytes"));
+ throw new SQLServerException(form.format(new Object[] {baseType}), null, 0, null);
+ }
+ jdbcType = JDBCType.TIMESTAMP;
+ scale = tdsReader.readUnsignedByte();
+ typeInfo.setScale(scale);
+ internalVariant.setScale(scale);
+ convertedValue = tdsReader.readDateTime2(expectedValueLength, typeInfo, cal, jdbcType);
+ break;
+
+ case BIGBINARY: // e.g binary20, binary 512, binary 8000 -> reads as bigbinary
+ case BIGVARBINARY:
+ if (cbPropsActual != sqlVariantProbBytes.BIGBINARY.getIntValue()) {
+ MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidProbbytes"));
+ throw new SQLServerException(form.format(new Object[] {baseType}), null, 0, null);
+ }
+ if (TDSType.BIGBINARY == baseType)
+ jdbcType = JDBCType.BINARY;// LONGVARCHAR;
+ else if (TDSType.BIGVARBINARY == baseType)
+ jdbcType = JDBCType.VARBINARY;
+ maxLength = tdsReader.readUnsignedShort();
+ internalVariant.setMaxLength(maxLength);
+ typeInfo.setMaxLength(maxLength);
+ if (maxLength > DataTypes.SHORT_VARTYPE_MAX_BYTES)
+ tdsReader.throwInvalidTDS();
+ typeInfo.setDisplaySize(2 * maxLength);
+ typeInfo.setPrecision(maxLength);
+ convertedValue = DDC.convertStreamToObject(new SimpleInputStream(tdsReader, expectedValueLength, streamGetterArgs, this), typeInfo,
+ jdbcType, streamGetterArgs);
+ break;
+
+ case GUID:
+ jdbcType = JDBCType.GUID;
+ internalVariant.setBaseType(intbaseType);
+ internalVariant.setBaseJDBCType(jdbcType);
+ typeInfo.setDisplaySize("NNNNNNNN-NNNN-NNNN-NNNN-NNNNNNNNNNNN".length());
+ lengthConsumed = 2 + cbPropsActual;
+ convertedValue = tdsReader.readGUID(expectedValueLength, jdbcType, streamGetterArgs.streamType);
+ break;
+
+ // Unknown SSType should have already been rejected by TypeInfo.setFromTDS()
+ default:
+ assert false : "Unexpected TDSType in Sql-Variant " + baseType;
+ break;
+ }
+ return convertedValue;
+ }
Object getSetterValue() {
// This function is never called, but must be implemented; it's abstract in DTVImpl.
diff --git a/src/main/java/microsoft/sql/Types.java b/src/main/java/microsoft/sql/Types.java
index 81d94801c1..36e820aade 100644
--- a/src/main/java/microsoft/sql/Types.java
+++ b/src/main/java/microsoft/sql/Types.java
@@ -52,4 +52,9 @@ private Types() {
* 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.
+ */
+ public static final int SQL_VARIANT = -156;
}
diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java
index b646d8e450..b164f004dd 100644
--- a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java
+++ b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/AESetup.java
@@ -13,11 +13,11 @@
import java.io.IOException;
import java.sql.DriverManager;
import java.sql.SQLException;
-import java.sql.Statement;
import java.util.Properties;
import javax.xml.bind.DatatypeConverter;
+import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.platform.runner.JUnitPlatform;
import org.junit.runner.RunWith;
@@ -27,71 +27,84 @@
import com.microsoft.sqlserver.jdbc.SQLServerColumnEncryptionKeyStoreProvider;
import com.microsoft.sqlserver.jdbc.SQLServerConnection;
import com.microsoft.sqlserver.jdbc.SQLServerException;
+import com.microsoft.sqlserver.jdbc.SQLServerStatement;
+import com.microsoft.sqlserver.jdbc.SQLServerStatementColumnEncryptionSetting;
import com.microsoft.sqlserver.testframework.AbstractTest;
import com.microsoft.sqlserver.testframework.DBConnection;
import com.microsoft.sqlserver.testframework.Utils;
+import com.microsoft.sqlserver.testframework.util.Util;
+
import static org.junit.jupiter.api.Assertions.fail;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
/**
- * Setup for Always Encrypted test
- * This test will work on Appveyor and Travis-ci as java key store gets created from the .yml scripts. Users on their local machine should create the
- * keystore manually and save the alias name in JavaKeyStore.txt file. For local test purposes, put this in the target/test-classes directory
+ * Setup for Always Encrypted test This test will work on Appveyor and Travis-ci as java key store gets created from the .yml scripts. Users on their
+ * local machine should create the keystore manually and save the alias name in JavaKeyStore.txt file. For local test purposes, put this in the
+ * target/test-classes directory
*
*/
@RunWith(JUnitPlatform.class)
public class AESetup extends AbstractTest {
- static String javaKeyStoreInputFile = "JavaKeyStore.txt";
- static String keyStoreName = "MSSQL_JAVA_KEYSTORE";
- static String jksName = "clientcert.jks";
+ static final String javaKeyStoreInputFile = "JavaKeyStore.txt";
+ static final String keyStoreName = "MSSQL_JAVA_KEYSTORE";
+ static final String jksName = "clientcert.jks";
+ static final String cmkName = "JDBC_CMK";
+ static final String cekName = "JDBC_CEK";
+ static final String secretstrJks = "password";
+ static final String numericTable = "JDBCEncrpytedNumericTable";
+ static final String charTable = "JDBCEncrpytedCharTable";
+ static final String binaryTable = "JDBCEncrpytedBinaryTable";
+ static final String dateTable = "JDBCEncrpytedDateTable";
+ static final String uid = "171fbe25-4331-4765-a838-b2e3eea3e7ea";
+
static String filePath = null;
static String thumbprint = null;
static SQLServerConnection con = null;
- static Statement stmt = null;
- static String cmkName = "JDBC_CMK";
- static String cekName = "JDBC_CEK";
+ static SQLServerStatement stmt = null;
static String keyPath = null;
static String javaKeyAliases = null;
static String OS = System.getProperty("os.name").toLowerCase();
static SQLServerColumnEncryptionKeyStoreProvider storeProvider = null;
- static String secretstrJks = "password";
- static String numericTable = "numericTable";
+ static SQLServerStatementColumnEncryptionSetting stmtColEncSetting = null;
/**
* Create connection, statement and generate path of resource file
- * @throws Exception
- * @throws TestAbortedException
+ *
+ * @throws Exception
+ * @throws TestAbortedException
*/
@BeforeAll
static void setUpConnection() throws TestAbortedException, Exception {
assumeTrue(13 <= new DBConnection(connectionString).getServerVersion(),
"Aborting test case as SQL Server version is not compatible with Always encrypted ");
+ String AETestConenctionString = connectionString + ";sendTimeAsDateTime=false";
+
readFromFile(javaKeyStoreInputFile, "Alias name");
- con = (SQLServerConnection) DriverManager.getConnection(connectionString);
- stmt = con.createStatement();
- Utils.dropTableIfExists(numericTable, stmt);
+ con = (SQLServerConnection) DriverManager.getConnection(AETestConenctionString);
+ stmt = (SQLServerStatement) con.createStatement();
dropCEK();
dropCMK();
con.close();
-
keyPath = Utils.getCurrentClassPath() + jksName;
storeProvider = new SQLServerColumnEncryptionJavaKeyStoreProvider(keyPath, secretstrJks.toCharArray());
+ stmtColEncSetting = SQLServerStatementColumnEncryptionSetting.Enabled;
Properties info = new Properties();
info.setProperty("ColumnEncryptionSetting", "Enabled");
info.setProperty("keyStoreAuthentication", "JavaKeyStorePassword");
info.setProperty("keyStoreLocation", keyPath);
info.setProperty("keyStoreSecret", secretstrJks);
- con = (SQLServerConnection) DriverManager.getConnection(connectionString, info);
- stmt = con.createStatement();
+ con = (SQLServerConnection) DriverManager.getConnection(AETestConenctionString, info);
+ stmt = (SQLServerStatement) con.createStatement();
createCMK(keyStoreName, javaKeyAliases);
+ createCEK(storeProvider);
}
/**
- * Read the alias from file which is created during creating jks
- * If the jks and alias name in JavaKeyStore.txt does not exists, will not run!
+ * Read the alias from file which is created during creating jks If the jks and alias name in JavaKeyStore.txt does not exists, will not run!
+ *
* @param inputFile
* @param lookupValue
* @throws IOException
@@ -109,7 +122,7 @@ private static void readFromFile(String inputFile,
while ((readLine = buffer.readLine()) != null) {
if (readLine.trim().contains(lookupValue)) {
- linecontents = readLine.split(" ");
+ linecontents = readLine.split(" ");
javaKeyAliases = linecontents[2];
break;
}
@@ -117,10 +130,10 @@ private static void readFromFile(String inputFile,
}
catch (IOException e) {
- fail(e.toString());;
+ fail(e.toString());
}
- finally{
- if (null != buffer){
+ finally {
+ if (null != buffer) {
buffer.close();
}
}
@@ -128,17 +141,265 @@ private static void readFromFile(String inputFile,
}
/**
- * Creating numeric table
+ * Create encrypted table for Binary
+ *
+ * @throws SQLException
+ */
+ static void createBinaryTable() throws SQLException {
+ String sql = "create table " + binaryTable + " (" + "PlainBinary binary(20) null,"
+ + "RandomizedBinary binary(20) ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicBinary binary(20) ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainVarbinary varbinary(50) null,"
+ + "RandomizedVarbinary varbinary(50) ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicVarbinary varbinary(50) ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainVarbinaryMax varbinary(max) null,"
+ + "RandomizedVarbinaryMax varbinary(max) ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicVarbinaryMax varbinary(max) ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainBinary512 binary(512) null,"
+ + "RandomizedBinary512 binary(512) ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicBinary512 binary(512) ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainBinary8000 varbinary(8000) null,"
+ + "RandomizedBinary8000 varbinary(8000) ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicBinary8000 varbinary(8000) ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + ");";
+
+ stmt.execute(sql);
+ }
+
+ /**
+ * Create encrypted table for Char
+ *
+ * @throws SQLException
+ */
+ static void createCharTable() throws SQLException {
+ String sql = "create table " + charTable + " (" + "PlainChar char(20) null,"
+ + "RandomizedChar char(20) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicChar char(20) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainVarchar varchar(50) null,"
+ + "RandomizedVarchar varchar(50) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicVarchar varchar(50) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainVarcharMax varchar(max) null,"
+ + "RandomizedVarcharMax varchar(max) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicVarcharMax varchar(max) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainNchar nchar(30) null,"
+ + "RandomizedNchar nchar(30) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicNchar nchar(30) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainNvarchar nvarchar(60) null,"
+ + "RandomizedNvarchar nvarchar(60) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicNvarchar nvarchar(60) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainNvarcharMax nvarchar(max) null,"
+ + "RandomizedNvarcharMax nvarchar(max) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicNvarcharMax nvarchar(max) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainUniqueidentifier uniqueidentifier null,"
+ + "RandomizedUniqueidentifier uniqueidentifier ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicUniqueidentifier uniqueidentifier ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainVarchar8000 varchar(8000) null,"
+ + "RandomizedVarchar8000 varchar(8000) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicVarchar8000 varchar(8000) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainNvarchar4000 nvarchar(4000) null,"
+ + "RandomizedNvarchar4000 nvarchar(4000) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicNvarchar4000 nvarchar(4000) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + ");";
+
+ stmt.execute(sql);
+ }
+
+ /**
+ * Create encrypted table for Date
+ *
+ * @throws SQLException
+ */
+ static void createDateTable() throws SQLException {
+ String sql = "create table " + dateTable + " (" + "PlainDate date null,"
+ + "RandomizedDate date ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicDate date ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainDatetime2Default datetime2 null,"
+ + "RandomizedDatetime2Default datetime2 ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicDatetime2Default datetime2 ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainDatetimeoffsetDefault datetimeoffset null,"
+ + "RandomizedDatetimeoffsetDefault datetimeoffset ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicDatetimeoffsetDefault datetimeoffset ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainTimeDefault time null,"
+ + "RandomizedTimeDefault time ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicTimeDefault time ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainDatetime datetime null,"
+ + "RandomizedDatetime datetime ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicDatetime datetime ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainSmalldatetime smalldatetime null,"
+ + "RandomizedSmalldatetime smalldatetime ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicSmalldatetime smalldatetime ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + ");";
+
+ stmt.execute(sql);
+ }
+
+ /**
+ * Create encrypted table for Numeric
+ *
+ * @throws SQLException
*/
- static void createNumericTable() {
- String sql = "create table " + numericTable + " (" + "PlainSmallint smallint null,"
+ static void createNumericTable() throws SQLException {
+ String sql = "create table " + numericTable + " (" + "PlainBit bit null,"
+ + "RandomizedBit bit ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicBit bit ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainTinyint tinyint null,"
+ + "RandomizedTinyint tinyint ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicTinyint tinyint ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainSmallint smallint null,"
+ "RandomizedSmallint smallint ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ cekName + ") NULL,"
+ "DeterministicSmallint smallint ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
- + cekName + ") NULL" + ");";
+ + cekName + ") NULL,"
+
+ + "PlainInt int null,"
+ + "RandomizedInt int ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicInt int ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainBigint bigint null,"
+ + "RandomizedBigint bigint ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicBigint bigint ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainFloatDefault float null,"
+ + "RandomizedFloatDefault float ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicFloatDefault float ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainFloat float(30) null,"
+ + "RandomizedFloat float(30) ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicFloat float(30) ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainReal real null,"
+ + "RandomizedReal real ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicReal real ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainDecimalDefault decimal null,"
+ + "RandomizedDecimalDefault decimal ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicDecimalDefault decimal ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainDecimal decimal(10,5) null,"
+ + "RandomizedDecimal decimal(10,5) ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicDecimal decimal(10,5) ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainNumericDefault numeric null,"
+ + "RandomizedNumericDefault numeric ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicNumericDefault numeric ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainNumeric numeric(8,2) null,"
+ + "RandomizedNumeric numeric(8,2) ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicNumeric numeric(8,2) ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainSmallMoney smallmoney null,"
+ + "RandomizedSmallMoney smallmoney ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicSmallMoney smallmoney ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainMoney money null,"
+ + "RandomizedMoney money ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicMoney money ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainDecimal2 decimal(28,4) null,"
+ + "RandomizedDecimal2 decimal(28,4) ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicDecimal2 decimal(28,4) ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + "PlainNumeric2 numeric(28,4) null,"
+ + "RandomizedNumeric2 numeric(28,4) ENCRYPTED WITH (ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+ + "DeterministicNumeric2 numeric(28,4) ENCRYPTED WITH (ENCRYPTION_TYPE = DETERMINISTIC, ALGORITHM = 'AEAD_AES_256_CBC_HMAC_SHA_256', COLUMN_ENCRYPTION_KEY = "
+ + cekName + ") NULL,"
+
+ + ");";
try {
stmt.execute(sql);
+ stmt.execute("DBCC FREEPROCCACHE");
}
catch (SQLException e) {
fail(e.toString());
@@ -147,6 +408,7 @@ static void createNumericTable() {
/**
* Create column master key
+ *
* @param keyStoreName
* @param keyPath
* @throws SQLException
@@ -160,6 +422,7 @@ private static void createCMK(String keyStoreName,
/**
* Create column encryption key
+ *
* @param storeProvider
* @param certStore
* @throws SQLException
@@ -170,12 +433,25 @@ static void createCEK(SQLServerColumnEncryptionKeyStoreProvider storeProvider) t
String cekSql = null;
byte[] key = storeProvider.encryptColumnEncryptionKey(javaKeyAliases, "RSA_OAEP", valuesDefault);
cekSql = "CREATE COLUMN ENCRYPTION KEY " + cekName + " WITH VALUES " + "(COLUMN_MASTER_KEY = " + cmkName
- + ", ALGORITHM = 'RSA_OAEP', ENCRYPTED_VALUE = 0x" + DatatypeConverter.printHexBinary(key) + ")" + ";";
+ + ", ALGORITHM = 'RSA_OAEP', ENCRYPTED_VALUE = 0x" + DatatypeConverter.printHexBinary(key) + ")" + ";";
stmt.execute(cekSql);
}
+ /**
+ * Drop all tables that are in use by AE
+ *
+ * @throws SQLException
+ */
+ static void dropTables() throws SQLException {
+ Utils.dropTableIfExists(numericTable, stmt);
+ Utils.dropTableIfExists(charTable, stmt);
+ Utils.dropTableIfExists(binaryTable, stmt);
+ Utils.dropTableIfExists(dateTable, stmt);
+ }
+
/**
* Dropping column encryption key
+ *
* @throws SQLServerException
* @throws SQLException
*/
@@ -187,6 +463,7 @@ static void dropCEK() throws SQLServerException, SQLException {
/**
* Dropping column master key
+ *
* @throws SQLServerException
* @throws SQLException
*/
diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/JDBCEncryptionDecryptionTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/JDBCEncryptionDecryptionTest.java
index ad3729d7af..2f647ef37e 100644
--- a/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/JDBCEncryptionDecryptionTest.java
+++ b/src/test/java/com/microsoft/sqlserver/jdbc/AlwaysEncrypted/JDBCEncryptionDecryptionTest.java
@@ -7,14 +7,21 @@
*/
package com.microsoft.sqlserver.jdbc.AlwaysEncrypted;
-import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+import java.math.BigDecimal;
+import java.sql.Date;
+import java.sql.JDBCType;
import java.sql.ResultSet;
import java.sql.SQLException;
+import java.sql.Statement;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.LinkedList;
import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.platform.runner.JUnitPlatform;
import org.junit.runner.RunWith;
@@ -22,9 +29,12 @@
import com.microsoft.sqlserver.jdbc.SQLServerException;
import com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement;
-import com.microsoft.sqlserver.jdbc.SQLServerStatementColumnEncryptionSetting;
-import com.microsoft.sqlserver.testframework.DBConnection;
-import com.microsoft.sqlserver.testframework.Utils;
+import com.microsoft.sqlserver.jdbc.SQLServerResultSet;
+import com.microsoft.sqlserver.jdbc.SQLServerStatement;
+import com.microsoft.sqlserver.testframework.util.RandomData;
+import com.microsoft.sqlserver.testframework.util.Util;
+
+import microsoft.sql.DateTimeOffset;
/**
* Tests Decryption and encryption of values
@@ -32,30 +42,482 @@
*/
@RunWith(JUnitPlatform.class)
public class JDBCEncryptionDecryptionTest extends AESetup {
- private static SQLServerPreparedStatement pstmt = null;
- String[] values = {"10"};
+ private SQLServerPreparedStatement pstmt = null;
+
+ private boolean nullable = false;
+ private String[] numericValues = null;
+ private String[] numericValues2 = null;
+ private String[] numericValuesNull = null;
+ private String[] numericValuesNull2 = null;
+ private String[] charValues = null;
+
+ private LinkedList byteValuesSetObject = null;
+ private LinkedList byteValuesNull = null;
+
+ private LinkedList