Skip to content

Commit

Permalink
Merge branch 'master' into Snow-1213120-Reuse-Connections-3
Browse files Browse the repository at this point in the history
  • Loading branch information
sfc-gh-ext-simba-jf committed Aug 8, 2024
2 parents 426d93c + 585ea31 commit 8e27bb0
Show file tree
Hide file tree
Showing 45 changed files with 2,622 additions and 911 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ snowflake-whitelist
Golang
ClientTelemetryFramework
lib/*
.wiremock/**

# WhiteSource Scan
wss*.config
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
**JDBC Driver 3.18.0**

- \||Please Refer to Release Notes at https://docs.snowflake.com/en/release-notes/clients-drivers/jdbc

**JDBC Driver 3.17.0**

- \||Please Refer to Release Notes at https://docs.snowflake.com/en/release-notes/clients-drivers/jdbc
Expand Down
4 changes: 2 additions & 2 deletions FIPS/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
<parent>
<groupId>net.snowflake</groupId>
<artifactId>snowflake-jdbc-parent</artifactId>
<version>3.17.1-SNAPSHOT</version>
<version>3.18.1-SNAPSHOT</version>
<relativePath>../parent-pom.xml</relativePath>
</parent>

<artifactId>snowflake-jdbc-fips</artifactId>
<version>3.17.1-SNAPSHOT</version>
<version>3.18.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>snowflake-jdbc-fips</name>
Expand Down
13 changes: 12 additions & 1 deletion parent-pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

<groupId>net.snowflake</groupId>
<artifactId>snowflake-jdbc-parent</artifactId>
<version>3.17.1-SNAPSHOT</version>
<version>3.18.1-SNAPSHOT</version>
<packaging>pom</packaging>

<modules>
Expand Down Expand Up @@ -102,6 +102,7 @@
<version.plugin.sortpom>3.0.1</version.plugin.sortpom>
<version.plugin.source>3.2.1</version.plugin.source>
<version.plugin.surefire>3.0.0</version.plugin.surefire>
<version.plugin.wiremock>3.8.0</version.plugin.wiremock>
</properties>

<dependencyManagement>
Expand Down Expand Up @@ -507,6 +508,12 @@
<version>${version.plugin.surefire}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.wiremock</groupId>
<artifactId>wiremock-standalone</artifactId>
<version>${version.plugin.wiremock}</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>

Expand Down Expand Up @@ -757,5 +764,9 @@
<groupId>org.apache.maven.surefire</groupId>
<artifactId>common-junit48</artifactId>
</dependency>
<dependency>
<groupId>org.wiremock</groupId>
<artifactId>wiremock-standalone</artifactId>
</dependency>
</dependencies>
</project>
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
<parent>
<groupId>net.snowflake</groupId>
<artifactId>snowflake-jdbc-parent</artifactId>
<version>3.17.1-SNAPSHOT</version>
<version>3.18.1-SNAPSHOT</version>
<relativePath>./parent-pom.xml</relativePath>
</parent>

<!-- Maven complains about using property here, but it makes install and deploy process easier to override final package names and localization -->
<artifactId>${artifactId}</artifactId>
<version>3.17.1-SNAPSHOT</version>
<version>3.18.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>${artifactId}</name>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,11 @@ private static void verifyFilePermissionSecure(Path configFilePath)
Arrays.asList(PosixFilePermission.OWNER_WRITE, PosixFilePermission.OWNER_READ)
.contains(o))) {
logger.error(
"Reading from file {} is not safe because of insufficient permissions", configFilePath);
"Reading from file %s is not safe because file permissions are different than read/write for user",
configFilePath);
throw new SnowflakeSQLException(
String.format(
"Reading from file %s is not safe because of insufficient permissions",
"Reading from file %s is not safe because file permissions are different than read/write for user",
configFilePath));
}
}
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/net/snowflake/client/core/SFLoginInput.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,22 @@ public class SFLoginInput {
private boolean disableConsoleLogin = true;
private boolean disableSamlURLCheck = false;

private Duration browserResponseTimeout;

// Additional headers to add for Snowsight.
Map<String, String> additionalHttpHeadersForSnowsight;

SFLoginInput() {}

Duration getBrowserResponseTimeout() {
return browserResponseTimeout;
}

SFLoginInput setBrowserResponseTimeout(Duration browserResponseTimeout) {
this.browserResponseTimeout = browserResponseTimeout;
return this;
}

public String getServerUrl() {
return serverUrl;
}
Expand Down
21 changes: 18 additions & 3 deletions src/main/java/net/snowflake/client/core/SFSession.java
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,13 @@ public class SFSession extends SFBaseSession {
*/
private int retryTimeout = 300;

/**
* Max timeout for external browser authentication in seconds
*
* <p>Default: 120
*/
private Duration browserResponseTimeout = Duration.ofSeconds(120);

// This constructor is used only by tests with no real connection.
// For real connections, the other constructor is always used.
@VisibleForTesting
Expand Down Expand Up @@ -489,6 +496,12 @@ public void addSFSessionProperty(String propertyName, Object propertyValue) thro
}
break;

