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

Adding replication connection option #1566

Merged
merged 3 commits into from
Apr 24, 2021
Merged
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
3 changes: 2 additions & 1 deletion src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,8 @@ static final String getTokenName(int tdsTokenType) {
static final byte LOGIN_OPTION2_USER_NORMAL = 0x00;
static final byte LOGIN_OPTION2_USER_SERVER = 0x10;
static final byte LOGIN_OPTION2_USER_REMUSER = 0x20;
static final byte LOGIN_OPTION2_USER_SQLREPL = 0x30;
static final byte LOGIN_OPTION2_USER_SQLREPL_OFF = 0x00;
static final byte LOGIN_OPTION2_USER_SQLREPL_ON = 0x30;
static final byte LOGIN_OPTION2_INTEGRATED_SECURITY_OFF = 0x00;
static final byte LOGIN_OPTION2_INTEGRATED_SECURITY_ON = (byte) 0x80;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,21 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource {
*/
String getResponseBuffering();

/**
* Sets the value to enable/disable the replication connection property.
*
* @param replication
* A Boolean value. When true, tells the server that the connection is used for replication.
*/
void setReplication(boolean replication);

/**
* Returns the value of the replication connection property.
*
* @return true if the connection is to be used for replication. Otherwise false.
*/
boolean getReplication();

/**
* Sets the value to enable/disable the sendTimeAsDatetime connection property.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,7 @@ public void setUseBulkCopyForBatchInsert(boolean useBulkCopyForBatchInsert) {

boolean userSetTNIR = true;

private boolean replication = SQLServerDriverBooleanProperty.REPLICATION.getDefaultValue();
private boolean sendTimeAsDatetime = SQLServerDriverBooleanProperty.SEND_TIME_AS_DATETIME.getDefaultValue();
private boolean useFmtOnly = SQLServerDriverBooleanProperty.USE_FMT_ONLY.getDefaultValue();

Expand Down Expand Up @@ -1803,6 +1804,15 @@ Connection connectInternal(Properties propsIn,
applicationIntent = ApplicationIntent.valueOfString(sPropValue);
activeConnectionProperties.setProperty(sPropKey, applicationIntent.toString());

sPropKey = SQLServerDriverBooleanProperty.REPLICATION.toString();
sPropValue = activeConnectionProperties.getProperty(sPropKey);
if (null == sPropValue) {
sPropValue = Boolean.toString(SQLServerDriverBooleanProperty.REPLICATION.getDefaultValue());
activeConnectionProperties.setProperty(sPropKey, sPropValue);
}

replication = isBooleanPropertyOn(sPropKey, sPropValue);

sPropKey = SQLServerDriverBooleanProperty.SEND_TIME_AS_DATETIME.toString();
sPropValue = activeConnectionProperties.getProperty(sPropKey);
if (null == sPropValue) {
Expand Down Expand Up @@ -5218,6 +5228,7 @@ final boolean complete(LogonCommand logonCommand, TDSReader tdsReader) throws SQ
// fails
TDS.LOGIN_OPTION2_ODBC_ON | // Use ODBC defaults (ANSI_DEFAULTS ON, IMPLICIT_TRANSACTIONS OFF, TEXTSIZE
// inf, ROWCOUNT inf)
(replication ? TDS.LOGIN_OPTION2_USER_SQLREPL_ON : TDS.LOGIN_OPTION2_USER_SQLREPL_OFF) |
(integratedSecurity ? // integrated security if integratedSecurity requested
TDS.LOGIN_OPTION2_INTEGRATED_SECURITY_ON
: TDS.LOGIN_OPTION2_INTEGRATED_SECURITY_OFF)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,18 @@ public String getApplicationIntent() {
SQLServerDriverStringProperty.APPLICATION_INTENT.getDefaultValue());
}

@Override
public void setReplication(boolean replication) {
setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.REPLICATION.toString(),
replication);
}

@Override
public boolean getReplication() {
return getBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.REPLICATION.toString(),
SQLServerDriverBooleanProperty.REPLICATION.getDefaultValue());
}

@Override
public void setSendTimeAsDatetime(boolean sendTimeAsDatetime) {
setBooleanProperty(connectionProps, SQLServerDriverBooleanProperty.SEND_TIME_AS_DATETIME.toString(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,7 @@ enum SQLServerDriverBooleanProperty {
INTEGRATED_SECURITY("integratedSecurity", false),
LAST_UPDATE_COUNT("lastUpdateCount", true),
MULTI_SUBNET_FAILOVER("multiSubnetFailover", false),
REPLICATION("replication", false),
SERVER_NAME_AS_ACE("serverNameAsACE", false),
SEND_STRING_PARAMETERS_AS_UNICODE("sendStringParametersAsUnicode", true),
SEND_TIME_AS_DATETIME("sendTimeAsDatetime", true),
Expand Down Expand Up @@ -589,6 +590,9 @@ public final class SQLServerDriver implements java.sql.Driver {
SQLServerDriverStringProperty.TRUST_MANAGER_CLASS.getDefaultValue(), false, null),
new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.TRUST_MANAGER_CONSTRUCTOR_ARG.toString(),
SQLServerDriverStringProperty.TRUST_MANAGER_CONSTRUCTOR_ARG.getDefaultValue(), false, null),
new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.REPLICATION.toString(),
Boolean.toString(SQLServerDriverBooleanProperty.REPLICATION.getDefaultValue()), false,
TRUE_FALSE),
new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.SEND_TIME_AS_DATETIME.toString(),
Boolean.toString(SQLServerDriverBooleanProperty.SEND_TIME_AS_DATETIME.getDefaultValue()), false,
TRUE_FALSE),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,8 @@ protected Object[][] getContents() {
"The optional argument to pass to the constructor specified by trustManagerClass."},
{"R_hostNameInCertificatePropertyDescription",
"The host name to be used when validating the SQL Server Secure Sockets Layer (SSL) certificate."},
{"R_replicationPropertyDescription",
"This setting tells the server if the connection is used for replication."},
{"R_sendTimeAsDatetimePropertyDescription",
"Determines whether to use the SQL Server datetime data type to send java.sql.Time values to the database."},
{"R_TransparentNetworkIPResolutionPropertyDescription",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,9 @@ public void testDataSource() {
ds.setApplicationIntent(stringPropValue);
assertEquals(stringPropValue, ds.getApplicationIntent(), TestResource.getResource("R_valuesAreDifferent"));

ds.setReplication(booleanPropValue);
assertEquals(booleanPropValue, ds.getReplication(), TestResource.getResource("R_valuesAreDifferent"));

ds.setSendTimeAsDatetime(booleanPropValue);
assertEquals(booleanPropValue, ds.getSendTimeAsDatetime(), TestResource.getResource("R_valuesAreDifferent"));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ public void testEscapeColumnDelimitersCSV() throws Exception {
i++;
}
}

TestUtils.dropTableIfExists(tableName, stmt);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* Microsoft JDBC Driver for SQL Server Copyright(c) Microsoft Corporation All rights reserved. This program is made
* available under the terms of the MIT License. See the LICENSE file in the project root for more information.
*/
package com.microsoft.sqlserver.jdbc.connection;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.platform.runner.JUnitPlatform;
import org.junit.runner.RunWith;

import com.microsoft.sqlserver.jdbc.RandomUtil;
import com.microsoft.sqlserver.jdbc.SQLServerDataSource;
import com.microsoft.sqlserver.jdbc.TestUtils;
import com.microsoft.sqlserver.testframework.AbstractSQLGenerator;
import com.microsoft.sqlserver.testframework.AbstractTest;
import com.microsoft.sqlserver.testframework.Constants;

/*
* This test is for testing the replication connection property
*/
@RunWith(JUnitPlatform.class)
@Tag(Constants.xAzureSQLDW)
public class ReplicationTest extends AbstractTest {

@Test
public void testReplication() throws SQLException {
String tableName = RandomUtil.getIdentifier("repl");
String triggerName = RandomUtil.getIdentifier("trig");
String escapedTableName = AbstractSQLGenerator.escapeIdentifier(tableName);
String escapedTriggerName = AbstractSQLGenerator.escapeIdentifier(triggerName);
SQLServerDataSource ds = new SQLServerDataSource();
ds.setURL(connectionString);
ds.setReplication(false);

String sqlCreateTable = "CREATE TABLE " + escapedTableName + " ([TestReplication] [varchar](50) NULL)";
String sqlCreateTrigger = "CREATE TRIGGER " + escapedTriggerName + " ON " + escapedTableName + " "
+ "INSTEAD OF INSERT NOT FOR REPLICATION AS "
+ "BEGIN "
+ " INSERT INTO " + escapedTableName + " (TestReplication) "
+ " SELECT TestReplication + ' - REPLICATION IS OFF' "
+ " FROM INSERTED "
+ "END";
String sqlInsert = "INSERT INTO " + escapedTableName + " (TestReplication) values ('Replication test')";
String sqlSelect = "SELECT TestReplication FROM " + escapedTableName;

try (Connection con = ds.getConnection(); Statement stmt = con.createStatement()) {
// drop
TestUtils.dropTableIfExists(escapedTableName, stmt);
// create
stmt.execute(sqlCreateTable);
stmt.execute(sqlCreateTrigger);
stmt.executeUpdate(sqlInsert);
try (ResultSet rs = stmt.executeQuery(sqlSelect)) {
if (rs.next()) {
assertEquals(rs.getString(1), "Replication test - REPLICATION IS OFF");
} else {
assertTrue(false, "Expected row of data was not found.");
}
}
TestUtils.clearTable(con, escapedTableName);
}

ds.setReplication(true);
try (Connection con = ds.getConnection(); Statement stmt = con.createStatement()) {
stmt.executeUpdate(sqlInsert);
try (ResultSet rs = stmt.executeQuery(sqlSelect)) {
if (rs.next()) {
assertEquals(rs.getString(1), "Replication test");
} else {
assertTrue(false, "Expected row of data was not found.");
}
}
TestUtils.dropTableIfExists(escapedTableName, stmt);
}
}
}