From 9bc117cf89957401d4dd696b9341949945f252d6 Mon Sep 17 00:00:00 2001 From: lilgreenbird Date: Wed, 13 Nov 2024 12:34:03 -0800 Subject: [PATCH 01/14] add props --- .../sqlserver/jdbc/ISQLServerDataSource.java | 38 +++++++++++- .../sqlserver/jdbc/SQLServerConnection.java | 55 +++++++++++++--- .../sqlserver/jdbc/SQLServerDataSource.java | 34 +++++++--- .../sqlserver/jdbc/SQLServerDriver.java | 62 ++++++++++++++++--- .../sqlserver/jdbc/SQLServerResource.java | 2 + 5 files changed, 165 insertions(+), 26 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerDataSource.java b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerDataSource.java index 66fc33744..ecdfcf5bb 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerDataSource.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerDataSource.java @@ -1346,8 +1346,8 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * @return cacheBulkCopyMetadata boolean value */ boolean getcacheBulkCopyMetadata(); - - /** + + /** * Returns value of 'retryExec' from Connection String. * * @param retryExec @@ -1385,4 +1385,38 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * @return useFlexibleCallableStatements */ boolean getUseFlexibleCallableStatements(); + + /** + * Returns value of 'quotedIdentifier' from Connection String. + * + * @return true + * if quotedIdentifier is set to true, false otherwise + */ + String getQuotedIdentifier(); + + /** + * Sets the value for 'quotedIdentifier' property + * + * @param quotedIdentifier + * boolean value + * + */ + void setQuotedIdentifier(String quotedIdentifier); + + /** + * Returns value of 'concatNullYieldsNull' from Connection String. + * + * @return true + * if concatNullYieldsNull is set to true, false otherwise + */ + String getConcatNullYieldsNull(); + + /** + * Sets the value for 'concatNullYieldsNull' property + * + * @param concatNullYieldsNull + * boolean value + * + */ + void setConcatNullYieldsNull(String concatNullYieldsNull); } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java index 5d01955f2..ff3bca1d6 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java @@ -3269,6 +3269,38 @@ else if (0 == requestedPacketSize) } } + // check QUOTED_IDENTIFIER property + String quotedIdentifierProperty = SQLServerDriverStringProperty.QUOTED_IDENTIFIER.toString(); + String quotedIdentiferValue = activeConnectionProperties.getProperty(quotedIdentifierProperty); + if (null == quotedIdentiferValue) { + quotedIdentiferValue = SQLServerDriverStringProperty.QUOTED_IDENTIFIER.getDefaultValue(); + activeConnectionProperties.setProperty(quotedIdentifierProperty, quotedIdentiferValue); + } + String quotedIdentifierOption = OnOffOption.valueOfString(quotedIdentiferValue).toString(); + if (quotedIdentifierOption.compareToIgnoreCase(OnOffOption.OFF.toString()) == 0) { + connectionCommand("SET QUOTED_IDENTIFIER OFF", "quotedIdentifier"); + } else if (quotedIdentifierOption.compareToIgnoreCase(OnOffOption.ON.toString()) == 0) { + connectionCommand("SET QUOTED_IDENTIFIER ON", "quotedIdentifier"); + + } + + // check CONCAT_NULL_YIELDS_NULL property + String concatNullYieldsProperty = SQLServerDriverStringProperty.CONCAT_NULL_YIELDS_NULL.toString(); + String concatNullYieldsValue = activeConnectionProperties.getProperty(concatNullYieldsProperty); + if (null == concatNullYieldsValue) { + quotedIdentiferValue = SQLServerDriverStringProperty.CONCAT_NULL_YIELDS_NULL.getDefaultValue(); + activeConnectionProperties.setProperty(concatNullYieldsProperty, concatNullYieldsValue); + } + String concatNullYieldsOption = OnOffOption.valueOfString(concatNullYieldsValue).toString(); + + if (concatNullYieldsOption.compareToIgnoreCase(OnOffOption.OFF.toString()) == 0) { + connectionCommand("SET CONCAT_NULL_YIELDS_NULL OFF", "concatNullYields"); + + } else if (concatNullYieldsOption.compareToIgnoreCase(OnOffOption.ON.toString()) == 0) { + connectionCommand("SET CONCAT_NULL_YIELDS_NULL ON", "concatNullYields"); + + } + state = State.OPENED; // Socket timeout is bounded by loginTimeout during the login phase. @@ -3278,18 +3310,21 @@ else if (0 == requestedPacketSize) if (connectionlogger.isLoggable(Level.FINER)) { connectionlogger.finer(toString() + " End of connect"); } - } catch (SocketException e) { - throw new SQLServerException(e.getMessage(), null); - } finally { - // once we exit the connect function, the connection can be only in one of two - // states, Opened or Closed(if an exception occurred) - if (!state.equals(State.OPENED) && !state.equals(State.CLOSED)) { - this.close(); - } + }catch( - activeConnectionProperties.remove(SQLServerDriverStringProperty.TRUST_STORE_PASSWORD.toString()); + SocketException e) + { + throw new SQLServerException(e.getMessage(), null); + }finally + { + // once we exit the connect function, the connection can be only in one of two + // states, Opened or Closed(if an exception occurred) + if (!state.equals(State.OPENED) && !state.equals(State.CLOSED)) { + this.close(); } - return this; + + activeConnectionProperties.remove(SQLServerDriverStringProperty.TRUST_STORE_PASSWORD.toString()); + }return this; } // log open connection failures diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java index 6136cffa0..bfd7a97ca 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java @@ -948,17 +948,15 @@ public boolean getEnablePrepareOnFirstPreparedStatementCall() { @Override public void setcacheBulkCopyMetadata(boolean cacheBulkCopyMetadata) { - setBooleanProperty(connectionProps, - SQLServerDriverBooleanProperty.ENABLE_BULK_COPY_CACHE.toString(), + setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.ENABLE_BULK_COPY_CACHE.toString(), cacheBulkCopyMetadata); } @Override public boolean getcacheBulkCopyMetadata() { - boolean defaultValue = SQLServerDriverBooleanProperty.ENABLE_BULK_COPY_CACHE - .getDefaultValue(); - return getBooleanProperty(connectionProps, - SQLServerDriverBooleanProperty.ENABLE_BULK_COPY_CACHE.toString(), defaultValue); + boolean defaultValue = SQLServerDriverBooleanProperty.ENABLE_BULK_COPY_CACHE.getDefaultValue(); + return getBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.ENABLE_BULK_COPY_CACHE.toString(), + defaultValue); } @Override @@ -1302,7 +1300,6 @@ public int getMsiTokenCacheTtl() { @Override public void setUseFlexibleCallableStatements(boolean enable) {} - /** * useFlexibleCallableStatements is temporarily removed. * This method is a no-op for backwards compatibility only. @@ -1393,6 +1390,29 @@ public String getRetryExec() { return getStringProperty(connectionProps, SQLServerDriverStringProperty.RETRY_EXEC.toString(), null); } + @Override + public String getQuotedIdentifier() { + return getStringProperty(connectionProps, SQLServerDriverStringProperty.QUOTED_IDENTIFIER.toString(), + SQLServerDriverStringProperty.QUOTED_IDENTIFIER.getDefaultValue()); + } + + @Override + public void setQuotedIdentifier(String quotedIdentifer) { + setStringProperty(connectionProps, SQLServerDriverStringProperty.QUOTED_IDENTIFIER.toString(), quotedIdentifer); + } + + @Override + public String getConcatNullYieldsNull() { + return getStringProperty(connectionProps, SQLServerDriverStringProperty.CONCAT_NULL_YIELDS_NULL.toString(), + SQLServerDriverStringProperty.CONCAT_NULL_YIELDS_NULL.getDefaultValue()); + } + + @Override + public void setConcatNullYieldsNull(String concatNullYieldNull) { + setStringProperty(connectionProps, SQLServerDriverStringProperty.CONCAT_NULL_YIELDS_NULL.toString(), + concatNullYieldNull); + } + /** * Sets a property string value. * diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java index 1c9abc000..aa3e165be 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java @@ -611,7 +611,9 @@ enum SQLServerDriverStringProperty { SERVER_CERTIFICATE("serverCertificate", ""), DATETIME_DATATYPE("datetimeParameterType", DatetimeType.DATETIME2.toString()), ACCESS_TOKEN_CALLBACK_CLASS("accessTokenCallbackClass", ""), - RETRY_EXEC("retryExec", ""); + RETRY_EXEC("retryExec", ""), + QUOTED_IDENTIFIER("quotedIdentifer", OnOffOption.OFF.toString()), + CONCAT_NULL_YIELDS_NULL("concatNullYieldsNull", OnOffOption.OFF.toString()); private final String name; private final String defaultValue; @@ -720,6 +722,47 @@ public String toString() { } +enum OnOffOption { + ON("ON"), + OFF("OFF"); + + private final String option; + + private OnOffOption(String option) { + this.option = option; + } + + @Override + public String toString() { + return option; + } + + static OnOffOption valueOfString(String value) throws SQLServerException { + OnOffOption option = null; + + if (value.toLowerCase(Locale.US).equalsIgnoreCase(OnOffOption.ON.toString())) { + option = OnOffOption.ON; + } else if (value.toLowerCase(Locale.US).equalsIgnoreCase(OnOffOption.OFF.toString())) { + option = OnOffOption.OFF; + } else { + MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidConnectionSetting")); + Object[] msgArgs = {"OnOffOption", value}; + throw new SQLServerException(form.format(msgArgs), null); + } + return option; + } + + static boolean isValidOnOffOption(String option) { + for (OnOffOption t : OnOffOption.values()) { + if (option.equalsIgnoreCase(t.toString())) { + return true; + } + } + return false; + } +} + + /** * Provides methods to connect to a SQL Server database and to obtain information about the JDBC driver. */ @@ -774,8 +817,8 @@ public final class SQLServerDriver implements java.sql.Driver { Boolean.toString(SQLServerDriverBooleanProperty.INTEGRATED_SECURITY.getDefaultValue()), false, TRUE_FALSE), new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.USE_DEFAULT_GSS_CREDENTIAL.toString(), - Boolean.toString(SQLServerDriverBooleanProperty.USE_DEFAULT_GSS_CREDENTIAL.getDefaultValue()), false, - TRUE_FALSE), + Boolean.toString(SQLServerDriverBooleanProperty.USE_DEFAULT_GSS_CREDENTIAL.getDefaultValue()), + false, TRUE_FALSE), new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.KEY_STORE_AUTHENTICATION.toString(), SQLServerDriverStringProperty.KEY_STORE_AUTHENTICATION.getDefaultValue(), false, new String[] {KeyStoreAuthentication.JAVA_KEYSTORE_PASSWORD.toString()}), @@ -919,8 +962,8 @@ public final class SQLServerDriver implements java.sql.Driver { Boolean.toString(SQLServerDriverBooleanProperty.USE_BULK_COPY_FOR_BATCH_INSERT.getDefaultValue()), false, TRUE_FALSE), new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.ENABLE_BULK_COPY_CACHE.toString(), - Boolean.toString(SQLServerDriverBooleanProperty.ENABLE_BULK_COPY_CACHE.getDefaultValue()), - false, TRUE_FALSE), + Boolean.toString(SQLServerDriverBooleanProperty.ENABLE_BULK_COPY_CACHE.getDefaultValue()), false, + TRUE_FALSE), new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.MSI_CLIENT_ID.toString(), SQLServerDriverStringProperty.MSI_CLIENT_ID.getDefaultValue(), false, null), new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.KEY_VAULT_PROVIDER_CLIENT_ID.toString(), @@ -954,8 +997,13 @@ public final class SQLServerDriver implements java.sql.Driver { new SQLServerDriverPropertyInfo(SQLServerDriverIntProperty.CONNECT_RETRY_COUNT.toString(), Integer.toString(SQLServerDriverIntProperty.CONNECT_RETRY_COUNT.getDefaultValue()), false, null), new SQLServerDriverPropertyInfo(SQLServerDriverIntProperty.CONNECT_RETRY_INTERVAL.toString(), - Integer.toString(SQLServerDriverIntProperty.CONNECT_RETRY_INTERVAL.getDefaultValue()), false, - null),}; + Integer.toString(SQLServerDriverIntProperty.CONNECT_RETRY_INTERVAL.getDefaultValue()), false, null), + new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.QUOTED_IDENTIFIER.toString(), + SQLServerDriverStringProperty.QUOTED_IDENTIFIER.getDefaultValue(), false, + new String[] {OnOffOption.OFF.toString(), OnOffOption.OFF.toString()}), + new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.CONCAT_NULL_YIELDS_NULL.toString(), + SQLServerDriverStringProperty.CONCAT_NULL_YIELDS_NULL.getDefaultValue(), false, + new String[] {OnOffOption.OFF.toString(), OnOffOption.OFF.toString()}),}; /** * Properties that can only be set by using Properties. Cannot set in connection string diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java index 55a5a5fc0..4f54e6f8c 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java @@ -244,6 +244,8 @@ protected Object[][] getContents() { {"R_AADSecurePrincipalSecretPropertyDescription", "A Secret defined for a registered application which has been granted permission to the database connected."}, {"R_accessTokenCallbackClassPropertyDescription", "The class to instantiate as the SQLServerAccessTokenCallback for acquiring tokens."}, {"R_accessTokenCallbackPropertyDescription", "A SQLServerAccessTokenCallback object which is used to call a callback method to return an access token."}, + {"R_setQuotedIdentifierPropertyDescription", "Indiates whether setQuotedIdentifier property is set."}, + {"setConcatNullYieldsNull", "Indiates whether setConcatNullYieldsNull property is set."}, {"R_noParserSupport", "An error occurred while instantiating the required parser. Error: \"{0}\""}, {"R_writeOnlyXML", "Cannot read from this SQLXML instance. This instance is for writing data only."}, {"R_dataHasBeenReadXML", "Cannot read from this SQLXML instance. The data has already been read."}, From a93cfae1660d4ffb24ab11db271545ccf6a056bd Mon Sep 17 00:00:00 2001 From: lilgreenbird Date: Wed, 13 Nov 2024 15:59:55 -0800 Subject: [PATCH 02/14] add test --- .../sqlserver/jdbc/SQLServerConnection.java | 60 +++++++++---------- .../sqlserver/jdbc/SQLServerDataSource.java | 4 +- .../sqlserver/jdbc/SQLServerDriver.java | 2 +- .../sqlserver/jdbc/SQLServerResource.java | 4 +- .../jdbc/SQLServerConnectionTest.java | 6 ++ 5 files changed, 39 insertions(+), 37 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java index ff3bca1d6..6427e254e 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java @@ -3271,34 +3271,31 @@ else if (0 == requestedPacketSize) // check QUOTED_IDENTIFIER property String quotedIdentifierProperty = SQLServerDriverStringProperty.QUOTED_IDENTIFIER.toString(); - String quotedIdentiferValue = activeConnectionProperties.getProperty(quotedIdentifierProperty); - if (null == quotedIdentiferValue) { - quotedIdentiferValue = SQLServerDriverStringProperty.QUOTED_IDENTIFIER.getDefaultValue(); - activeConnectionProperties.setProperty(quotedIdentifierProperty, quotedIdentiferValue); + String quotedIdentifierValue = activeConnectionProperties.getProperty(quotedIdentifierProperty); + if (null == quotedIdentifierValue) { + quotedIdentifierValue = SQLServerDriverStringProperty.QUOTED_IDENTIFIER.getDefaultValue(); + activeConnectionProperties.setProperty(quotedIdentifierProperty, quotedIdentifierValue); } - String quotedIdentifierOption = OnOffOption.valueOfString(quotedIdentiferValue).toString(); + String quotedIdentifierOption = OnOffOption.valueOfString(quotedIdentifierValue).toString(); if (quotedIdentifierOption.compareToIgnoreCase(OnOffOption.OFF.toString()) == 0) { - connectionCommand("SET QUOTED_IDENTIFIER OFF", "quotedIdentifier"); + connectionCommand("SET QUOTED_IDENTIFIER OFF", "quotedIdentifier"); } else if (quotedIdentifierOption.compareToIgnoreCase(OnOffOption.ON.toString()) == 0) { connectionCommand("SET QUOTED_IDENTIFIER ON", "quotedIdentifier"); - } // check CONCAT_NULL_YIELDS_NULL property - String concatNullYieldsProperty = SQLServerDriverStringProperty.CONCAT_NULL_YIELDS_NULL.toString(); - String concatNullYieldsValue = activeConnectionProperties.getProperty(concatNullYieldsProperty); - if (null == concatNullYieldsValue) { - quotedIdentiferValue = SQLServerDriverStringProperty.CONCAT_NULL_YIELDS_NULL.getDefaultValue(); - activeConnectionProperties.setProperty(concatNullYieldsProperty, concatNullYieldsValue); + String concatNullYieldsNullProperty = SQLServerDriverStringProperty.CONCAT_NULL_YIELDS_NULL.toString(); + String concatNullYieldsNullValue = activeConnectionProperties.getProperty(concatNullYieldsNullProperty); + if (null == concatNullYieldsNullValue) { + concatNullYieldsNullValue = SQLServerDriverStringProperty.CONCAT_NULL_YIELDS_NULL.getDefaultValue(); + activeConnectionProperties.setProperty(concatNullYieldsNullProperty, concatNullYieldsNullValue); } - String concatNullYieldsOption = OnOffOption.valueOfString(concatNullYieldsValue).toString(); - - if (concatNullYieldsOption.compareToIgnoreCase(OnOffOption.OFF.toString()) == 0) { - connectionCommand("SET CONCAT_NULL_YIELDS_NULL OFF", "concatNullYields"); - - } else if (concatNullYieldsOption.compareToIgnoreCase(OnOffOption.ON.toString()) == 0) { - connectionCommand("SET CONCAT_NULL_YIELDS_NULL ON", "concatNullYields"); + String concatNullYieldsNullOption = OnOffOption.valueOfString(concatNullYieldsNullValue).toString(); + if (concatNullYieldsNullOption.compareToIgnoreCase(OnOffOption.OFF.toString()) == 0) { + connectionCommand("SET CONCAT_NULL_YIELDS_NULL OFF", "concatNullYieldsNull"); + } else if (concatNullYieldsNullOption.compareToIgnoreCase(OnOffOption.ON.toString()) == 0) { + connectionCommand("SET CONCAT_NULL_YIELDS_NULL ON", "concatNullYieldsNull"); } state = State.OPENED; @@ -3310,21 +3307,20 @@ else if (0 == requestedPacketSize) if (connectionlogger.isLoggable(Level.FINER)) { connectionlogger.finer(toString() + " End of connect"); } - }catch( + } catch ( - SocketException e) - { - throw new SQLServerException(e.getMessage(), null); - }finally - { - // once we exit the connect function, the connection can be only in one of two - // states, Opened or Closed(if an exception occurred) - if (!state.equals(State.OPENED) && !state.equals(State.CLOSED)) { - this.close(); - } + SocketException e) { + throw new SQLServerException(e.getMessage(), null); + } finally { + // once we exit the connect function, the connection can be only in one of two + // states, Opened or Closed(if an exception occurred) + if (!state.equals(State.OPENED) && !state.equals(State.CLOSED)) { + this.close(); + } - activeConnectionProperties.remove(SQLServerDriverStringProperty.TRUST_STORE_PASSWORD.toString()); - }return this; + activeConnectionProperties.remove(SQLServerDriverStringProperty.TRUST_STORE_PASSWORD.toString()); + } + return this; } // log open connection failures diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java index bfd7a97ca..f2683bba0 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java @@ -1397,8 +1397,8 @@ public String getQuotedIdentifier() { } @Override - public void setQuotedIdentifier(String quotedIdentifer) { - setStringProperty(connectionProps, SQLServerDriverStringProperty.QUOTED_IDENTIFIER.toString(), quotedIdentifer); + public void setQuotedIdentifier(String quotedIdentifier) { + setStringProperty(connectionProps, SQLServerDriverStringProperty.QUOTED_IDENTIFIER.toString(), quotedIdentifier); } @Override diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java index aa3e165be..06f05bc0d 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java @@ -612,7 +612,7 @@ enum SQLServerDriverStringProperty { DATETIME_DATATYPE("datetimeParameterType", DatetimeType.DATETIME2.toString()), ACCESS_TOKEN_CALLBACK_CLASS("accessTokenCallbackClass", ""), RETRY_EXEC("retryExec", ""), - QUOTED_IDENTIFIER("quotedIdentifer", OnOffOption.OFF.toString()), + QUOTED_IDENTIFIER("quotedIdentifier", OnOffOption.OFF.toString()), CONCAT_NULL_YIELDS_NULL("concatNullYieldsNull", OnOffOption.OFF.toString()); private final String name; diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java index 4f54e6f8c..8289cb069 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java @@ -244,8 +244,8 @@ protected Object[][] getContents() { {"R_AADSecurePrincipalSecretPropertyDescription", "A Secret defined for a registered application which has been granted permission to the database connected."}, {"R_accessTokenCallbackClassPropertyDescription", "The class to instantiate as the SQLServerAccessTokenCallback for acquiring tokens."}, {"R_accessTokenCallbackPropertyDescription", "A SQLServerAccessTokenCallback object which is used to call a callback method to return an access token."}, - {"R_setQuotedIdentifierPropertyDescription", "Indiates whether setQuotedIdentifier property is set."}, - {"setConcatNullYieldsNull", "Indiates whether setConcatNullYieldsNull property is set."}, + {"R_quotedIdentifierPropertyDescription", "Indicates whether quotedIdentifier property is set."}, + {"R_concatNullYieldsNullPropertyDescription", "Indicates whether concatNullYieldsNull property is set."}, {"R_noParserSupport", "An error occurred while instantiating the required parser. Error: \"{0}\""}, {"R_writeOnlyXML", "Cannot read from this SQLXML instance. This instance is for writing data only."}, {"R_dataHasBeenReadXML", "Cannot read from this SQLXML instance. The data has already been read."}, diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionTest.java index d4a2ebe6a..d66069703 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionTest.java @@ -319,6 +319,12 @@ public void testDataSource() throws SQLServerException { ds.setKeyStorePrincipalId(stringPropValue); assertTrue(ds.getKeyStorePrincipalId().equals(stringPropValue)); + + ds.setQuotedIdentifier(stringPropValue); + assertTrue(ds.getQuotedIdentifier().equals(stringPropValue)); + + ds.setConcatNullYieldsNull(stringPropValue); + assertTrue(ds.getConcatNullYieldsNull().equals(stringPropValue)); } @Test From c3e8fed6a821ea4576ff19ad1a8067b9b78292b6 Mon Sep 17 00:00:00 2001 From: lilgreenbird Date: Thu, 14 Nov 2024 11:14:48 -0800 Subject: [PATCH 03/14] change default --- .../java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java index 06f05bc0d..dc913f2f5 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java @@ -612,8 +612,8 @@ enum SQLServerDriverStringProperty { DATETIME_DATATYPE("datetimeParameterType", DatetimeType.DATETIME2.toString()), ACCESS_TOKEN_CALLBACK_CLASS("accessTokenCallbackClass", ""), RETRY_EXEC("retryExec", ""), - QUOTED_IDENTIFIER("quotedIdentifier", OnOffOption.OFF.toString()), - CONCAT_NULL_YIELDS_NULL("concatNullYieldsNull", OnOffOption.OFF.toString()); + QUOTED_IDENTIFIER("quotedIdentifier", OnOffOption.ON.toString()), + CONCAT_NULL_YIELDS_NULL("concatNullYieldsNull", OnOffOption.ON.toString()); private final String name; private final String defaultValue; From c24c9e719d0775b78aad81f31bce613f064f3b38 Mon Sep 17 00:00:00 2001 From: lilgreenbird Date: Thu, 14 Nov 2024 15:26:07 -0800 Subject: [PATCH 04/14] change to use executeQuery --- .../sqlserver/jdbc/SQLServerConnection.java | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java index 6427e254e..853e8c95b 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java @@ -3269,6 +3269,8 @@ else if (0 == requestedPacketSize) } } + state = State.OPENED; + // check QUOTED_IDENTIFIER property String quotedIdentifierProperty = SQLServerDriverStringProperty.QUOTED_IDENTIFIER.toString(); String quotedIdentifierValue = activeConnectionProperties.getProperty(quotedIdentifierProperty); @@ -3276,11 +3278,14 @@ else if (0 == requestedPacketSize) quotedIdentifierValue = SQLServerDriverStringProperty.QUOTED_IDENTIFIER.getDefaultValue(); activeConnectionProperties.setProperty(quotedIdentifierProperty, quotedIdentifierValue); } + String quotedIdentifierOption = OnOffOption.valueOfString(quotedIdentifierValue).toString(); - if (quotedIdentifierOption.compareToIgnoreCase(OnOffOption.OFF.toString()) == 0) { - connectionCommand("SET QUOTED_IDENTIFIER OFF", "quotedIdentifier"); - } else if (quotedIdentifierOption.compareToIgnoreCase(OnOffOption.ON.toString()) == 0) { - connectionCommand("SET QUOTED_IDENTIFIER ON", "quotedIdentifier"); + try (SQLServerStatement stmt = (SQLServerStatement) this.createStatement()) { + stmt.executeQueryInternal("SET QUOTED_IDENTIFIER " + + ((quotedIdentifierOption.compareToIgnoreCase(OnOffOption.OFF.toString()) == 0) ? "OFF" + : "ON")); + } catch (Exception e) { + throw new SQLServerException(e.getMessage(), null); } // check CONCAT_NULL_YIELDS_NULL property @@ -3291,15 +3296,14 @@ else if (0 == requestedPacketSize) activeConnectionProperties.setProperty(concatNullYieldsNullProperty, concatNullYieldsNullValue); } String concatNullYieldsNullOption = OnOffOption.valueOfString(concatNullYieldsNullValue).toString(); - if (concatNullYieldsNullOption.compareToIgnoreCase(OnOffOption.OFF.toString()) == 0) { - connectionCommand("SET CONCAT_NULL_YIELDS_NULL OFF", "concatNullYieldsNull"); - - } else if (concatNullYieldsNullOption.compareToIgnoreCase(OnOffOption.ON.toString()) == 0) { - connectionCommand("SET CONCAT_NULL_YIELDS_NULL ON", "concatNullYieldsNull"); + try (SQLServerStatement stmt = (SQLServerStatement) this.createStatement()) { + stmt.executeQueryInternal("SET CONCAT_NULL_YIELDS_NULL " + + ((concatNullYieldsNullOption.compareToIgnoreCase(OnOffOption.OFF.toString()) == 0) ? "OFF" + : "ON")); + } catch (Exception e) { + throw new SQLServerException(e.getMessage(), null); } - state = State.OPENED; - // Socket timeout is bounded by loginTimeout during the login phase. // Reset socket timeout back to the original value. tdsChannel.resetTcpSocketTimeout(); From e5300114c02b1b1efce3d755e840fbdd71172af0 Mon Sep 17 00:00:00 2001 From: lilgreenbird Date: Thu, 14 Nov 2024 15:28:17 -0800 Subject: [PATCH 05/14] change default --- .../java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java index dc913f2f5..06f05bc0d 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java @@ -612,8 +612,8 @@ enum SQLServerDriverStringProperty { DATETIME_DATATYPE("datetimeParameterType", DatetimeType.DATETIME2.toString()), ACCESS_TOKEN_CALLBACK_CLASS("accessTokenCallbackClass", ""), RETRY_EXEC("retryExec", ""), - QUOTED_IDENTIFIER("quotedIdentifier", OnOffOption.ON.toString()), - CONCAT_NULL_YIELDS_NULL("concatNullYieldsNull", OnOffOption.ON.toString()); + QUOTED_IDENTIFIER("quotedIdentifier", OnOffOption.OFF.toString()), + CONCAT_NULL_YIELDS_NULL("concatNullYieldsNull", OnOffOption.OFF.toString()); private final String name; private final String defaultValue; From 70d0f9612922c822ed1caf72f059e78d86f3c1c3 Mon Sep 17 00:00:00 2001 From: lilgreenbird Date: Thu, 14 Nov 2024 19:08:43 -0800 Subject: [PATCH 06/14] update test --- .../sqlserver/jdbc/fmtOnly/ParameterMetaDataTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/fmtOnly/ParameterMetaDataTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/fmtOnly/ParameterMetaDataTest.java index 0709c2e34..bff91e87a 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/fmtOnly/ParameterMetaDataTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/fmtOnly/ParameterMetaDataTest.java @@ -77,11 +77,11 @@ public void compareStoredProcTest() throws SQLException { "SELECT cInt FROM " + tableName + " WHERE (cInt + (3 - 5)) = ?", "SELECT cInt FROM " + tableName + " WHERE " + tableName + ".[cInt] = ?", "SELECT cInt FROM " + tableName + " WHERE ? = " + tableName + ".[cInt]", - "WITH t1(cInt) AS (SELECT 1), t2(cInt) AS (SELECT 2) SELECT * FROM t1 JOIN t2 ON [t1].\"cInt\" = \"t2\".[cInt] WHERE \"t1\".[cInt] = [t2].\"cInt\" + ?", + "WITH t1(cInt) AS (SELECT 1), t2(cInt) AS (SELECT 2) SELECT * FROM t1 JOIN t2 ON [t1].[cInt] = [t2].[cInt] WHERE [t1].[cInt] = [t2].[cInt] + ?", "INSERT INTO " + tableName + "(cInt,cFloat) SELECT 1,1.5 WHERE 1 > ?", "WITH t1(cInt) AS (SELECT 1), t2(cInt) AS (SELECT 2), t3(cInt) AS (SELECT 3) SELECT * FROM t1,t2,t3 WHERE t1.cInt >= ?", - "SELECT (1),2,[cInt],\"cFloat\" FROM " + tableName + " WHERE cNvarchar LIKE ?", - "WITH t1(cInt) AS (SELECT 1) SELECT * FROM \"t1\""); + "SELECT (1),2,[cInt],[cFloat] FROM " + tableName + " WHERE cNvarchar LIKE ?", + "WITH t1(cInt) AS (SELECT 1) SELECT * FROM [t1]"); l.forEach(this::compareFmtAndSp); } From 29a12c9a69025a9b119b0d70d4433c2ead4c3155 Mon Sep 17 00:00:00 2001 From: Terry Chow Date: Fri, 15 Nov 2024 12:06:29 -0800 Subject: [PATCH 07/14] Deadlock and null TDSCommand counter fix --- .../sqlserver/jdbc/SQLServerConnection.java | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java index 853e8c95b..5b7710d46 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java @@ -3280,12 +3280,10 @@ else if (0 == requestedPacketSize) } String quotedIdentifierOption = OnOffOption.valueOfString(quotedIdentifierValue).toString(); - try (SQLServerStatement stmt = (SQLServerStatement) this.createStatement()) { - stmt.executeQueryInternal("SET QUOTED_IDENTIFIER " - + ((quotedIdentifierOption.compareToIgnoreCase(OnOffOption.OFF.toString()) == 0) ? "OFF" - : "ON")); - } catch (Exception e) { - throw new SQLServerException(e.getMessage(), null); + if (quotedIdentifierOption.compareToIgnoreCase(OnOffOption.OFF.toString()) == 0) { + connectionCommand("SET QUOTED_IDENTIFIER OFF", "quotedIdentifier"); + } else if (quotedIdentifierOption.compareToIgnoreCase(OnOffOption.ON.toString()) == 0) { + connectionCommand("SET QUOTED_IDENTIFIER ON", "quotedIdentifier"); } // check CONCAT_NULL_YIELDS_NULL property @@ -3296,12 +3294,11 @@ else if (0 == requestedPacketSize) activeConnectionProperties.setProperty(concatNullYieldsNullProperty, concatNullYieldsNullValue); } String concatNullYieldsNullOption = OnOffOption.valueOfString(concatNullYieldsNullValue).toString(); - try (SQLServerStatement stmt = (SQLServerStatement) this.createStatement()) { - stmt.executeQueryInternal("SET CONCAT_NULL_YIELDS_NULL " - + ((concatNullYieldsNullOption.compareToIgnoreCase(OnOffOption.OFF.toString()) == 0) ? "OFF" - : "ON")); - } catch (Exception e) { - throw new SQLServerException(e.getMessage(), null); + if (concatNullYieldsNullOption.compareToIgnoreCase(OnOffOption.OFF.toString()) == 0) { + connectionCommand("SET CONCAT_NULL_YIELDS_NULL OFF", "concatNullYieldsNull"); + + } else if (concatNullYieldsNullOption.compareToIgnoreCase(OnOffOption.ON.toString()) == 0) { + connectionCommand("SET CONCAT_NULL_YIELDS_NULL ON", "concatNullYieldsNull"); } // Socket timeout is bounded by loginTimeout during the login phase. @@ -4557,6 +4554,7 @@ boolean executeReconnectCommand(TDSCommand newCommand) throws SQLServerException */ boolean commandComplete = false; try { + newCommand.createCounter(null, activeConnectionProperties); commandComplete = newCommand.execute(tdsChannel.getWriter(), tdsChannel.getReader(newCommand)); } finally { /* From 90a1d0ef2a3ff6841908a095ef4b33b6f7c975d3 Mon Sep 17 00:00:00 2001 From: Divang Sharma Date: Thu, 27 Feb 2025 16:58:00 +0530 Subject: [PATCH 08/14] Moved the QUOTED_IDENTIFIER and CONCAT_NULL_YIELDS_NULL flag setting in initResettableValues() method to handle it in pooled connection too --- .../sqlserver/jdbc/SQLServerConnection.java | 64 ++++++++++--------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java index 5b7710d46..bc0a77084 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java @@ -1634,6 +1634,40 @@ final void initResettableValues() { sqlWarnings = null; sCatalog = originalCatalog; databaseMetaData = null; + + try{ + // check QUOTED_IDENTIFIER property + String quotedIdentifierProperty = SQLServerDriverStringProperty.QUOTED_IDENTIFIER.toString(); + String quotedIdentifierValue = activeConnectionProperties.getProperty(quotedIdentifierProperty); + if (null == quotedIdentifierValue) { + quotedIdentifierValue = SQLServerDriverStringProperty.QUOTED_IDENTIFIER.getDefaultValue(); + activeConnectionProperties.setProperty(quotedIdentifierProperty, quotedIdentifierValue); + } + + String quotedIdentifierOption = OnOffOption.valueOfString(quotedIdentifierValue).toString(); + if (quotedIdentifierOption.compareToIgnoreCase(OnOffOption.OFF.toString()) == 0) { + connectionCommand("SET QUOTED_IDENTIFIER OFF", "quotedIdentifier"); + } else if (quotedIdentifierOption.compareToIgnoreCase(OnOffOption.ON.toString()) == 0) { + connectionCommand("SET QUOTED_IDENTIFIER ON", "quotedIdentifier"); + } + + // check CONCAT_NULL_YIELDS_NULL property + String concatNullYieldsNullProperty = SQLServerDriverStringProperty.CONCAT_NULL_YIELDS_NULL.toString(); + String concatNullYieldsNullValue = activeConnectionProperties.getProperty(concatNullYieldsNullProperty); + if (null == concatNullYieldsNullValue) { + concatNullYieldsNullValue = SQLServerDriverStringProperty.CONCAT_NULL_YIELDS_NULL.getDefaultValue(); + activeConnectionProperties.setProperty(concatNullYieldsNullProperty, concatNullYieldsNullValue); + } + String concatNullYieldsNullOption = OnOffOption.valueOfString(concatNullYieldsNullValue).toString(); + if (concatNullYieldsNullOption.compareToIgnoreCase(OnOffOption.OFF.toString()) == 0) { + connectionCommand("SET CONCAT_NULL_YIELDS_NULL OFF", "concatNullYieldsNull"); + + } else if (concatNullYieldsNullOption.compareToIgnoreCase(OnOffOption.ON.toString()) == 0) { + connectionCommand("SET CONCAT_NULL_YIELDS_NULL ON", "concatNullYieldsNull"); + } + } catch(SQLServerException e) { + loggerExternal.log(Level.WARNING, "Error setting QUOTED_IDENTIFIER and CONCAT_NULL_YIELDS_NULL properties", e); + } } /** Limit for the maximum number of rows returned from queries on this connection */ @@ -3271,36 +3305,6 @@ else if (0 == requestedPacketSize) state = State.OPENED; - // check QUOTED_IDENTIFIER property - String quotedIdentifierProperty = SQLServerDriverStringProperty.QUOTED_IDENTIFIER.toString(); - String quotedIdentifierValue = activeConnectionProperties.getProperty(quotedIdentifierProperty); - if (null == quotedIdentifierValue) { - quotedIdentifierValue = SQLServerDriverStringProperty.QUOTED_IDENTIFIER.getDefaultValue(); - activeConnectionProperties.setProperty(quotedIdentifierProperty, quotedIdentifierValue); - } - - String quotedIdentifierOption = OnOffOption.valueOfString(quotedIdentifierValue).toString(); - if (quotedIdentifierOption.compareToIgnoreCase(OnOffOption.OFF.toString()) == 0) { - connectionCommand("SET QUOTED_IDENTIFIER OFF", "quotedIdentifier"); - } else if (quotedIdentifierOption.compareToIgnoreCase(OnOffOption.ON.toString()) == 0) { - connectionCommand("SET QUOTED_IDENTIFIER ON", "quotedIdentifier"); - } - - // check CONCAT_NULL_YIELDS_NULL property - String concatNullYieldsNullProperty = SQLServerDriverStringProperty.CONCAT_NULL_YIELDS_NULL.toString(); - String concatNullYieldsNullValue = activeConnectionProperties.getProperty(concatNullYieldsNullProperty); - if (null == concatNullYieldsNullValue) { - concatNullYieldsNullValue = SQLServerDriverStringProperty.CONCAT_NULL_YIELDS_NULL.getDefaultValue(); - activeConnectionProperties.setProperty(concatNullYieldsNullProperty, concatNullYieldsNullValue); - } - String concatNullYieldsNullOption = OnOffOption.valueOfString(concatNullYieldsNullValue).toString(); - if (concatNullYieldsNullOption.compareToIgnoreCase(OnOffOption.OFF.toString()) == 0) { - connectionCommand("SET CONCAT_NULL_YIELDS_NULL OFF", "concatNullYieldsNull"); - - } else if (concatNullYieldsNullOption.compareToIgnoreCase(OnOffOption.ON.toString()) == 0) { - connectionCommand("SET CONCAT_NULL_YIELDS_NULL ON", "concatNullYieldsNull"); - } - // Socket timeout is bounded by loginTimeout during the login phase. // Reset socket timeout back to the original value. tdsChannel.resetTcpSocketTimeout(); From cf9ea3a26bdaff8eecca8f8f19fe17a50a1d23c3 Mon Sep 17 00:00:00 2001 From: Divang Sharma Date: Fri, 28 Feb 2025 12:24:36 +0530 Subject: [PATCH 09/14] Removed the default Flag setting call to server for QUOTED_IDENTIFIER and CONCAT_NULL_YIELDS_NULL --- .../com/microsoft/sqlserver/jdbc/SQLServerConnection.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java index 478d236c1..ddd6d669d 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java @@ -1841,8 +1841,6 @@ final void initResettableValues() { String quotedIdentifierOption = OnOffOption.valueOfString(quotedIdentifierValue).toString(); if (quotedIdentifierOption.compareToIgnoreCase(OnOffOption.OFF.toString()) == 0) { connectionCommand("SET QUOTED_IDENTIFIER OFF", "quotedIdentifier"); - } else if (quotedIdentifierOption.compareToIgnoreCase(OnOffOption.ON.toString()) == 0) { - connectionCommand("SET QUOTED_IDENTIFIER ON", "quotedIdentifier"); } // check CONCAT_NULL_YIELDS_NULL property @@ -1856,8 +1854,6 @@ final void initResettableValues() { if (concatNullYieldsNullOption.compareToIgnoreCase(OnOffOption.OFF.toString()) == 0) { connectionCommand("SET CONCAT_NULL_YIELDS_NULL OFF", "concatNullYieldsNull"); - } else if (concatNullYieldsNullOption.compareToIgnoreCase(OnOffOption.ON.toString()) == 0) { - connectionCommand("SET CONCAT_NULL_YIELDS_NULL ON", "concatNullYieldsNull"); } } catch(SQLServerException e) { loggerExternal.log(Level.WARNING, "Error setting QUOTED_IDENTIFIER and CONCAT_NULL_YIELDS_NULL properties", e); @@ -3568,9 +3564,7 @@ else if (0 == requestedPacketSize) if (connectionlogger.isLoggable(Level.FINER)) { connectionlogger.finer(toString() + " End of connect"); } - } catch ( - - SocketException e) { + } catch (SocketException e) { throw new SQLServerException(e.getMessage(), null); } finally { // once we exit the connect function, the connection can be only in one of two From 1b333c05a5bb2eae904a05506b51ad8ea2ccd961 Mon Sep 17 00:00:00 2001 From: Divang Sharma Date: Fri, 28 Feb 2025 22:07:31 +0530 Subject: [PATCH 10/14] Added one more state - NOT_SET for QUOTED_IDENTIFIER and CONCAT_NULL_YIELDS_NULL flag --- .../sqlserver/jdbc/SQLServerConnection.java | 76 +++++++++++-------- .../sqlserver/jdbc/SQLServerDriver.java | 9 ++- 2 files changed, 52 insertions(+), 33 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java index ddd6d669d..434b6a959 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java @@ -299,6 +299,12 @@ public String toString() { /** flag indicating whether prelogin TLS handshake is required */ private boolean isTDS8 = false; + /** flag to indicating whether QUOTED_IDENTIFIER is ON/OFF */ + private OnOffOption isQuotedIdentifierOn = OnOffOption.NOT_SET; + + /** flag to indicating whether CONCAT_NULL_YIELDS_NULL is ON/OFF */ + private OnOffOption isConcatNullYieldsNullOn = OnOffOption.NOT_SET; + /** encrypted truststore password */ byte[] encryptedTrustStorePassword = null; @@ -1813,6 +1819,20 @@ final void setMaxFieldSize(int limit) throws SQLServerException { } } + private void setCustomFlags() { + try{ + if (OnOffOption.OFF.equals(isQuotedIdentifierOn)) { + connectionCommand("SET QUOTED_IDENTIFIER OFF", "quotedIdentifier"); + } + + if (OnOffOption.OFF.equals(isConcatNullYieldsNullOn)) { + connectionCommand("SET CONCAT_NULL_YIELDS_NULL OFF", "concatNullYieldsNull"); + } + } catch(SQLServerException e) { + loggerExternal.log(Level.WARNING, "Error setting QUOTED_IDENTIFIER and CONCAT_NULL_YIELDS_NULL properties", e); + } + } + /** * This function is used both to init the values on creation of connection and resetting the values after the * connection is released to the pool for reuse. @@ -1828,36 +1848,7 @@ final void initResettableValues() { sqlWarnings = null; sCatalog = originalCatalog; databaseMetaData = null; - - try{ - // check QUOTED_IDENTIFIER property - String quotedIdentifierProperty = SQLServerDriverStringProperty.QUOTED_IDENTIFIER.toString(); - String quotedIdentifierValue = activeConnectionProperties.getProperty(quotedIdentifierProperty); - if (null == quotedIdentifierValue) { - quotedIdentifierValue = SQLServerDriverStringProperty.QUOTED_IDENTIFIER.getDefaultValue(); - activeConnectionProperties.setProperty(quotedIdentifierProperty, quotedIdentifierValue); - } - - String quotedIdentifierOption = OnOffOption.valueOfString(quotedIdentifierValue).toString(); - if (quotedIdentifierOption.compareToIgnoreCase(OnOffOption.OFF.toString()) == 0) { - connectionCommand("SET QUOTED_IDENTIFIER OFF", "quotedIdentifier"); - } - - // check CONCAT_NULL_YIELDS_NULL property - String concatNullYieldsNullProperty = SQLServerDriverStringProperty.CONCAT_NULL_YIELDS_NULL.toString(); - String concatNullYieldsNullValue = activeConnectionProperties.getProperty(concatNullYieldsNullProperty); - if (null == concatNullYieldsNullValue) { - concatNullYieldsNullValue = SQLServerDriverStringProperty.CONCAT_NULL_YIELDS_NULL.getDefaultValue(); - activeConnectionProperties.setProperty(concatNullYieldsNullProperty, concatNullYieldsNullValue); - } - String concatNullYieldsNullOption = OnOffOption.valueOfString(concatNullYieldsNullValue).toString(); - if (concatNullYieldsNullOption.compareToIgnoreCase(OnOffOption.OFF.toString()) == 0) { - connectionCommand("SET CONCAT_NULL_YIELDS_NULL OFF", "concatNullYieldsNull"); - - } - } catch(SQLServerException e) { - loggerExternal.log(Level.WARNING, "Error setting QUOTED_IDENTIFIER and CONCAT_NULL_YIELDS_NULL properties", e); - } + setCustomFlags(); } /** Limit for the maximum number of rows returned from queries on this connection */ @@ -3557,6 +3548,31 @@ else if (0 == requestedPacketSize) state = State.OPENED; + // check QUOTED_IDENTIFIER property + String quotedIdentifierProperty = SQLServerDriverStringProperty.QUOTED_IDENTIFIER.toString(); + String quotedIdentifierValue = activeConnectionProperties.getProperty(quotedIdentifierProperty); + if (null == quotedIdentifierValue) { + quotedIdentifierValue = SQLServerDriverStringProperty.QUOTED_IDENTIFIER.getDefaultValue(); + activeConnectionProperties.setProperty(quotedIdentifierProperty, quotedIdentifierValue); + } + + isQuotedIdentifierOn = OnOffOption.valueOfString(quotedIdentifierValue); + if (!isQuotedIdentifierOn.equals(OnOffOption.NOT_SET)) { + connectionCommand("SET QUOTED_IDENTIFIER " + isQuotedIdentifierOn, "quotedIdentifier"); + } + + // check CONCAT_NULL_YIELDS_NULL property + String concatNullYieldsNullProperty = SQLServerDriverStringProperty.CONCAT_NULL_YIELDS_NULL.toString(); + String concatNullYieldsNullValue = activeConnectionProperties.getProperty(concatNullYieldsNullProperty); + if (null == concatNullYieldsNullValue) { + concatNullYieldsNullValue = SQLServerDriverStringProperty.CONCAT_NULL_YIELDS_NULL.getDefaultValue(); + activeConnectionProperties.setProperty(concatNullYieldsNullProperty, concatNullYieldsNullValue); + } + isConcatNullYieldsNullOn = OnOffOption.valueOfString(concatNullYieldsNullValue); + if (!isConcatNullYieldsNullOn.equals(OnOffOption.NOT_SET)) { + connectionCommand("SET CONCAT_NULL_YIELDS_NULL " + isConcatNullYieldsNullOn, "concatNullYieldsNull"); + } + // Socket timeout is bounded by loginTimeout during the login phase. // Reset socket timeout back to the original value. tdsChannel.resetTcpSocketTimeout(); diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java index 050d41d31..927dcdf19 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java @@ -613,8 +613,8 @@ enum SQLServerDriverStringProperty { ACCESS_TOKEN_CALLBACK_CLASS("accessTokenCallbackClass", ""), RETRY_EXEC("retryExec", ""), RETRY_CONN("retryConn", ""), - QUOTED_IDENTIFIER("quotedIdentifier", OnOffOption.OFF.toString()), - CONCAT_NULL_YIELDS_NULL("concatNullYieldsNull", OnOffOption.OFF.toString()); + QUOTED_IDENTIFIER("quotedIdentifier", OnOffOption.NOT_SET.toString()), + CONCAT_NULL_YIELDS_NULL("concatNullYieldsNull", OnOffOption.NOT_SET.toString()); private final String name; private final String defaultValue; @@ -732,7 +732,8 @@ public String toString() { enum OnOffOption { ON("ON"), - OFF("OFF"); + OFF("OFF"), + NOT_SET("NOT_SET"); private final String option; @@ -752,6 +753,8 @@ static OnOffOption valueOfString(String value) throws SQLServerException { option = OnOffOption.ON; } else if (value.toLowerCase(Locale.US).equalsIgnoreCase(OnOffOption.OFF.toString())) { option = OnOffOption.OFF; + } else if (value.toLowerCase(Locale.US).equalsIgnoreCase(OnOffOption.NOT_SET.toString())) { + option = OnOffOption.NOT_SET; } else { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidConnectionSetting")); Object[] msgArgs = {"OnOffOption", value}; From bb41fb6b520b01b2199e2042ca9a80c7ea0f18ee Mon Sep 17 00:00:00 2001 From: Divang Sharma Date: Fri, 28 Feb 2025 22:22:11 +0530 Subject: [PATCH 11/14] Fixed setCustomFlags to set correct state of a flag --- .../com/microsoft/sqlserver/jdbc/SQLServerConnection.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java index 434b6a959..7bdf98b0b 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java @@ -1821,12 +1821,12 @@ final void setMaxFieldSize(int limit) throws SQLServerException { private void setCustomFlags() { try{ - if (OnOffOption.OFF.equals(isQuotedIdentifierOn)) { - connectionCommand("SET QUOTED_IDENTIFIER OFF", "quotedIdentifier"); + if (!isQuotedIdentifierOn.equals(OnOffOption.NOT_SET)) { + connectionCommand("SET QUOTED_IDENTIFIER " + isQuotedIdentifierOn, "quotedIdentifier"); } - if (OnOffOption.OFF.equals(isConcatNullYieldsNullOn)) { - connectionCommand("SET CONCAT_NULL_YIELDS_NULL OFF", "concatNullYieldsNull"); + if (!isConcatNullYieldsNullOn.equals(OnOffOption.NOT_SET)) { + connectionCommand("SET CONCAT_NULL_YIELDS_NULL " + isConcatNullYieldsNullOn, "concatNullYieldsNull"); } } catch(SQLServerException e) { loggerExternal.log(Level.WARNING, "Error setting QUOTED_IDENTIFIER and CONCAT_NULL_YIELDS_NULL properties", e); From bfad8d7d7fc29b20b32e0f65982fd3c6d06eea6b Mon Sep 17 00:00:00 2001 From: Divang Sharma Date: Mon, 3 Mar 2025 19:50:01 +0530 Subject: [PATCH 12/14] Reverted defaultFlagSet method. It is not required. Server set ANSI_DEFAULTS=ON on LOGIN7 call and CONCAT_NULL_YIELDS_NULL/QUOTED_IDENTIFIER are set ON by default. --- .../sqlserver/jdbc/SQLServerConnection.java | 34 ++++--------------- .../sqlserver/jdbc/SQLServerDriver.java | 9 ++--- 2 files changed, 10 insertions(+), 33 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java index 7bdf98b0b..a650490df 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java @@ -299,12 +299,6 @@ public String toString() { /** flag indicating whether prelogin TLS handshake is required */ private boolean isTDS8 = false; - /** flag to indicating whether QUOTED_IDENTIFIER is ON/OFF */ - private OnOffOption isQuotedIdentifierOn = OnOffOption.NOT_SET; - - /** flag to indicating whether CONCAT_NULL_YIELDS_NULL is ON/OFF */ - private OnOffOption isConcatNullYieldsNullOn = OnOffOption.NOT_SET; - /** encrypted truststore password */ byte[] encryptedTrustStorePassword = null; @@ -1819,20 +1813,6 @@ final void setMaxFieldSize(int limit) throws SQLServerException { } } - private void setCustomFlags() { - try{ - if (!isQuotedIdentifierOn.equals(OnOffOption.NOT_SET)) { - connectionCommand("SET QUOTED_IDENTIFIER " + isQuotedIdentifierOn, "quotedIdentifier"); - } - - if (!isConcatNullYieldsNullOn.equals(OnOffOption.NOT_SET)) { - connectionCommand("SET CONCAT_NULL_YIELDS_NULL " + isConcatNullYieldsNullOn, "concatNullYieldsNull"); - } - } catch(SQLServerException e) { - loggerExternal.log(Level.WARNING, "Error setting QUOTED_IDENTIFIER and CONCAT_NULL_YIELDS_NULL properties", e); - } - } - /** * This function is used both to init the values on creation of connection and resetting the values after the * connection is released to the pool for reuse. @@ -1848,7 +1828,6 @@ final void initResettableValues() { sqlWarnings = null; sCatalog = originalCatalog; databaseMetaData = null; - setCustomFlags(); } /** Limit for the maximum number of rows returned from queries on this connection */ @@ -3556,9 +3535,9 @@ else if (0 == requestedPacketSize) activeConnectionProperties.setProperty(quotedIdentifierProperty, quotedIdentifierValue); } - isQuotedIdentifierOn = OnOffOption.valueOfString(quotedIdentifierValue); - if (!isQuotedIdentifierOn.equals(OnOffOption.NOT_SET)) { - connectionCommand("SET QUOTED_IDENTIFIER " + isQuotedIdentifierOn, "quotedIdentifier"); + String quotedIdentifierOption = OnOffOption.valueOfString(quotedIdentifierValue).toString(); + if (quotedIdentifierOption.compareToIgnoreCase(OnOffOption.OFF.toString()) == 0) { + connectionCommand("SET QUOTED_IDENTIFIER OFF", "quotedIdentifier"); } // check CONCAT_NULL_YIELDS_NULL property @@ -3568,9 +3547,10 @@ else if (0 == requestedPacketSize) concatNullYieldsNullValue = SQLServerDriverStringProperty.CONCAT_NULL_YIELDS_NULL.getDefaultValue(); activeConnectionProperties.setProperty(concatNullYieldsNullProperty, concatNullYieldsNullValue); } - isConcatNullYieldsNullOn = OnOffOption.valueOfString(concatNullYieldsNullValue); - if (!isConcatNullYieldsNullOn.equals(OnOffOption.NOT_SET)) { - connectionCommand("SET CONCAT_NULL_YIELDS_NULL " + isConcatNullYieldsNullOn, "concatNullYieldsNull"); + + String concatNullYieldsOption = OnOffOption.valueOfString(concatNullYieldsNullValue).toString(); + if (concatNullYieldsOption.compareToIgnoreCase(OnOffOption.OFF.toString()) == 0) { + connectionCommand("SET CONCAT_NULL_YIELDS_NULL OFF", "concatNullYields"); } // Socket timeout is bounded by loginTimeout during the login phase. diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java index 927dcdf19..aa1c0c5c0 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java @@ -613,8 +613,8 @@ enum SQLServerDriverStringProperty { ACCESS_TOKEN_CALLBACK_CLASS("accessTokenCallbackClass", ""), RETRY_EXEC("retryExec", ""), RETRY_CONN("retryConn", ""), - QUOTED_IDENTIFIER("quotedIdentifier", OnOffOption.NOT_SET.toString()), - CONCAT_NULL_YIELDS_NULL("concatNullYieldsNull", OnOffOption.NOT_SET.toString()); + QUOTED_IDENTIFIER("quotedIdentifier", OnOffOption.ON.toString()), + CONCAT_NULL_YIELDS_NULL("concatNullYieldsNull", OnOffOption.ON.toString()); private final String name; private final String defaultValue; @@ -732,8 +732,7 @@ public String toString() { enum OnOffOption { ON("ON"), - OFF("OFF"), - NOT_SET("NOT_SET"); + OFF("OFF"); private final String option; @@ -753,8 +752,6 @@ static OnOffOption valueOfString(String value) throws SQLServerException { option = OnOffOption.ON; } else if (value.toLowerCase(Locale.US).equalsIgnoreCase(OnOffOption.OFF.toString())) { option = OnOffOption.OFF; - } else if (value.toLowerCase(Locale.US).equalsIgnoreCase(OnOffOption.NOT_SET.toString())) { - option = OnOffOption.NOT_SET; } else { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_InvalidConnectionSetting")); Object[] msgArgs = {"OnOffOption", value}; From e3d0cf2daff166c1fd1a60b521c51698034712f7 Mon Sep 17 00:00:00 2001 From: Divang Sharma Date: Mon, 3 Mar 2025 21:08:36 +0530 Subject: [PATCH 13/14] Optimized the code for QUOTED_IDENTIFIER/CONCAT_NULL_YIELDS_NULL flags are not supplied (server default case) --- .../sqlserver/jdbc/SQLServerConnection.java | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java index a650490df..f8883cc17 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java @@ -3530,27 +3530,33 @@ else if (0 == requestedPacketSize) // check QUOTED_IDENTIFIER property String quotedIdentifierProperty = SQLServerDriverStringProperty.QUOTED_IDENTIFIER.toString(); String quotedIdentifierValue = activeConnectionProperties.getProperty(quotedIdentifierProperty); - if (null == quotedIdentifierValue) { - quotedIdentifierValue = SQLServerDriverStringProperty.QUOTED_IDENTIFIER.getDefaultValue(); + if (null != quotedIdentifierValue) { + OnOffOption quotedIdentifierOption = OnOffOption.valueOfString(quotedIdentifierValue); activeConnectionProperties.setProperty(quotedIdentifierProperty, quotedIdentifierValue); - } - - String quotedIdentifierOption = OnOffOption.valueOfString(quotedIdentifierValue).toString(); - if (quotedIdentifierOption.compareToIgnoreCase(OnOffOption.OFF.toString()) == 0) { - connectionCommand("SET QUOTED_IDENTIFIER OFF", "quotedIdentifier"); + switch (quotedIdentifierOption) { + case ON: + connectionCommand("SET QUOTED_IDENTIFIER ON", "quotedIdentifier"); + break; + case OFF: + connectionCommand("SET QUOTED_IDENTIFIER OFF", "quotedIdentifier"); + break; + } } // check CONCAT_NULL_YIELDS_NULL property String concatNullYieldsNullProperty = SQLServerDriverStringProperty.CONCAT_NULL_YIELDS_NULL.toString(); String concatNullYieldsNullValue = activeConnectionProperties.getProperty(concatNullYieldsNullProperty); - if (null == concatNullYieldsNullValue) { - concatNullYieldsNullValue = SQLServerDriverStringProperty.CONCAT_NULL_YIELDS_NULL.getDefaultValue(); + if (null != concatNullYieldsNullValue) { + OnOffOption concatNullYieldsOption = OnOffOption.valueOfString(concatNullYieldsNullValue); activeConnectionProperties.setProperty(concatNullYieldsNullProperty, concatNullYieldsNullValue); - } - - String concatNullYieldsOption = OnOffOption.valueOfString(concatNullYieldsNullValue).toString(); - if (concatNullYieldsOption.compareToIgnoreCase(OnOffOption.OFF.toString()) == 0) { - connectionCommand("SET CONCAT_NULL_YIELDS_NULL OFF", "concatNullYields"); + switch (concatNullYieldsOption) { + case ON: + connectionCommand("SET CONCAT_NULL_YIELDS_NULL ON", "concatNullYields"); + break; + case OFF: + connectionCommand("SET CONCAT_NULL_YIELDS_NULL OFF", "concatNullYields"); + break; + } } // Socket timeout is bounded by loginTimeout during the login phase. From 4e7192ad7a9a74b4aaef0a5f80c218f76a83be04 Mon Sep 17 00:00:00 2001 From: Divang Sharma Date: Tue, 4 Mar 2025 13:20:14 +0530 Subject: [PATCH 14/14] Added test cases for QUOTED_IDENTIFIER/CONCAT_NULL_YIELDS_NULL flags' value for new and pooled connection --- .../jdbc/SQLServerConnectionTest.java | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) diff --git a/src/test/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionTest.java b/src/test/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionTest.java index 921e93742..b95064952 100644 --- a/src/test/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionTest.java +++ b/src/test/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionTest.java @@ -468,6 +468,126 @@ public void testConnectionPoolGetTwice() throws SQLException { } } + /** + * Test connection properties: CONCAT_NULL_YIELDS_NULL with SQLServerXADataSource for new connection and pooled connection + * @throws SQLException + */ + @Test + public void testConcatNullYieldsNull() throws SQLException { + SQLServerDataSource ds = new SQLServerDataSource(); + ds.setURL(connectionString); + ds.setConcatNullYieldsNull("OFF"); + int expectedResultForNewConnection = 0; + // Server default is CONCAT_NULL_YIELDS_NULL = ON + int expectedResultForPooledConnection = 1; + + String sqlSelect = "SELECT SESSIONPROPERTY('CONCAT_NULL_YIELDS_NULL')"; + + try (Connection con = ds.getConnection(); Statement stmt = con.createStatement()) { + try (ResultSet rs = stmt.executeQuery(sqlSelect)) { + if (rs.next()) { + assertEquals(expectedResultForNewConnection, rs.getInt(1)); + } else { + assertTrue(false, "Expected row of data was not found."); + } + } + } + + // Test pooled connections + SQLServerXADataSource pds = new SQLServerXADataSource(); + pds.setURL(connectionString); + pds.setConcatNullYieldsNull("OFF"); + + PooledConnection pc = pds.getPooledConnection(); + try { + try (Connection con = pc.getConnection(); Statement statement = con.createStatement()) { + try (ResultSet rs = statement.executeQuery(sqlSelect)) { + if (rs.next()) { + assertEquals(expectedResultForNewConnection, rs.getInt(1)); + } else { + assertTrue(false, "Expected row of data was not found."); + } + } + } + // Repeat getConnection to put the physical connection through a RESETCONNECTION + try (Connection con = pc.getConnection(); Statement statement = con.createStatement()) { + try (ResultSet rs = statement.executeQuery(sqlSelect)) { + if (rs.next()) { + assertEquals(expectedResultForPooledConnection, rs.getInt(1)); + } else { + assertTrue(false, "Expected row of data was not found."); + } + } + } + } catch (Exception e) { + fail(TestResource.getResource("R_unexpectedErrorMessage") + e.getMessage()); + } finally { + if (null != pc) { + pc.close(); + } + } + } + + /** + * Test connection properties: QUOTED_IDENTIFIER with SQLServerXADataSource for new connection and pooled connection + * @throws SQLException + */ + @Test + public void testQuptedIdentifier() throws SQLException { + SQLServerDataSource ds = new SQLServerDataSource(); + ds.setURL(connectionString); + ds.setQuotedIdentifier("OFF"); + int expectedResultForNewConnection = 0; + // Server default is QUOTED_IDENTIFIER = ON + int expectedResultForPooledConnection = 1; + + String sqlSelect = "SELECT SESSIONPROPERTY('QUOTED_IDENTIFIER')"; + + try (Connection con = ds.getConnection(); Statement stmt = con.createStatement()) { + try (ResultSet rs = stmt.executeQuery(sqlSelect)) { + if (rs.next()) { + assertEquals(expectedResultForNewConnection, rs.getInt(1)); + } else { + assertTrue(false, "Expected row of data was not found."); + } + } + } + + // Test pooled connections + SQLServerXADataSource pds = new SQLServerXADataSource(); + pds.setURL(connectionString); + pds.setQuotedIdentifier("OFF"); + + PooledConnection pc = pds.getPooledConnection(); + try { + try (Connection con = pc.getConnection(); Statement statement = con.createStatement()) { + try (ResultSet rs = statement.executeQuery(sqlSelect)) { + if (rs.next()) { + assertEquals(expectedResultForNewConnection, rs.getInt(1)); + } else { + assertTrue(false, "Expected row of data was not found."); + } + } + } + // Repeat getConnection to put the physical connection through a RESETCONNECTION + try (Connection con = pc.getConnection(); Statement statement = con.createStatement()) { + try (ResultSet rs = statement.executeQuery(sqlSelect)) { + if (rs.next()) { + assertEquals(expectedResultForPooledConnection, rs.getInt(1)); + } else { + assertTrue(false, "Expected row of data was not found."); + } + } + } + } catch (Exception e) { + fail(TestResource.getResource("R_unexpectedErrorMessage") + e.getMessage()); + } finally { + if (null != pc) { + pc.close(); + } + } + } + /** * Runs the `testConnectCountInLoginAndCorrectRetryCount` test several times with different values of * connectRetryCount.