case BROWSER_RESPONSE_TIMEOUT:
if (propertyValue != null) {
browserResponseTimeout = Duration.ofSeconds((Integer) propertyValue);
}
break;

case JDBC_DEFAULT_FORMAT_DATE_WITH_TIMEZONE:
if (propertyValue != null) {
setDefaultFormatDateWithTimezone(getBooleanValue(propertyValue));
Expand Down Expand Up @@ -542,7 +555,7 @@ public synchronized void open() throws SFException, SnowflakeSQLException {
+ " application: {}, app id: {}, app version: {}, login timeout: {}, retry timeout: {}, network timeout: {},"
+ " query timeout: {}, tracing: {}, private key file: {}, private key file pwd is {},"
+ " enable_diagnostics: {}, diagnostics_allowlist_path: {},"
+ " session parameters: client store temporary credential: {}, gzip disabled: {}",
+ " session parameters: client store temporary credential: {}, gzip disabled: {}, browser response timeout: {}",
connectionPropertiesMap.get(SFSessionProperty.SERVER_URL),
connectionPropertiesMap.get(SFSessionProperty.ACCOUNT),
connectionPropertiesMap.get(SFSessionProperty.USER),
Expand Down Expand Up @@ -574,7 +587,8 @@ public synchronized void open() throws SFException, SnowflakeSQLException {
connectionPropertiesMap.get(SFSessionProperty.ENABLE_DIAGNOSTICS),
connectionPropertiesMap.get(SFSessionProperty.DIAGNOSTICS_ALLOWLIST_FILE),
sessionParametersMap.get(CLIENT_STORE_TEMPORARY_CREDENTIAL),
connectionPropertiesMap.get(SFSessionProperty.GZIP_DISABLED));
connectionPropertiesMap.get(SFSessionProperty.GZIP_DISABLED),
connectionPropertiesMap.get(SFSessionProperty.BROWSER_RESPONSE_TIMEOUT));

HttpClientSettingsKey httpClientSettingsKey = getHttpClientKey();
logger.debug(
Expand Down Expand Up @@ -632,7 +646,8 @@ public synchronized void open() throws SFException, SnowflakeSQLException {
connectionPropertiesMap.get(SFSessionProperty.DISABLE_SAML_URL_CHECK) != null
? getBooleanValue(
connectionPropertiesMap.get(SFSessionProperty.DISABLE_SAML_URL_CHECK))
: false);
: false)
.setBrowserResponseTimeout(browserResponseTimeout);

logger.info(
"Connecting to {} Snowflake domain",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,9 @@ public enum SFSessionProperty {
"JDBC_DEFAULT_FORMAT_DATE_WITH_TIMEZONE", false, Boolean.class),

// Used as a fix for issue SNOW-354859. Remove with snowflake-jdbc version 4.x with BCR changes.
JDBC_GET_DATE_USE_NULL_TIMEZONE("JDBC_GET_DATE_USE_NULL_TIMEZONE", false, Boolean.class);
JDBC_GET_DATE_USE_NULL_TIMEZONE("JDBC_GET_DATE_USE_NULL_TIMEZONE", false, Boolean.class),

BROWSER_RESPONSE_TIMEOUT("BROWSER_RESPONSE_TIMEOUT", false, Integer.class);

// property key in string
private String propertyKey;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
Expand Down Expand Up @@ -256,6 +257,10 @@ private String generateProofKey() {
return Base64.getEncoder().encodeToString(randomness);
}

private int getBrowserResponseTimeout() {
return (int) loginInput.getBrowserResponseTimeout().toMillis();
}

/**
* Authenticate
*
Expand All @@ -265,6 +270,7 @@ private String generateProofKey() {
void authenticate() throws SFException, SnowflakeSQLException {
ServerSocket ssocket = this.getServerSocket();
try {
ssocket.setSoTimeout(getBrowserResponseTimeout());
// main procedure
int port = this.getLocalPort(ssocket);
logger.debug("Listening localhost: {}", port);
Expand Down Expand Up @@ -305,6 +311,13 @@ void authenticate() throws SFException, SnowflakeSQLException {
socket.close();
}
}
} catch (SocketTimeoutException e) {
throw new SFException(
e,
ErrorCode.NETWORK_ERROR,
"External browser authentication failed within timeout of "
+ getBrowserResponseTimeout()
+ " milliseconds");
} catch (IOException ex) {
throw new SFException(ex, ErrorCode.NETWORK_ERROR, ex.getMessage());
} finally {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/
package net.snowflake.client.core;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
Expand All @@ -19,4 +20,5 @@
ElementType.METHOD
})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SnowflakeJdbcInternalApi {}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@ public class SnowflakeBasicDataSource implements DataSource, Serializable {
private static final long serialversionUID = 1L;
private static final String AUTHENTICATOR_SNOWFLAKE_JWT = "SNOWFLAKE_JWT";
private static final String AUTHENTICATOR_OAUTH = "OAUTH";

private static final String AUTHENTICATOR_EXTERNAL_BROWSER = "EXTERNALBROWSER";

private static final String AUTHENTICATOR_USERNAME_PASSWORD_MFA = "USERNAME_PASSWORD_MFA";

private String url;

private String serverName;
Expand Down Expand Up @@ -94,7 +98,8 @@ public Connection getConnection(String username, String password) throws SQLExce
}

// The driver needs password for OAUTH as part of SNOW-533673 feature request.
if (!AUTHENTICATOR_SNOWFLAKE_JWT.equalsIgnoreCase(authenticator)) {
if (!AUTHENTICATOR_SNOWFLAKE_JWT.equalsIgnoreCase(authenticator)
&& !AUTHENTICATOR_EXTERNAL_BROWSER.equalsIgnoreCase(authenticator)) {
properties.put(SFSessionProperty.PASSWORD.getPropertyKey(), password);
}

Expand Down Expand Up @@ -380,4 +385,9 @@ public void setJDBCDefaultFormatDateWithTimezone(Boolean jdbcDefaultFormatDateWi
public void setGetDateUseNullTimezone(Boolean getDateUseNullTimezone) {
this.properties.put("JDBC_GET_DATE_USE_NULL_TIMEZONE", getDateUseNullTimezone);
}

public void setBrowserResponseTimeout(int seconds) {
this.setAuthenticator(AUTHENTICATOR_EXTERNAL_BROWSER);
this.properties.put("BROWSER_RESPONSE_TIMEOUT", Integer.toString(seconds));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,16 @@

package net.snowflake.client.jdbc;

import static net.snowflake.client.jdbc.SnowflakeUtil.getFieldMetadata;
import static net.snowflake.client.jdbc.SnowflakeUtil.getSnowflakeType;
import static net.snowflake.client.jdbc.SnowflakeUtil.isVectorType;

import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.base.Strings;
import java.io.Serializable;
import java.sql.Types;
import java.util.List;
import net.snowflake.client.core.SFBaseSession;
import net.snowflake.client.core.SnowflakeJdbcInternalApi;

/**
Expand Down Expand Up @@ -99,6 +107,57 @@ public SnowflakeColumnMetadata(
this.isAutoIncrement = isAutoIncrement;
}

@SnowflakeJdbcInternalApi
public SnowflakeColumnMetadata(
JsonNode colNode, boolean jdbcTreatDecimalAsInt, SFBaseSession session)
throws SnowflakeSQLLoggedException {
this.name = colNode.path("name").asText();
this.nullable = colNode.path("nullable").asBoolean();
this.precision = colNode.path("precision").asInt();
this.scale = colNode.path("scale").asInt();
this.length = colNode.path("length").asInt();
int dimension =
colNode
.path("dimension")
.asInt(); // vector dimension when checking columns via connection.getMetadata
int vectorDimension =
colNode
.path("vectorDimension")
.asInt(); // dimension when checking columns via resultSet.getMetadata
this.dimension = dimension > 0 ? dimension : vectorDimension;
this.fixed = colNode.path("fixed").asBoolean();
JsonNode udtOutputType = colNode.path("outputType");
JsonNode extColTypeNameNode = colNode.path("extTypeName");
String extColTypeName = null;
if (!extColTypeNameNode.isMissingNode()
&& !Strings.isNullOrEmpty(extColTypeNameNode.asText())) {
extColTypeName = extColTypeNameNode.asText();
}
String internalColTypeName = colNode.path("type").asText();
List<FieldMetadata> fieldsMetadata =
getFieldMetadata(jdbcTreatDecimalAsInt, internalColTypeName, colNode);

int fixedColType = jdbcTreatDecimalAsInt && scale == 0 ? Types.BIGINT : Types.DECIMAL;
ColumnTypeInfo columnTypeInfo =
getSnowflakeType(
internalColTypeName,
extColTypeName,
udtOutputType,
session,
fixedColType,
!fieldsMetadata.isEmpty(),
isVectorType(internalColTypeName));

this.typeName = columnTypeInfo.getExtColTypeName();
this.type = columnTypeInfo.getColumnType();
this.base = columnTypeInfo.getSnowflakeType();
this.fields = fieldsMetadata;
this.columnSrcDatabase = colNode.path("database").asText();
this.columnSrcSchema = colNode.path("schema").asText();
this.columnSrcTable = colNode.path("table").asText();
this.isAutoIncrement = colNode.path("isAutoIncrement").asBoolean();
}

public String getName() {
return name;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1825,8 +1825,7 @@ public boolean next() throws SQLException {
logger.debug("Data type string: {}", dataTypeStr);

SnowflakeColumnMetadata columnMetadata =
SnowflakeUtil.extractColumnMetadata(
jsonNode, session.isJdbcTreatDecimalAsInt(), session);
new SnowflakeColumnMetadata(jsonNode, session.isJdbcTreatDecimalAsInt(), session);

logger.debug("Nullable: {}", columnMetadata.isNullable());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public class SnowflakeDriver implements Driver {
static SnowflakeDriver INSTANCE;

public static final Properties EMPTY_PROPERTIES = new Properties();
public static String implementVersion = "3.17.1";
public static String implementVersion = "3.18.1";

static int majorVersion = 0;
static int minorVersion = 0;
Expand Down
Loading

0 comments on commit 8e27bb0

Please sign in to comment.