-
Notifications
You must be signed in to change notification settings - Fork 118
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add SQL Server JDBC support (#263)
* add support for mssql-jdbc driver * update artifact name and mssql-jdbc version * added integration tests for sqlserver * split jdbc and r2dbc connectors into separate folders * update mssql driver verison * added relative path to parent section of pom.xml * update integration tests * sqlserver integration tests * move core out of jdbc folder * remove folder restructuring * remove relativePath from poms other than sqlserver * Update sqlserver/pom.xml Co-authored-by: Kurtis Van Gent <[email protected]> * add dependency info for SQL server to README Co-authored-by: Kurtis Van Gent <[email protected]>
- Loading branch information
1 parent
062278c
commit 2a60a67
Showing
6 changed files
with
300 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<parent> | ||
<groupId>com.google.cloud.sql</groupId> | ||
<artifactId>jdbc-socket-factory-parent</artifactId> | ||
<version>1.1.1-SNAPSHOT</version> <!-- {x-version-update:cloud-sql-java-connector:current} --> | ||
<relativePath>..</relativePath> | ||
</parent> | ||
<artifactId>cloud-sql-connector-jdbc-sqlserver</artifactId> | ||
<packaging>jar</packaging> | ||
|
||
<name>Cloud SQL JDBC connector for SQL Server</name> | ||
<description> | ||
Socket factory for the Microsoft JDBC Driver for SQL Server that allows a user with the | ||
appropriate permissions to connect to a Cloud SQL database without having to deal with IP | ||
allowlisting or SSL certificates manually. | ||
</description> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>com.microsoft.sqlserver</groupId> | ||
<artifactId>mssql-jdbc</artifactId> | ||
<version>9.1.0.jre8-preview</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.google.cloud.sql</groupId> | ||
<artifactId>jdbc-socket-factory-core</artifactId> | ||
<version>1.1.1-SNAPSHOT</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>junit</groupId> | ||
<artifactId>junit</artifactId> | ||
<version>4.13.1</version> | ||
<scope>test</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.google.truth</groupId> | ||
<artifactId>truth</artifactId> | ||
<version>1.0.1</version> | ||
<scope>test</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>com.zaxxer</groupId> | ||
<artifactId>HikariCP</artifactId> | ||
<version>3.4.5</version> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
|
||
<profiles> | ||
<profile> | ||
<id>jar-with-driver-and-dependencies</id> | ||
<dependencies> | ||
<dependency> | ||
<groupId>com.microsoft.sqlserver</groupId> | ||
<artifactId>mssql-jdbc</artifactId> | ||
<version>9.1.0-SNAPSHOT</version> | ||
</dependency> | ||
</dependencies> | ||
</profile> | ||
</profiles> | ||
|
||
</project> |
71 changes: 71 additions & 0 deletions
71
sqlserver/src/main/java/com.google.cloud.sql.sqlserver/SocketFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
/* | ||
* Copyright 2020 Google Inc. All Rights Reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package com.google.cloud.sql.sqlserver; | ||
|
||
import com.google.cloud.sql.core.CoreSocketFactory; | ||
import java.io.IOException; | ||
import java.net.InetAddress; | ||
import java.net.Socket; | ||
import java.util.Properties; | ||
import java.util.logging.Logger; | ||
|
||
public class SocketFactory extends javax.net.SocketFactory { | ||
|
||
private static final Logger logger = Logger.getLogger(SocketFactory.class.getName()); | ||
private Properties props = new Properties(); | ||
|
||
static { | ||
CoreSocketFactory.addArtifactId("cloud-sql-connector-jdbc-sqlserver"); | ||
} | ||
|
||
/** | ||
* Implements the {@link SocketFactory} constructor, which can be used to create authenticated | ||
* connections to a Cloud SQL instance. | ||
*/ | ||
public SocketFactory(String instanceName) { | ||
this.props.setProperty(CoreSocketFactory.CLOUD_SQL_INSTANCE_PROPERTY, instanceName); | ||
} | ||
|
||
@Override | ||
public Socket createSocket() throws IOException { | ||
return CoreSocketFactory.connect(props); | ||
} | ||
|
||
@Override | ||
public Socket createSocket(String host, int port) throws IOException { | ||
throw new UnsupportedOperationException(); | ||
} | ||
|
||
@Override | ||
public Socket createSocket(String host, int port, InetAddress localHost, int localPort) | ||
throws IOException { | ||
throw new UnsupportedOperationException(); | ||
} | ||
|
||
@Override | ||
public Socket createSocket(InetAddress host, int port) throws IOException { | ||
throw new UnsupportedOperationException(); | ||
} | ||
|
||
@Override | ||
public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) | ||
throws IOException { | ||
throw new UnsupportedOperationException(); | ||
} | ||
} | ||
|
||
|
139 changes: 139 additions & 0 deletions
139
sqlserver/src/test/java/com/google/cloud/sql/sqlserver/JdbcSqlServerIntegrationTests.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
/* | ||
* Copyright 2020 Google LLC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package com.google.cloud.sql.sqlserver; | ||
|
||
|
||
import static com.google.common.truth.Truth.assertThat; | ||
import static com.google.common.truth.Truth.assertWithMessage; | ||
|
||
import com.google.common.collect.ImmutableList; | ||
import com.zaxxer.hikari.HikariConfig; | ||
import com.zaxxer.hikari.HikariDataSource; | ||
import java.sql.Connection; | ||
import java.sql.PreparedStatement; | ||
import java.sql.ResultSet; | ||
import java.sql.SQLException; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.Properties; | ||
import java.util.UUID; | ||
import java.util.concurrent.TimeUnit; | ||
import org.junit.After; | ||
import org.junit.Before; | ||
import org.junit.BeforeClass; | ||
import org.junit.Rule; | ||
import org.junit.Test; | ||
import org.junit.rules.Timeout; | ||
import org.junit.runner.RunWith; | ||
import org.junit.runners.JUnit4; | ||
|
||
|
||
@RunWith(JUnit4.class) | ||
public class JdbcSqlServerIntegrationTests { | ||
|
||
private static final String CONNECTION_NAME = System.getenv("SQLSERVER_CONNECTION_NAME"); | ||
private static final String DB_NAME = System.getenv("SQLSERVER_DB"); | ||
private static final String DB_USER = System.getenv("SQLSERVER_USER"); | ||
private static final String DB_PASSWORD = System.getenv("SQLSERVER_PASS"); | ||
private static ImmutableList<String> requiredEnvVars = ImmutableList | ||
.of("SQLSERVER_USER", "SQLSERVER_PASS", "SQLSERVER_DB", "SQLSERVER_CONNECTION_NAME"); | ||
@Rule | ||
public Timeout globalTimeout = new Timeout(20, TimeUnit.SECONDS); | ||
|
||
private HikariDataSource connectionPool; | ||
private String tableName; | ||
|
||
@BeforeClass | ||
public static void checkEnvVars() { | ||
// Check that required env vars are set | ||
requiredEnvVars.stream().forEach((varName) -> { | ||
assertWithMessage( | ||
String.format("Environment variable '%s' must be set to perform these tests.", varName)) | ||
.that(System.getenv(varName)).isNotEmpty(); | ||
}); | ||
} | ||
|
||
@Before | ||
public void setUpPool() throws SQLException { | ||
|
||
// Initialize connection pool | ||
HikariConfig config = new HikariConfig(); | ||
config | ||
.setDataSourceClassName("com.microsoft.sqlserver.jdbc.SQLServerDataSource"); | ||
config.setUsername(DB_USER); // e.g. "root", "sqlserver" | ||
config.setPassword(DB_PASSWORD); // e.g. "my-password" | ||
config.addDataSourceProperty("databaseName", DB_NAME); | ||
|
||
config.addDataSourceProperty("socketFactoryClass", | ||
"com.google.cloud.sql.sqlserver.SocketFactory"); | ||
config.addDataSourceProperty("socketFactoryConstructorArg", CONNECTION_NAME); | ||
|
||
this.connectionPool = new HikariDataSource(config); | ||
this.tableName = String.format("books_%s", UUID.randomUUID().toString().replace("-", "")); | ||
|
||
// Create table | ||
try (Connection conn = connectionPool.getConnection()) { | ||
String stmt = String.format("CREATE TABLE %s (", this.tableName) | ||
+ " ID CHAR(20) NOT NULL," | ||
+ " TITLE TEXT NOT NULL" | ||
+ ");"; | ||
try (PreparedStatement createTableStatement = conn.prepareStatement(stmt)) { | ||
createTableStatement.execute(); | ||
} | ||
} | ||
} | ||
|
||
|
||
@After | ||
public void dropTableIfPresent() throws SQLException { | ||
try (Connection conn = connectionPool.getConnection()) { | ||
String stmt = String.format("DROP TABLE %s;", this.tableName); | ||
try (PreparedStatement dropTableStatement = conn.prepareStatement(stmt)) { | ||
dropTableStatement.execute(); | ||
} | ||
} | ||
} | ||
|
||
@Test | ||
public void pooledConnectionTest() throws SQLException { | ||
try (Connection conn = connectionPool.getConnection()) { | ||
String stmt = String.format("INSERT INTO %s (ID, TITLE) VALUES (?, ?)", this.tableName); | ||
try (PreparedStatement insertStmt = conn.prepareStatement(stmt)) { | ||
insertStmt.setString(1, "book1"); | ||
insertStmt.setString(2, "Book One"); | ||
insertStmt.execute(); | ||
insertStmt.setString(1, "book2"); | ||
insertStmt.setString(2, "Book Two"); | ||
insertStmt.execute(); | ||
} | ||
} | ||
|
||
List<String> bookList = new ArrayList<>(); | ||
try (Connection conn = connectionPool.getConnection()) { | ||
String stmt = String.format("SELECT TITLE FROM %s ORDER BY ID", this.tableName); | ||
try (PreparedStatement selectStmt = conn.prepareStatement(stmt)) { | ||
|
||
ResultSet rs = selectStmt.executeQuery(); | ||
while (rs.next()) { | ||
bookList.add(rs.getString("TITLE")); | ||
} | ||
} | ||
} | ||
assertThat(bookList).containsExactly("Book One", "Book Two"); | ||
|
||
} | ||
} |