Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blackrock: Added QUOTED_IDENTIFIER and CONCAT_NULL_YIELDS_NULL flag in connection #2618

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1451,8 +1451,8 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource {
* @return cacheBulkCopyMetadata boolean value
*/
boolean getcacheBulkCopyMetadata();
/**

/**
* Returns value of 'retryExec' from Connection String.
*
* @param retryExec
Expand Down Expand Up @@ -1506,4 +1506,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);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3527,6 +3527,38 @@

state = State.OPENED;

// check QUOTED_IDENTIFIER property
String quotedIdentifierProperty = SQLServerDriverStringProperty.QUOTED_IDENTIFIER.toString();
String quotedIdentifierValue = activeConnectionProperties.getProperty(quotedIdentifierProperty);
if (null != quotedIdentifierValue) {
OnOffOption quotedIdentifierOption = OnOffOption.valueOfString(quotedIdentifierValue);
activeConnectionProperties.setProperty(quotedIdentifierProperty, quotedIdentifierValue);
switch (quotedIdentifierOption) {
case ON:
connectionCommand("SET QUOTED_IDENTIFIER ON", "quotedIdentifier");
break;

Check warning on line 3539 in src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java#L3538-L3539

Added lines #L3538 - L3539 were not covered by tests
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) {
OnOffOption concatNullYieldsOption = OnOffOption.valueOfString(concatNullYieldsNullValue);
activeConnectionProperties.setProperty(concatNullYieldsNullProperty, concatNullYieldsNullValue);
switch (concatNullYieldsOption) {
case ON:
connectionCommand("SET CONCAT_NULL_YIELDS_NULL ON", "concatNullYields");
break;

Check warning on line 3555 in src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java#L3554-L3555

Added lines #L3554 - L3555 were not covered by tests
case OFF:
connectionCommand("SET CONCAT_NULL_YIELDS_NULL OFF", "concatNullYields");
break;
}
}

// Socket timeout is bounded by loginTimeout during the login phase.
// Reset socket timeout back to the original value.
tdsChannel.resetTcpSocketTimeout();
Expand Down Expand Up @@ -4782,6 +4814,7 @@
*/
boolean commandComplete = false;
try {
newCommand.createCounter(null, activeConnectionProperties);

Check warning on line 4817 in src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java#L4817

Added line #L4817 was not covered by tests
commandComplete = newCommand.execute(tdsChannel.getWriter(), tdsChannel.getReader(newCommand));
} finally {
/*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -948,17 +948,15 @@

@Override
public void setcacheBulkCopyMetadata(boolean cacheBulkCopyMetadata) {
setBooleanProperty(connectionProps,
SQLServerDriverBooleanProperty.ENABLE_BULK_COPY_CACHE.toString(),
setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.ENABLE_BULK_COPY_CACHE.toString(),

Check warning on line 951 in src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java#L951

Added line #L951 was not covered by tests
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(),

Check warning on line 958 in src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDataSource.java#L957-L958

Added lines #L957 - L958 were not covered by tests
defaultValue);
}

@Override
Expand Down Expand Up @@ -1392,7 +1390,6 @@
@Override
public void setUseFlexibleCallableStatements(boolean enable) {}


/**
* useFlexibleCallableStatements is temporarily removed.
* This method is a no-op for backwards compatibility only.
Expand Down Expand Up @@ -1494,6 +1491,29 @@
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 quotedIdentifier) {
setStringProperty(connectionProps, SQLServerDriverStringProperty.QUOTED_IDENTIFIER.toString(), quotedIdentifier);
}

@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 the 'retryConn' setting.
*
Expand Down
58 changes: 53 additions & 5 deletions src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,9 @@
DATETIME_DATATYPE("datetimeParameterType", DatetimeType.DATETIME2.toString()),
ACCESS_TOKEN_CALLBACK_CLASS("accessTokenCallbackClass", ""),
RETRY_EXEC("retryExec", ""),
RETRY_CONN("retryConn", "");
RETRY_CONN("retryConn", ""),
QUOTED_IDENTIFIER("quotedIdentifier", OnOffOption.ON.toString()),
CONCAT_NULL_YIELDS_NULL("concatNullYieldsNull", OnOffOption.ON.toString());

private final String name;
private final String defaultValue;
Expand Down Expand Up @@ -728,6 +730,47 @@
}


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;

Check warning on line 752 in src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java#L752

Added line #L752 was not covered by tests
} 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);

Check warning on line 758 in src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java#L756-L758

Added lines #L756 - L758 were not covered by tests
}
return option;
}

static boolean isValidOnOffOption(String option) {
for (OnOffOption t : OnOffOption.values()) {
if (option.equalsIgnoreCase(t.toString())) {
return true;

Check warning on line 766 in src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java#L766

Added line #L766 was not covered by tests
}
}
return false;

Check warning on line 769 in src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java

View check run for this annotation

Codecov / codecov/patch

src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java#L769

Added line #L769 was not covered by tests
}
}


/**
* Provides methods to connect to a SQL Server database and to obtain information about the JDBC driver.
*/
Expand Down Expand Up @@ -807,8 +850,8 @@
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()}),
Expand Down Expand Up @@ -1002,8 +1045,13 @@
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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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_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."},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,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
Expand Down Expand Up @@ -462,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.
Expand Down
Loading
Loading