diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 199e5cedd..f3e0c7747 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,59 +1,59 @@ **JDBC Driver 3.15.0** -- \||Please Refer to Release Notes at https://docs.snowflake.com/en/release-notes/clients-drivers/jdbc +- \||Please Refer to Release Notes at https://community.snowflake.com/s/article/JDBC-Driver-Release-Notes **JDBC Driver 3.14.5** -- \||Please Refer to Release Notes at https://docs.snowflake.com/en/release-notes/clients-drivers/jdbc +- \||Please Refer to Release Notes at https://community.snowflake.com/s/article/JDBC-Driver-Release-Notes **JDBC Driver 3.14.4** -- \||Please Refer to Release Notes at https://docs.snowflake.com/en/release-notes/clients-drivers/jdbc +- \||Please Refer to Release Notes at https://community.snowflake.com/s/article/JDBC-Driver-Release-Notes **JDBC Driver 3.14.3** -- \||Please Refer to Release Notes at https://docs.snowflake.com/en/release-notes/clients-drivers/jdbc +- \||Please Refer to Release Notes at https://community.snowflake.com/s/article/JDBC-Driver-Release-Notes **JDBC Driver 3.14.2** -- \||Please Refer to Release Notes at https://docs.snowflake.com/en/release-notes/clients-drivers/jdbc +- \||Please Refer to Release Notes at https://community.snowflake.com/s/article/JDBC-Driver-Release-Notes **JDBC Driver 3.14.1** -- \||Please Refer to Release Notes at https://docs.snowflake.com/en/release-notes/clients-drivers/jdbc +- \||Please Refer to Release Notes at https://community.snowflake.com/s/article/JDBC-Driver-Release-Notes **JDBC Driver 3.14.0** -- \||Please Refer to Release Notes at https://docs.snowflake.com/en/release-notes/clients-drivers/jdbc +- \||Please Refer to Release Notes at https://community.snowflake.com/s/article/JDBC-Driver-Release-Notes **JDBC Driver 3.13.33** -- \|| Please Refer to Release Notes at https://docs.snowflake.com/en/release-notes/clients-drivers/jdbc +- \|| Please Refer to Release Notes at https://community.snowflake.com/s/article/JDBC-Driver-Release-Notes **JDBC Driver 3.13.32** -- \|| Please Refer to Release Notes at https://docs.snowflake.com/en/release-notes/clients-drivers/jdbc +- \|| Please Refer to Release Notes at https://community.snowflake.com/s/article/JDBC-Driver-Release-Notes **JDBC Driver 3.13.31** -- \|| Please Refer to Release Notes at https://docs.snowflake.com/en/release-notes/clients-drivers/jdbc +- \|| Please Refer to Release Notes at https://community.snowflake.com/s/article/JDBC-Driver-Release-Notes **JDBC Driver 3.13.30** -- \|| Please Refer to Release Notes at https://docs.snowflake.com/en/release-notes/clients-drivers/jdbc +- \|| Please Refer to Release Notes at https://community.snowflake.com/s/article/JDBC-Driver-Release-Notes **JDBC Driver 3.13.29** -- \|| Please Refer to Release Notes at https://docs.snowflake.com/en/release-notes/clients-drivers/jdbc +- \|| Please Refer to Release Notes at https://community.snowflake.com/s/article/JDBC-Driver-Release-Notes **JDBC Driver 3.13.28** -- \|| Please Refer to Release Notes at https://docs.snowflake.com/en/release-notes/clients-drivers/jdbc +- \|| Please Refer to Release Notes at https://community.snowflake.com/s/article/JDBC-Driver-Release-Notes **JDBC Driver 3.13.27** -- \|| Please Refer to Release Notes at https://docs.snowflake.com/en/release-notes/clients-drivers/jdbc +- \|| Please Refer to Release Notes at https://community.snowflake.com/s/article/JDBC-Driver-Release-Notes **JDBC Driver 3.13.26** diff --git a/parent-pom.xml b/parent-pom.xml index ff8ee40f9..cceedf9cd 100644 --- a/parent-pom.xml +++ b/parent-pom.xml @@ -38,7 +38,6 @@ 1.5.4 0.9.5.4 2.22.0 - 1.19.0 2.21.0 2.22.6 2.10.1 @@ -162,11 +161,6 @@ proto-google-common-protos ${google.api.grpc.version} - - com.google.auth - google-auth-library-oauth2-http - ${google.auth.library.oauth2.http.version} - com.google.cloud google-cloud-core @@ -520,10 +514,6 @@ com.google.api gax - - com.google.auth - google-auth-library-oauth2-http - com.google.cloud google-cloud-core diff --git a/src/main/java/net/snowflake/client/core/JsonSqlInput.java b/src/main/java/net/snowflake/client/core/JsonSqlInput.java index 0ae79096a..2430d0c7f 100644 --- a/src/main/java/net/snowflake/client/core/JsonSqlInput.java +++ b/src/main/java/net/snowflake/client/core/JsonSqlInput.java @@ -190,9 +190,11 @@ public Timestamp readTimestamp(TimeZone tz) throws SQLException { int columnType = ColumnTypeHelper.getColumnType(fieldMetadata.getType(), session); int columnSubType = fieldMetadata.getType(); int scale = fieldMetadata.getScale(); + Timestamp result = SqlInputTimestampUtil.getTimestampFromType( columnSubType, (String) value, session, sessionTimeZone, tz); + if (result != null) { return result; } diff --git a/src/main/java/net/snowflake/client/core/SFArrowResultSet.java b/src/main/java/net/snowflake/client/core/SFArrowResultSet.java index 5bb67919e..852e187b4 100644 --- a/src/main/java/net/snowflake/client/core/SFArrowResultSet.java +++ b/src/main/java/net/snowflake/client/core/SFArrowResultSet.java @@ -13,7 +13,6 @@ import java.io.IOException; import java.math.BigDecimal; import java.math.RoundingMode; -import java.sql.Array; import java.sql.Date; import java.sql.SQLException; import java.sql.SQLInput; diff --git a/src/main/java/net/snowflake/client/core/SFBaseResultSet.java b/src/main/java/net/snowflake/client/core/SFBaseResultSet.java index 24756bbc7..0a0dd35a2 100644 --- a/src/main/java/net/snowflake/client/core/SFBaseResultSet.java +++ b/src/main/java/net/snowflake/client/core/SFBaseResultSet.java @@ -11,7 +11,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import java.math.BigDecimal; -import java.sql.Array; import java.sql.Date; import java.sql.SQLException; import java.sql.SQLInput; diff --git a/src/main/java/net/snowflake/client/core/SFBaseSession.java b/src/main/java/net/snowflake/client/core/SFBaseSession.java index b0da3e9b4..d0bfeda9d 100644 --- a/src/main/java/net/snowflake/client/core/SFBaseSession.java +++ b/src/main/java/net/snowflake/client/core/SFBaseSession.java @@ -137,9 +137,6 @@ public abstract class SFBaseSession { // we need to allow for it to maintain backwards compatibility. private boolean enablePatternSearch = true; - /** Disable lookup for default credentials by GCS library */ - private boolean disableGcsDefaultCredentials = false; - private Map commonParameters; private boolean isJdbcArrowTreatDecimalAsInt = true; @@ -748,14 +745,6 @@ public void setEnablePatternSearch(boolean enablePatternSearch) { this.enablePatternSearch = enablePatternSearch; } - public boolean getDisableGcsDefaultCredentials() { - return disableGcsDefaultCredentials; - } - - public void setDisableGcsDefaultCredentials(boolean disableGcsDefaultCredentials) { - this.disableGcsDefaultCredentials = disableGcsDefaultCredentials; - } - public int getClientResultChunkSize() { return clientResultChunkSize; } diff --git a/src/main/java/net/snowflake/client/core/SFJsonResultSet.java b/src/main/java/net/snowflake/client/core/SFJsonResultSet.java index 181492294..48bb16e33 100644 --- a/src/main/java/net/snowflake/client/core/SFJsonResultSet.java +++ b/src/main/java/net/snowflake/client/core/SFJsonResultSet.java @@ -7,7 +7,6 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import java.math.BigDecimal; -import java.sql.Array; import java.sql.Date; import java.sql.SQLInput; import java.sql.Time; @@ -88,6 +87,7 @@ public Object getObject(int columnIndex) throws SFException { } else { throw new SFException(ErrorCode.FEATURE_UNSUPPORTED, "data type: " + type); } + case Types.ARRAY: if (StructureTypeHelper.isStructureTypeEnabled()) { return getArray(columnIndex); diff --git a/src/main/java/net/snowflake/client/core/SFResultSet.java b/src/main/java/net/snowflake/client/core/SFResultSet.java index b7698cf5d..77f30ddd7 100644 --- a/src/main/java/net/snowflake/client/core/SFResultSet.java +++ b/src/main/java/net/snowflake/client/core/SFResultSet.java @@ -155,7 +155,22 @@ public SFResultSet( Telemetry telemetryClient, boolean sortResult) throws SQLException { - super(resultSetSerializable.getTimeZone(), new Converters(session, resultSetSerializable)); + super( + resultSetSerializable.getTimeZone(), + new Converters( + resultSetSerializable.getTimeZone(), + session, + resultSetSerializable.getResultVersion(), + resultSetSerializable.isHonorClientTZForTimestampNTZ(), + resultSetSerializable.getTreatNTZAsUTC(), + resultSetSerializable.getUseSessionTimezone(), + resultSetSerializable.getFormatDateWithTimeZone(), + resultSetSerializable.getBinaryFormatter(), + resultSetSerializable.getDateFormatter(), + resultSetSerializable.getTimeFormatter(), + resultSetSerializable.getTimestampNTZFormatter(), + resultSetSerializable.getTimestampLTZFormatter(), + resultSetSerializable.getTimestampTZFormatter())); this.resultSetSerializable = resultSetSerializable; this.columnCount = 0; this.sortResult = sortResult; diff --git a/src/main/java/net/snowflake/client/core/SFResultSetMetaData.java b/src/main/java/net/snowflake/client/core/SFResultSetMetaData.java index ce129788b..dfb621400 100644 --- a/src/main/java/net/snowflake/client/core/SFResultSetMetaData.java +++ b/src/main/java/net/snowflake/client/core/SFResultSetMetaData.java @@ -473,8 +473,7 @@ public List getIsAutoIncrementList() { return isAutoIncrementList; } - @SnowflakeJdbcInternalApi - public List getColumnMetadata() { + List getColumnMetadata() { return columnMetadata; } } diff --git a/src/main/java/net/snowflake/client/core/SFSession.java b/src/main/java/net/snowflake/client/core/SFSession.java index d7ee69a07..a0c25c213 100644 --- a/src/main/java/net/snowflake/client/core/SFSession.java +++ b/src/main/java/net/snowflake/client/core/SFSession.java @@ -469,11 +469,6 @@ public void addSFSessionProperty(String propertyName, Object propertyValue) thro setEnablePatternSearch(getBooleanValue(propertyValue)); } break; - case DISABLE_GCS_DEFAULT_CREDENTIALS: - if (propertyValue != null) { - setDisableGcsDefaultCredentials(getBooleanValue(propertyValue)); - } - break; case JDBC_ARROW_TREAT_DECIMAL_AS_INT: if (propertyValue != null) { diff --git a/src/main/java/net/snowflake/client/core/SessionUtil.java b/src/main/java/net/snowflake/client/core/SessionUtil.java index 9a51cd8ae..88020f6f0 100644 --- a/src/main/java/net/snowflake/client/core/SessionUtil.java +++ b/src/main/java/net/snowflake/client/core/SessionUtil.java @@ -401,7 +401,21 @@ private static SFLoginOutput newSession( } } else if (authenticatorType == ClientAuthnDTO.AuthenticatorType.OKTA) { // okta authenticator v1 - tokenOrSamlResponse = getSamlResponseUsingOkta(loginInput); + while (true) { + try { + tokenOrSamlResponse = getSamlResponseUsingOkta(loginInput); + } catch (SnowflakeSQLException ex) { + // This error gets thrown if the okta request encountered a retry-able error that + // requires getting a new one-time token. + if (ex.getErrorCode() == ErrorCode.AUTHENTICATOR_REQUEST_TIMEOUT.getMessageCode()) { + logger.debug("Failed to get Okta SAML response. Retrying."); + continue; + } else { + throw ex; + } + } + break; + } } else if (authenticatorType == ClientAuthnDTO.AuthenticatorType.SNOWFLAKE_JWT) { SessionUtilKeyPair s = new SessionUtilKeyPair( @@ -651,16 +665,31 @@ private static SFLoginOutput newSession( loginInput.getHttpClientSettingsKey()); } catch (SnowflakeSQLException ex) { if (ex.getErrorCode() == ErrorCode.AUTHENTICATOR_REQUEST_TIMEOUT.getMessageCode()) { - if (authenticatorType == ClientAuthnDTO.AuthenticatorType.SNOWFLAKE_JWT) { - SessionUtilKeyPair s = - new SessionUtilKeyPair( - loginInput.getPrivateKey(), - loginInput.getPrivateKeyFile(), - loginInput.getPrivateKeyFilePwd(), - loginInput.getAccountName(), - loginInput.getUserName()); - - data.put(ClientAuthnParameter.TOKEN.name(), s.issueJwtToken()); + if (authenticatorType == ClientAuthnDTO.AuthenticatorType.SNOWFLAKE_JWT + || authenticatorType == ClientAuthnDTO.AuthenticatorType.OKTA) { + + if (authenticatorType == ClientAuthnDTO.AuthenticatorType.SNOWFLAKE_JWT) { + SessionUtilKeyPair s = + new SessionUtilKeyPair( + loginInput.getPrivateKey(), + loginInput.getPrivateKeyFile(), + loginInput.getPrivateKeyFilePwd(), + loginInput.getAccountName(), + loginInput.getUserName()); + + data.put(ClientAuthnParameter.TOKEN.name(), s.issueJwtToken()); + } else if (authenticatorType == ClientAuthnDTO.AuthenticatorType.OKTA) { + logger.debug("Retrieve new token for Okta authentication."); + // If we need to retry, we need to get a new Okta token + tokenOrSamlResponse = getSamlResponseUsingOkta(loginInput); + data.put(ClientAuthnParameter.RAW_SAML_RESPONSE.name(), tokenOrSamlResponse); + authnData.setData(data); + String updatedJson = mapper.writeValueAsString(authnData); + + StringEntity updatedInput = new StringEntity(updatedJson, StandardCharsets.UTF_8); + updatedInput.setContentType("application/json"); + postRequest.setEntity(updatedInput); + } long elapsedSeconds = ex.getElapsedSeconds(); @@ -690,7 +719,8 @@ private static SFLoginOutput newSession( } } - // JWT renew should not count as a retry, so we pass back the current retry count. + // JWT or Okta renew should not count as a retry, so we pass back the current retry + // count. retryCount = ex.getRetryCount(); continue; diff --git a/src/main/java/net/snowflake/client/core/SfSqlArray.java b/src/main/java/net/snowflake/client/core/SfSqlArray.java deleted file mode 100644 index 83270796a..000000000 --- a/src/main/java/net/snowflake/client/core/SfSqlArray.java +++ /dev/null @@ -1,77 +0,0 @@ -package net.snowflake.client.core; - -import java.sql.Array; -import java.sql.JDBCType; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.SQLFeatureNotSupportedException; -import java.util.Map; - -@SnowflakeJdbcInternalApi -public class SfSqlArray implements Array { - - private int baseType; - private Object elements; - - public SfSqlArray(int baseType, Object elements) { - this.baseType = baseType; - this.elements = elements; - } - - @Override - public String getBaseTypeName() throws SQLException { - return JDBCType.valueOf(baseType).getName(); - } - - @Override - public int getBaseType() throws SQLException { - return baseType; - } - - @Override - public Object getArray() throws SQLException { - return elements; - } - - @Override - public Object getArray(Map> map) throws SQLException { - throw new SQLFeatureNotSupportedException("getArray(Map> map)"); - } - - @Override - public Object getArray(long index, int count) throws SQLException { - throw new SQLFeatureNotSupportedException("getArray(long index, int count)"); - } - - @Override - public Object getArray(long index, int count, Map> map) throws SQLException { - throw new SQLFeatureNotSupportedException( - "getArray(long index, int count, Map> map)"); - } - - @Override - public ResultSet getResultSet() throws SQLException { - throw new SQLFeatureNotSupportedException( - "getArray(long index, int count, Map> map)"); - } - - @Override - public ResultSet getResultSet(Map> map) throws SQLException { - throw new SQLFeatureNotSupportedException("getResultSet(Map> map)"); - } - - @Override - public ResultSet getResultSet(long index, int count) throws SQLException { - throw new SQLFeatureNotSupportedException("getResultSet(long index, int count)"); - } - - @Override - public ResultSet getResultSet(long index, int count, Map> map) - throws SQLException { - throw new SQLFeatureNotSupportedException( - "getResultSet(long index, int count, Map> map)"); - } - - @Override - public void free() throws SQLException {} -} diff --git a/src/main/java/net/snowflake/client/core/json/Converters.java b/src/main/java/net/snowflake/client/core/json/Converters.java index a2f911b39..0fa0c3284 100644 --- a/src/main/java/net/snowflake/client/core/json/Converters.java +++ b/src/main/java/net/snowflake/client/core/json/Converters.java @@ -20,7 +20,6 @@ import net.snowflake.client.jdbc.SnowflakeResultSetSerializableV1; import net.snowflake.client.util.Converter; import net.snowflake.common.core.SFBinaryFormat; -import net.snowflake.common.core.SFTimestamp; import net.snowflake.common.core.SnowflakeDateTimeFormat; public class Converters { @@ -79,24 +78,6 @@ public Converters( formatDateWithTimeZone); } - @SnowflakeJdbcInternalApi - public Converters(SFBaseSession session, SnowflakeResultSetSerializableV1 resultSetSerializable) { - this( - resultSetSerializable.getTimeZone(), - session, - resultSetSerializable.getResultVersion(), - resultSetSerializable.isHonorClientTZForTimestampNTZ(), - resultSetSerializable.getTreatNTZAsUTC(), - resultSetSerializable.getUseSessionTimezone(), - resultSetSerializable.getFormatDateWithTimeZone(), - resultSetSerializable.getBinaryFormatter(), - resultSetSerializable.getDateFormatter(), - resultSetSerializable.getTimeFormatter(), - resultSetSerializable.getTimestampNTZFormatter(), - resultSetSerializable.getTimestampLTZFormatter(), - resultSetSerializable.getTimestampTZFormatter()); - } - public BooleanConverter getBooleanConverter() { return booleanConverter; } diff --git a/src/main/java/net/snowflake/client/core/json/NumberConverter.java b/src/main/java/net/snowflake/client/core/json/NumberConverter.java index 18f6e96b2..132003359 100644 --- a/src/main/java/net/snowflake/client/core/json/NumberConverter.java +++ b/src/main/java/net/snowflake/client/core/json/NumberConverter.java @@ -115,7 +115,7 @@ public BigDecimal getBigDecimal(Object obj, int columnType, Integer scale) throw if (obj == null) { return null; } - BigDecimal value = getBigDecimal(obj.toString(), columnType); + BigDecimal value = new BigDecimal(obj.toString()); value = value.setScale(scale, RoundingMode.HALF_UP); return value; } diff --git a/src/main/java/net/snowflake/client/core/structs/SQLDataCreationHelper.java b/src/main/java/net/snowflake/client/core/structs/SQLDataCreationHelper.java index fd3257e79..5cfdb5ca2 100644 --- a/src/main/java/net/snowflake/client/core/structs/SQLDataCreationHelper.java +++ b/src/main/java/net/snowflake/client/core/structs/SQLDataCreationHelper.java @@ -13,10 +13,11 @@ public class SQLDataCreationHelper { public static T create(Class type) throws SQLException { Optional> typeFactory = SnowflakeObjectTypeFactories.get(type); - return (T) + SQLData instance = typeFactory .map(Supplier::get) .orElseGet(() -> createUsingReflection((Class) type)); + return (T) instance; } private static SQLData createUsingReflection(Class type) { diff --git a/src/main/java/net/snowflake/client/jdbc/RestRequest.java b/src/main/java/net/snowflake/client/jdbc/RestRequest.java index 615b20894..fa7826664 100644 --- a/src/main/java/net/snowflake/client/jdbc/RestRequest.java +++ b/src/main/java/net/snowflake/client/jdbc/RestRequest.java @@ -399,6 +399,16 @@ public static CloseableHttpResponse execute( break; } + // If this was a request for an Okta one-time token that failed with a retry-able error, + // throw exception to renew the token before trying again. + if (String.valueOf(httpRequest.getURI()).contains("okta.com/api/v1/authn")) { + throw new SnowflakeSQLException( + ErrorCode.AUTHENTICATOR_REQUEST_TIMEOUT, + retryCount, + true, + elapsedMilliForTransientIssues / 1000); + } + // Make sure that any authenticator specific info that needs to be // updated get's updated before the next retry. Ex - JWT token // Check to see if customer set socket/connect timeout has been reached, diff --git a/src/main/java/net/snowflake/client/jdbc/SFAsyncResultSet.java b/src/main/java/net/snowflake/client/jdbc/SFAsyncResultSet.java index c50bf4900..bc164de89 100644 --- a/src/main/java/net/snowflake/client/jdbc/SFAsyncResultSet.java +++ b/src/main/java/net/snowflake/client/jdbc/SFAsyncResultSet.java @@ -26,6 +26,7 @@ /** SFAsyncResultSet implementation. Note: For Snowflake internal use */ public class SFAsyncResultSet extends SnowflakeBaseResultSet implements SnowflakeResultSet, ResultSet { + private final SFBaseResultSet sfBaseResultSet; private ResultSet resultSetForNext = new SnowflakeResultSetV1.EmptyResultSet(); private boolean resultSetForNextInitialized = false; private String queryID; @@ -46,8 +47,8 @@ public class SFAsyncResultSet extends SnowflakeBaseResultSet * @throws SQLException if failed to construct snowflake result set metadata */ SFAsyncResultSet(SFBaseResultSet sfBaseResultSet, Statement statement) throws SQLException { - super(statement); + this.sfBaseResultSet = sfBaseResultSet; this.queryID = sfBaseResultSet.getQueryId(); this.session = sfBaseResultSet.getSession(); this.extraStatement = statement; @@ -69,6 +70,8 @@ public SFAsyncResultSet( throws SQLException { super(resultSetSerializable); this.queryID = sfBaseResultSet.getQueryId(); + this.sfBaseResultSet = sfBaseResultSet; + this.resultSetMetaData = new SnowflakeResultSetMetaDataV1(sfBaseResultSet.getMetaData()); this.resultSetMetaData.setQueryIdForAsyncResults(this.queryID); this.resultSetMetaData.setQueryType(SnowflakeResultSetMetaDataV1.QueryType.ASYNC); @@ -76,6 +79,7 @@ public SFAsyncResultSet( public SFAsyncResultSet(String queryID, Statement statement) throws SQLException { super(statement); + this.sfBaseResultSet = null; queryID.trim(); if (!QueryIdValidator.isValid(queryID)) { throw new SQLException( diff --git a/src/main/java/net/snowflake/client/jdbc/SnowflakeBaseResultSet.java b/src/main/java/net/snowflake/client/jdbc/SnowflakeBaseResultSet.java index bd330e68e..4921142a9 100644 --- a/src/main/java/net/snowflake/client/jdbc/SnowflakeBaseResultSet.java +++ b/src/main/java/net/snowflake/client/jdbc/SnowflakeBaseResultSet.java @@ -31,12 +31,12 @@ import java.sql.Statement; import java.sql.Time; import java.sql.Timestamp; -import java.util.Arrays; import java.util.Calendar; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.TimeZone; import net.snowflake.client.core.ArrowSqlInput; import net.snowflake.client.core.ColumnTypeHelper; @@ -57,7 +57,6 @@ public abstract class SnowflakeBaseResultSet implements ResultSet { private final int resultSetType; private final int resultSetConcurrency; private final int resultSetHoldability; - protected SFBaseResultSet sfBaseResultSet; // Snowflake supports sessionless result set. For this case, there is no // statement for this result set. protected final Statement statement; @@ -65,7 +64,6 @@ public abstract class SnowflakeBaseResultSet implements ResultSet { protected Map parameters = new HashMap<>(); private int fetchSize = 0; protected SFBaseSession session = null; - private static final ObjectMapper OBJECT_MAPPER = ObjectMapperFactory.getObjectMapper(); SnowflakeBaseResultSet(Statement statement) throws SQLException { this.statement = statement; @@ -1353,6 +1351,7 @@ public void updateNClob(String columnLabel, Reader reader) throws SQLException { @Override public T getObject(int columnIndex, Class type) throws SQLException { logger.debug("public T getObject(int columnIndex,Class type)", false); + if (StructureTypeHelper.isStructureTypeEnabled()) { if (SQLData.class.isAssignableFrom(type)) { SQLData instance = (SQLData) SQLDataCreationHelper.create(type); @@ -1699,8 +1698,6 @@ public Map getMap(int columnIndex, Class type) throws SQLExcep + type.getName()); } } - - return resultMap; } @Override diff --git a/src/main/java/net/snowflake/client/jdbc/SnowflakeResultSetMetaDataV1.java b/src/main/java/net/snowflake/client/jdbc/SnowflakeResultSetMetaDataV1.java index 4bc90bd54..94f4bab11 100644 --- a/src/main/java/net/snowflake/client/jdbc/SnowflakeResultSetMetaDataV1.java +++ b/src/main/java/net/snowflake/client/jdbc/SnowflakeResultSetMetaDataV1.java @@ -106,11 +106,10 @@ public boolean isCaseSensitive(int column) throws SQLException { int colType = getColumnType(column); switch (colType) { - // Note: SF types GEOGRAPHY, GEOMETRY are also represented as VARCHAR. + // Note: SF types ARRAY, GEOGRAPHY, GEOMETRY are also represented as VARCHAR. case Types.VARCHAR: case Types.CHAR: case Types.STRUCT: - case Types.ARRAY: return true; case Types.INTEGER: diff --git a/src/main/java/net/snowflake/client/jdbc/SnowflakeResultSetV1.java b/src/main/java/net/snowflake/client/jdbc/SnowflakeResultSetV1.java index bdd8ffcee..83b3d5069 100644 --- a/src/main/java/net/snowflake/client/jdbc/SnowflakeResultSetV1.java +++ b/src/main/java/net/snowflake/client/jdbc/SnowflakeResultSetV1.java @@ -36,6 +36,7 @@ /** Snowflake ResultSet implementation */ public class SnowflakeResultSetV1 extends SnowflakeBaseResultSet implements SnowflakeResultSet, ResultSet { + private final SFBaseResultSet sfBaseResultSet; /** * Constructor takes an inputstream from the API response that we get from executing a SQL @@ -50,7 +51,6 @@ public class SnowflakeResultSetV1 extends SnowflakeBaseResultSet */ public SnowflakeResultSetV1(SFBaseResultSet sfBaseResultSet, Statement statement) throws SQLException { - super(statement); this.sfBaseResultSet = sfBaseResultSet; this.resultSetMetaData = new SnowflakeResultSetMetaDataV1(sfBaseResultSet.getMetaData()); @@ -102,6 +102,7 @@ public SnowflakeResultSetV1( SFBaseResultSet sfBaseResultSet, SnowflakeResultSetSerializableV1 resultSetSerializable) throws SQLException { super(resultSetSerializable); + this.sfBaseResultSet = sfBaseResultSet; this.resultSetMetaData = new SnowflakeResultSetMetaDataV1(sfBaseResultSet.getMetaData()); } diff --git a/src/main/java/net/snowflake/client/jdbc/SnowflakeType.java b/src/main/java/net/snowflake/client/jdbc/SnowflakeType.java index 2e483fe5b..d95cacf84 100644 --- a/src/main/java/net/snowflake/client/jdbc/SnowflakeType.java +++ b/src/main/java/net/snowflake/client/jdbc/SnowflakeType.java @@ -30,7 +30,6 @@ public enum SnowflakeType { FIXED, INTEGER, OBJECT, - MAP, REAL, TEXT, TIME, diff --git a/src/main/java/net/snowflake/client/jdbc/SnowflakeUtil.java b/src/main/java/net/snowflake/client/jdbc/SnowflakeUtil.java index 82dbca171..85002beea 100644 --- a/src/main/java/net/snowflake/client/jdbc/SnowflakeUtil.java +++ b/src/main/java/net/snowflake/client/jdbc/SnowflakeUtil.java @@ -55,7 +55,7 @@ */ public class SnowflakeUtil { - private static final SFLogger logger = SFLoggerFactory.getLogger(SnowflakeUtil.class); + static final SFLogger logger = SFLoggerFactory.getLogger(RestRequest.class); /** Additional data types not covered by standard JDBC */ public static final int EXTRA_TYPES_TIMESTAMP_LTZ = 50000; @@ -186,7 +186,7 @@ public static SnowflakeColumnMetadata extractColumnMetadata( String colSrcDatabase = colNode.path("database").asText(); String colSrcSchema = colNode.path("schema").asText(); String colSrcTable = colNode.path("table").asText(); - List fieldsMetadata = getFieldMetadata(jdbcTreatDecimalAsInt, colNode); + List fieldsMetadata = getFieldMetadata(fixedColType, colNode); boolean isAutoIncrement = colNode.path("isAutoIncrement").asBoolean(); @@ -277,7 +277,7 @@ static ColumnTypeInfo getSnowflakeType( case ARRAY: columnTypeInfo = - new ColumnTypeInfo(Types.ARRAY, defaultIfNull(extColTypeName, "ARRAY"), baseType); + new ColumnTypeInfo(Types.VARCHAR, defaultIfNull(extColTypeName, "ARRAY"), baseType); break; case MAP: @@ -342,8 +342,8 @@ private static String defaultIfNull(String extColTypeName, String defaultValue) return Optional.ofNullable(extColTypeName).orElse(defaultValue); } - static List createFieldsMetadata( - ArrayNode fieldsJson, boolean jdbcTreatDecimalAsInt) throws SnowflakeSQLLoggedException { + static List createFieldsMetadata(ArrayNode fieldsJson, int fixedColType) + throws SnowflakeSQLLoggedException { List fields = new ArrayList<>(); for (JsonNode node : fieldsJson) { String colName = node.path("name").asText(); @@ -353,8 +353,7 @@ static List createFieldsMetadata( boolean nullable = node.path("nullable").asBoolean(); int length = node.path("length").asInt(); boolean fixed = node.path("fixed").asBoolean(); - int fixedColType = jdbcTreatDecimalAsInt && scale == 0 ? Types.BIGINT : Types.DECIMAL; - List internalFields = getFieldMetadata(jdbcTreatDecimalAsInt, node); + List internalFields = getFieldMetadata(fixedColType, node); JsonNode outputType = node.path("outputType"); JsonNode extColTypeNameNode = node.path("extTypeName"); String extColTypeName = null; @@ -380,11 +379,11 @@ static List createFieldsMetadata( return fields; } - private static List getFieldMetadata(boolean jdbcTreatDecimalAsInt, JsonNode node) + private static List getFieldMetadata(int fixedColType, JsonNode node) throws SnowflakeSQLLoggedException { if (!node.path("fields").isEmpty()) { ArrayNode internalFieldsJson = (ArrayNode) node.path("fields"); - return createFieldsMetadata(internalFieldsJson, jdbcTreatDecimalAsInt); + return createFieldsMetadata(internalFieldsJson, fixedColType); } else { return new ArrayList<>(); } diff --git a/src/main/java/net/snowflake/client/jdbc/cloud/storage/SnowflakeGCSClient.java b/src/main/java/net/snowflake/client/jdbc/cloud/storage/SnowflakeGCSClient.java index 61c31b3ab..25b3bc9dc 100644 --- a/src/main/java/net/snowflake/client/jdbc/cloud/storage/SnowflakeGCSClient.java +++ b/src/main/java/net/snowflake/client/jdbc/cloud/storage/SnowflakeGCSClient.java @@ -12,8 +12,6 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.google.api.gax.paging.Page; import com.google.api.gax.rpc.FixedHeaderProvider; -import com.google.auth.oauth2.AccessToken; -import com.google.auth.oauth2.GoogleCredentials; import com.google.cloud.storage.Blob; import com.google.cloud.storage.BlobId; import com.google.cloud.storage.BlobInfo; @@ -45,7 +43,6 @@ import net.snowflake.client.core.ObjectMapperFactory; import net.snowflake.client.core.SFSession; import net.snowflake.client.core.SFSessionProperty; -import net.snowflake.client.core.SnowflakeJdbcInternalApi; import net.snowflake.client.jdbc.ErrorCode; import net.snowflake.client.jdbc.FileBackedOutputStream; import net.snowflake.client.jdbc.MatDesc; @@ -77,10 +74,6 @@ * @author ppaulus */ public class SnowflakeGCSClient implements SnowflakeStorageClient { - @SnowflakeJdbcInternalApi - public static final String DISABLE_GCS_DEFAULT_CREDENTIALS_PROPERTY_NAME = - "net.snowflake.jdbc.disableGcsDefaultCredentials"; - private static final String GCS_ENCRYPTIONDATAPROP = "encryptiondata"; private static final String localFileSep = systemGetProperty("file.separator"); private static final String GCS_METADATA_PREFIX = "x-goog-meta-"; @@ -1207,19 +1200,13 @@ private void setupGCSClient( try { String accessToken = (String) stage.getCredentials().get("GCS_ACCESS_TOKEN"); if (accessToken != null) { - // We are authenticated with an oauth access token. - StorageOptions.Builder builder = StorageOptions.newBuilder(); - if (areDisabledGcsDefaultCredentials(session)) { - logger.debug( - "Adding explicit credentials to avoid default credential lookup by the GCS client"); - builder.setCredentials(GoogleCredentials.create(new AccessToken(accessToken, null))); - } - // Using GoogleCredential with access token will cause IllegalStateException when the token // is expired and trying to refresh, which cause error cannot be caught. Instead, set a // header so we can caught the error code. + + // We are authenticated with an oauth access token. this.gcsClient = - builder + StorageOptions.newBuilder() .setHeaderProvider( FixedHeaderProvider.create("Authorization", "Bearer " + accessToken)) .build() @@ -1247,12 +1234,6 @@ private void setupGCSClient( } } - private static boolean areDisabledGcsDefaultCredentials(SFSession session) { - return session != null && session.getDisableGcsDefaultCredentials() - || SnowflakeUtil.convertSystemPropertyToBooleanValue( - DISABLE_GCS_DEFAULT_CREDENTIALS_PROPERTY_NAME, false); - } - private static boolean isSuccessStatusCode(int code) { return code < 300 && code >= 200; } diff --git a/src/main/java/net/snowflake/client/jdbc/cloud/storage/StorageClientFactory.java b/src/main/java/net/snowflake/client/jdbc/cloud/storage/StorageClientFactory.java index ef97c9508..bfa2e3451 100644 --- a/src/main/java/net/snowflake/client/jdbc/cloud/storage/StorageClientFactory.java +++ b/src/main/java/net/snowflake/client/jdbc/cloud/storage/StorageClientFactory.java @@ -22,7 +22,7 @@ */ public class StorageClientFactory { - private static final SFLogger logger = SFLoggerFactory.getLogger(StorageClientFactory.class); + private static final SFLogger logger = SFLoggerFactory.getLogger(SnowflakeS3Client.class); private static StorageClientFactory factory; diff --git a/src/test/java/net/snowflake/client/TestUtil.java b/src/test/java/net/snowflake/client/TestUtil.java index 1f782ec1f..fa53f4c58 100644 --- a/src/test/java/net/snowflake/client/TestUtil.java +++ b/src/test/java/net/snowflake/client/TestUtil.java @@ -116,13 +116,13 @@ public static void withSchema(Statement statement, String schemaName, ThrowingRu * @param action action to execute when schema was created * @throws Exception when any error occurred */ - public static void withRandomSchema( - Statement statement, ThrowingConsumer action) throws Exception { + public static void withRandomSchema(Statement statement, ThrowingConsumer action) + throws Exception { String customSchema = GENERATED_SCHEMA_PREFIX + SnowflakeUtil.randomAlphaNumeric(5).toUpperCase(); try { statement.execute("CREATE OR REPLACE SCHEMA " + customSchema); - action.accept(customSchema); + action.call(customSchema); } finally { statement.execute("DROP SCHEMA " + customSchema); } diff --git a/src/test/java/net/snowflake/client/ThrowingConsumer.java b/src/test/java/net/snowflake/client/ThrowingConsumer.java index d5a47cd5e..8b6f8c001 100644 --- a/src/test/java/net/snowflake/client/ThrowingConsumer.java +++ b/src/test/java/net/snowflake/client/ThrowingConsumer.java @@ -1,6 +1,6 @@ package net.snowflake.client; @FunctionalInterface -public interface ThrowingConsumer { - void accept(A parameter) throws T; +public interface ThrowingConsumer { + void call(T parameter) throws Exception; } diff --git a/src/test/java/net/snowflake/client/core/SessionUtilLatestIT.java b/src/test/java/net/snowflake/client/core/SessionUtilLatestIT.java index f3e60f56b..bedd77438 100644 --- a/src/test/java/net/snowflake/client/core/SessionUtilLatestIT.java +++ b/src/test/java/net/snowflake/client/core/SessionUtilLatestIT.java @@ -390,4 +390,79 @@ public void testOktaAuthGetFail() throws Throwable { assertEquals(SqlState.IO_ERROR, e.getSQLState()); } } + + private SFLoginInput createOktaLoginInput() { + SFLoginInput input = new SFLoginInput(); + input.setServerUrl("https://testauth.okta.com"); + input.setUserName("MOCK_USERNAME"); + input.setPassword("MOCK_PASSWORD"); + input.setAccountName("MOCK_ACCOUNT_NAME"); + input.setAppId("MOCK_APP_ID"); + input.setOCSPMode(OCSPMode.FAIL_OPEN); + input.setHttpClientSettingsKey(new HttpClientSettingsKey(OCSPMode.FAIL_OPEN)); + input.setLoginTimeout(1000); + input.setSessionParameters(new HashMap<>()); + input.setAuthenticator("https://testauth.okta.com"); + return input; + } + + // Testing retry with Okta calls the service to get a new unique token. This is valid after + // version 3.15.0. + @Test + public void testOktaAuthRetry() throws Throwable { + SFLoginInput loginInput = createOktaLoginInput(); + Map connectionPropertiesMap = initConnectionPropertiesMap(); + SnowflakeSQLException ex = + new SnowflakeSQLException(ErrorCode.AUTHENTICATOR_REQUEST_TIMEOUT, 0, true, 0); + try (MockedStatic mockedHttpUtil = mockStatic(HttpUtil.class)) { + mockedHttpUtil + .when( + () -> + HttpUtil.executeGeneralRequest( + Mockito.any(HttpPost.class), + Mockito.anyInt(), + Mockito.anyInt(), + Mockito.anyInt(), + Mockito.anyInt(), + Mockito.nullable(HttpClientSettingsKey.class))) + .thenReturn( + "{\"data\":{\"tokenUrl\":\"https://testauth.okta.com/api/v1/authn\"," + + "\"ssoUrl\":\"https://testauth.okta.com/app/snowflake/abcdefghijklmnopqrstuvwxyz/sso/saml\"," + + "\"proofKey\":null},\"code\":null,\"message\":null,\"success\":true}") + .thenThrow(ex) + .thenReturn( + "{\"data\":{\"tokenUrl\":\"https://testauth.okta.com/api/v1/authn\"," + + "\"ssoUrl\":\"https://testauth.okta.com/app/snowflake/abcdefghijklmnopqrstuvwxyz/sso/saml\"," + + "\"proofKey\":null},\"code\":null,\"message\":null,\"success\":true}"); + + mockedHttpUtil + .when( + () -> + HttpUtil.executeRequestWithoutCookies( + Mockito.any(HttpRequestBase.class), + Mockito.anyInt(), + Mockito.anyInt(), + Mockito.anyInt(), + Mockito.anyInt(), + Mockito.anyInt(), + Mockito.nullable(AtomicBoolean.class), + Mockito.nullable(HttpClientSettingsKey.class))) + .thenReturn( + "{\"expiresAt\":\"2023-10-13T19:18:09.000Z\",\"status\":\"SUCCESS\",\"sessionToken\":\"testsessiontoken\"}"); + + mockedHttpUtil + .when( + () -> + HttpUtil.executeGeneralRequest( + Mockito.any(HttpGet.class), + Mockito.anyInt(), + Mockito.anyInt(), + Mockito.anyInt(), + Mockito.anyInt(), + Mockito.nullable(HttpClientSettingsKey.class))) + .thenReturn("
"); + + SessionUtil.openSession(loginInput, connectionPropertiesMap, "ALL"); + } + } } diff --git a/src/test/java/net/snowflake/client/jdbc/ConnectionIT.java b/src/test/java/net/snowflake/client/jdbc/ConnectionIT.java index 14b9f2d71..68d337aff 100644 --- a/src/test/java/net/snowflake/client/jdbc/ConnectionIT.java +++ b/src/test/java/net/snowflake/client/jdbc/ConnectionIT.java @@ -33,8 +33,10 @@ import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.sql.Statement; +import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; +import java.util.List; import java.util.Map; import java.util.Properties; import java.util.concurrent.ExecutorService; @@ -387,6 +389,40 @@ public void testDataSourceOktaSerialization() throws Exception { con.close(); } + @Test + @Ignore + public void testDataSourceOktaGenerates429StatusCode() throws Exception { + // test with username/password authentication + // set up DataSource object and ensure connection works + Map params = getConnectionParameters(); + SnowflakeBasicDataSource ds = new SnowflakeBasicDataSource(); + ds.setServerName(params.get("host")); + ds.setSsl("on".equals(params.get("ssl"))); + ds.setAccount(params.get("account")); + ds.setPortNumber(Integer.parseInt(params.get("port"))); + ds.setUser(params.get("ssoUser")); + ds.setPassword(params.get("ssoPassword")); + ds.setAuthenticator(""); + Runnable r = + () -> { + try { + ds.getConnection(); + } catch (SQLException e) { + throw new RuntimeException(e); + } + }; + List threadList = new ArrayList<>(); + for (int i = 0; + i < 30; + ++i) { // https://docs.snowflake.com/en/user-guide/admin-security-fed-auth-use#http-429-errors + threadList.add(new Thread(r)); + } + threadList.forEach(Thread::start); + for (Thread thread : threadList) { + thread.join(); + } + } + @Test @ConditionalIgnore(condition = RunningOnGithubAction.class) public void testConnectUsingKeyPair() throws Exception { diff --git a/src/test/java/net/snowflake/client/jdbc/ConnectionLatestIT.java b/src/test/java/net/snowflake/client/jdbc/ConnectionLatestIT.java index b9a406176..15d8b2f80 100644 --- a/src/test/java/net/snowflake/client/jdbc/ConnectionLatestIT.java +++ b/src/test/java/net/snowflake/client/jdbc/ConnectionLatestIT.java @@ -403,10 +403,10 @@ public void testQueryStatusErrorMessageAndErrorCodeChangeOnAsyncQuery() throws S SnowflakeResultSet sfResultSet = rs1.unwrap(SnowflakeResultSet.class); // status should change state to RUNNING and then to SUCCESS await() - .atMost(Duration.ofSeconds(10)) + .atMost(Duration.ofSeconds(5)) .until(() -> sfResultSet.getStatusV2().getStatus(), equalTo(QueryStatus.RUNNING)); await() - .atMost(Duration.ofSeconds(50)) + .atMost(Duration.ofSeconds(5)) .until(() -> sfResultSet.getStatusV2().getStatus(), equalTo(QueryStatus.SUCCESS)); } } diff --git a/src/test/java/net/snowflake/client/jdbc/MockConnectionTest.java b/src/test/java/net/snowflake/client/jdbc/MockConnectionTest.java index c763606fe..65163a938 100644 --- a/src/test/java/net/snowflake/client/jdbc/MockConnectionTest.java +++ b/src/test/java/net/snowflake/client/jdbc/MockConnectionTest.java @@ -50,7 +50,6 @@ import net.snowflake.client.core.json.Converters; import net.snowflake.client.jdbc.telemetry.Telemetry; import net.snowflake.client.jdbc.telemetry.TelemetryData; -import net.snowflake.common.core.SFBinaryFormat; import net.snowflake.common.core.SnowflakeDateTimeFormat; import org.junit.Test; import org.junit.experimental.categories.Category; @@ -882,21 +881,6 @@ public ResultSet createResultSet(String queryID, Statement statement) throws SQL @Override public SnowflakeBaseResultSet createResultSet(SFBaseResultSet resultSet, Statement statement) throws SQLException { - Converters convertes = - new Converters( - null, - new SFSession(), - 0, - false, - false, - false, - false, - SFBinaryFormat.BASE64, - null, - null, - null, - null, - null); return new SnowflakeResultSetV1(resultSet, statement); } diff --git a/src/test/java/net/snowflake/client/jdbc/RestRequestTest.java b/src/test/java/net/snowflake/client/jdbc/RestRequestTest.java index 0654cc73d..ed6e165d1 100644 --- a/src/test/java/net/snowflake/client/jdbc/RestRequestTest.java +++ b/src/test/java/net/snowflake/client/jdbc/RestRequestTest.java @@ -359,6 +359,20 @@ public void testExceptionAuthBasedTimeout() throws IOException { } } + @Test + public void testExceptionAuthBasedTimeoutFor429ErrorCode() throws IOException { + CloseableHttpClient client = mock(CloseableHttpClient.class); + when(client.execute(any(HttpUriRequest.class))) + .thenAnswer((Answer) invocation -> retryLoginResponse()); + + try { + execute(client, "login-request.com/?requestId=abcd-1234", 2, 1, 30000, true, false); + } catch (SnowflakeSQLException ex) { + assertThat( + ex.getErrorCode(), equalTo(ErrorCode.AUTHENTICATOR_REQUEST_TIMEOUT.getMessageCode())); + } + } + @Test public void testNoRetry() throws IOException, SnowflakeSQLException { boolean telemetryEnabled = TelemetryService.getInstance().isEnabled(); diff --git a/src/test/java/net/snowflake/client/jdbc/ResultSetFeatureNotSupportedIT.java b/src/test/java/net/snowflake/client/jdbc/ResultSetFeatureNotSupportedIT.java index 2535a6579..539784120 100644 --- a/src/test/java/net/snowflake/client/jdbc/ResultSetFeatureNotSupportedIT.java +++ b/src/test/java/net/snowflake/client/jdbc/ResultSetFeatureNotSupportedIT.java @@ -117,6 +117,7 @@ private void checkFeatureNotSupportedException(ResultSet resultSet) throws SQLEx expectFeatureNotSupportedException(() -> resultSet.getObject(1, Collections.emptyMap())); expectFeatureNotSupportedException(() -> resultSet.getRef(1)); expectFeatureNotSupportedException(() -> resultSet.getBlob(1)); + expectFeatureNotSupportedException(() -> resultSet.getArray(1)); expectFeatureNotSupportedException(() -> resultSet.getURL(1)); expectFeatureNotSupportedException(() -> resultSet.getRowId(1)); expectFeatureNotSupportedException(() -> resultSet.getNClob(1)); diff --git a/src/test/java/net/snowflake/client/jdbc/ResultSetStructuredTypesLatestIT.java b/src/test/java/net/snowflake/client/jdbc/ResultSetStructuredTypesLatestIT.java index 71f8d590b..3fea6ef8c 100644 --- a/src/test/java/net/snowflake/client/jdbc/ResultSetStructuredTypesLatestIT.java +++ b/src/test/java/net/snowflake/client/jdbc/ResultSetStructuredTypesLatestIT.java @@ -19,8 +19,6 @@ import java.time.LocalDate; import java.time.LocalDateTime; import java.time.LocalTime; -import java.util.List; -import java.util.Map; import net.snowflake.client.ConditionalIgnoreRule; import net.snowflake.client.RunningOnGithubAction; import net.snowflake.client.ThrowingConsumer; @@ -91,13 +89,17 @@ public void testMapStructToObjectWithReflection() throws SQLException { private void testMapJson(boolean registerFactory) throws SQLException { if (registerFactory) { SnowflakeObjectTypeFactories.register(SimpleClass.class, SimpleClass::new); + } else { + SnowflakeObjectTypeFactories.unregister(SimpleClass.class); + } + try (Connection connection = init(); + Statement statement = connection.createStatement(); + ResultSet resultSet = + statement.executeQuery("select {'string':'a'}::OBJECT(string VARCHAR)"); ) { + resultSet.next(); + SimpleClass object = resultSet.getObject(1, SimpleClass.class); + assertEquals("a", object.getString()); } - withFirstRow( - "select {'string':'a'}::OBJECT(string VARCHAR)", - (resultSet) -> { - SimpleClass object = resultSet.getObject(1, SimpleClass.class); - assertEquals("a", object.getString()); - }); } @Test @@ -156,12 +158,12 @@ private void testMapAllTypes(boolean registerFactory) throws SQLException { resultSet.next(); AllTypesClass object = resultSet.getObject(1, AllTypesClass.class); assertEquals("a", object.getString()); - assertEquals(new Byte("1"), object.getB()); - assertEquals(Short.valueOf("2"), object.getS()); - assertEquals(Integer.valueOf(3), object.getI()); - assertEquals(Long.valueOf(4), object.getL()); - assertEquals(Float.valueOf(1.1f), object.getF(), 0.01); - assertEquals(Double.valueOf(2.2), object.getD(), 0.01); + assertEquals(1, (long) object.getB()); + assertEquals(2, (long) object.getS()); + assertEquals(3, (long) object.getI()); + assertEquals(4, (long) object.getL()); + assertEquals(1.1, (double) object.getF(), 0.01); + assertEquals(2.2, (double) object.getD(), 0.01); assertEquals(BigDecimal.valueOf(3.3), object.getBd()); assertEquals( Timestamp.valueOf(LocalDateTime.of(2021, 12, 22, 9, 43, 44)), object.getTimestampLtz()); diff --git a/src/test/java/net/snowflake/client/jdbc/SnowflakeDriverLatestIT.java b/src/test/java/net/snowflake/client/jdbc/SnowflakeDriverLatestIT.java index e76e5c60e..744ffccf6 100644 --- a/src/test/java/net/snowflake/client/jdbc/SnowflakeDriverLatestIT.java +++ b/src/test/java/net/snowflake/client/jdbc/SnowflakeDriverLatestIT.java @@ -8,7 +8,6 @@ import static net.snowflake.client.jdbc.SnowflakeDriverIT.findFile; import static net.snowflake.client.jdbc.SnowflakeResultSetSerializableV1.mapper; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -47,9 +46,7 @@ import net.snowflake.client.core.Constants; import net.snowflake.client.core.OCSPMode; import net.snowflake.client.core.SFSession; -import net.snowflake.client.core.SFSessionProperty; import net.snowflake.client.core.SFStatement; -import net.snowflake.client.jdbc.cloud.storage.SnowflakeGCSClient; import net.snowflake.client.jdbc.cloud.storage.SnowflakeStorageClient; import net.snowflake.client.jdbc.cloud.storage.StageInfo; import net.snowflake.client.jdbc.cloud.storage.StorageClientFactory; @@ -841,7 +838,7 @@ public void testGeoOutputTypes() throws Throwable { regularStatement, false, "geoJson", "OBJECT", "java.lang.String", Types.VARCHAR); testGeoOutputTypeSingle( - regularStatement, true, "geoJson", "GEOGRAPHY", "java.lang.String", Types.VARCHAR); + regularStatement, true, "geoJson", "GEOGRAPHY", "java.lang.String", Types.STRUCT); testGeoOutputTypeSingle( regularStatement, false, "wkt", "VARCHAR", "java.lang.String", Types.VARCHAR); @@ -989,10 +986,10 @@ public void testGeometryOutputTypes() throws Throwable { "insert into t_geo2 values ('POINT(0 0)'), ('LINESTRING(1 1, 2 2)')"); testGeometryOutputTypeSingle( - regularStatement, true, "geoJson", "GEOMETRY", "java.lang.String", Types.VARCHAR); + regularStatement, true, "geoJson", "GEOMETRY", "java.lang.String", Types.STRUCT); testGeometryOutputTypeSingle( - regularStatement, true, "wkt", "GEOMETRY", "java.lang.String", Types.VARCHAR); + regularStatement, true, "wkt", "GEOMETRY", "java.lang.String", Types.STRUCT); } finally { if (regularStatement != null) { @@ -1108,67 +1105,58 @@ private void testGeometryMetadataSingle( @Test @ConditionalIgnoreRule.ConditionalIgnore(condition = RunningOnGithubAction.class) public void testPutGetGcsDownscopedCredential() throws Throwable { + Connection connection = null; + Statement statement = null; Properties paramProperties = new Properties(); paramProperties.put("GCS_USE_DOWNSCOPED_CREDENTIAL", true); - try (Connection connection = getConnection("gcpaccount", paramProperties); - Statement statement = connection.createStatement()) { - putAndGetFile(statement); - } - } + try { + connection = getConnection("gcpaccount", paramProperties); - /** Added in > 3.15.0 */ - @Test - @ConditionalIgnoreRule.ConditionalIgnore(condition = RunningOnGithubAction.class) - public void testPutGetGcsDownscopedCredentialWithDisabledDefaultCredentials() throws Throwable { - Properties paramProperties = new Properties(); - paramProperties.put("GCS_USE_DOWNSCOPED_CREDENTIAL", true); - paramProperties.put(SFSessionProperty.DISABLE_GCS_DEFAULT_CREDENTIALS.getPropertyKey(), true); - try (Connection connection = getConnection("gcpaccount", paramProperties); - Statement statement = connection.createStatement()) { - putAndGetFile(statement); - } - } + statement = connection.createStatement(); - private void putAndGetFile(Statement statement) throws Throwable { - String sourceFilePath = getFullPathFileInResource(TEST_DATA_FILE_2); + String sourceFilePath = getFullPathFileInResource(TEST_DATA_FILE_2); - File destFolder = tmpFolder.newFolder(); - String destFolderCanonicalPath = destFolder.getCanonicalPath(); - String destFolderCanonicalPathWithSeparator = destFolderCanonicalPath + File.separator; + File destFolder = tmpFolder.newFolder(); + String destFolderCanonicalPath = destFolder.getCanonicalPath(); + String destFolderCanonicalPathWithSeparator = destFolderCanonicalPath + File.separator; - try { - statement.execute("CREATE OR REPLACE STAGE testPutGet_stage"); + try { + statement.execute("CREATE OR REPLACE STAGE testPutGet_stage"); - assertTrue( - "Failed to put a file", - statement.execute("PUT file://" + sourceFilePath + " @testPutGet_stage")); + assertTrue( + "Failed to put a file", + statement.execute("PUT file://" + sourceFilePath + " @testPutGet_stage")); - findFile(statement, "ls @testPutGet_stage/"); + findFile(statement, "ls @testPutGet_stage/"); - // download the file we just uploaded to stage - assertTrue( - "Failed to get a file", - statement.execute( - "GET @testPutGet_stage 'file://" + destFolderCanonicalPath + "' parallel=8")); + // download the file we just uploaded to stage + assertTrue( + "Failed to get a file", + statement.execute( + "GET @testPutGet_stage 'file://" + destFolderCanonicalPath + "' parallel=8")); - // Make sure that the downloaded file exists, it should be gzip compressed - File downloaded = new File(destFolderCanonicalPathWithSeparator + TEST_DATA_FILE_2 + ".gz"); - assert (downloaded.exists()); + // Make sure that the downloaded file exists, it should be gzip compressed + File downloaded = new File(destFolderCanonicalPathWithSeparator + TEST_DATA_FILE_2 + ".gz"); + assert (downloaded.exists()); - Process p = - Runtime.getRuntime() - .exec("gzip -d " + destFolderCanonicalPathWithSeparator + TEST_DATA_FILE_2 + ".gz"); - p.waitFor(); + Process p = + Runtime.getRuntime() + .exec("gzip -d " + destFolderCanonicalPathWithSeparator + TEST_DATA_FILE_2 + ".gz"); + p.waitFor(); - File original = new File(sourceFilePath); - File unzipped = new File(destFolderCanonicalPathWithSeparator + TEST_DATA_FILE_2); - System.out.println( - "Original file: " + original.getAbsolutePath() + ", size: " + original.length()); - System.out.println( - "Unzipped file: " + unzipped.getAbsolutePath() + ", size: " + unzipped.length()); - assert (original.length() == unzipped.length()); + File original = new File(sourceFilePath); + File unzipped = new File(destFolderCanonicalPathWithSeparator + TEST_DATA_FILE_2); + System.out.println( + "Original file: " + original.getAbsolutePath() + ", size: " + original.length()); + System.out.println( + "Unzipped file: " + unzipped.getAbsolutePath() + ", size: " + unzipped.length()); + assert (original.length() == unzipped.length()); + } finally { + statement.execute("DROP STAGE IF EXISTS testGetPut_stage"); + statement.close(); + } } finally { - statement.execute("DROP STAGE IF EXISTS testGetPut_stage"); + closeSQLObjects(null, statement, connection); } } @@ -1509,7 +1497,7 @@ public void testAzureS3UploadStreamingIngestFileMetadata() throws Throwable { ((SnowflakeFileTransferMetadataV1) oneMetadata).getStageInfo(), 1, null, - /* session= */ null); + /*session = */ null); String location = ((SnowflakeFileTransferMetadataV1) oneMetadata).getStageInfo().getLocation(); @@ -1549,7 +1537,7 @@ public void testNoSpaceLeftOnDeviceException() throws SQLException { new SnowflakeFileTransferAgent(command, sfSession, sfStatement); StageInfo info = sfAgent.getStageInfo(); SnowflakeStorageClient client = - StorageClientFactory.getFactory().createClient(info, 1, null, /* session= */ null); + StorageClientFactory.getFactory().createClient(info, 1, null, /*session = */ null); client.handleStorageException( new StorageException( @@ -1625,72 +1613,58 @@ public void testUploadWithGCSPresignedUrlWithoutConnection() throws Throwable { @Test @ConditionalIgnoreRule.ConditionalIgnore(condition = RunningOnGithubAction.class) public void testUploadWithGCSDownscopedCredentialWithoutConnection() throws Throwable { - uploadWithGCSDownscopedCredentialWithoutConnection(); - } - - /** Added in > 3.15.0 */ - @Test - @ConditionalIgnoreRule.ConditionalIgnore(condition = RunningOnGithubAction.class) - public void - testUploadWithGCSDownscopedCredentialAndDisabledGcsDefaultCredentialsWithoutConnection() - throws Throwable { - System.setProperty(SnowflakeGCSClient.DISABLE_GCS_DEFAULT_CREDENTIALS_PROPERTY_NAME, "true"); - try { - uploadWithGCSDownscopedCredentialWithoutConnection(); - } finally { - System.clearProperty(SnowflakeGCSClient.DISABLE_GCS_DEFAULT_CREDENTIALS_PROPERTY_NAME); - } - } - - private void uploadWithGCSDownscopedCredentialWithoutConnection() throws Throwable { + Connection connection = null; File destFolder = tmpFolder.newFolder(); String destFolderCanonicalPath = destFolder.getCanonicalPath(); - Properties paramProperties = new Properties(); - paramProperties.put("GCS_USE_DOWNSCOPED_CREDENTIAL", true); - try (Connection connection = getConnection("gcpaccount", paramProperties); - Statement statement = connection.createStatement(); ) { - try { - // create a stage to put the file in - statement.execute("CREATE OR REPLACE STAGE " + testStageName); + try { + Properties paramProperties = new Properties(); + paramProperties.put("GCS_USE_DOWNSCOPED_CREDENTIAL", true); + connection = getConnection("gcpaccount", paramProperties); + // connection = getConnection(null, paramProperties); + Statement statement = connection.createStatement(); - SFSession sfSession = connection.unwrap(SnowflakeConnectionV1.class).getSfSession(); + // create a stage to put the file in + statement.execute("CREATE OR REPLACE STAGE " + testStageName); - // Test put file with internal compression - String putCommand = "put file:///dummy/path/file1.gz @" + testStageName; - SnowflakeFileTransferAgent sfAgent = - new SnowflakeFileTransferAgent(putCommand, sfSession, new SFStatement(sfSession)); - List metadataList = sfAgent.getFileTransferMetadatas(); - assertEquals(1, metadataList.size()); - SnowflakeFileTransferMetadata oneMetadata = metadataList.get(0); - assertFalse(oneMetadata.isForOneFile()); - - // Upload multiple file with the same SnowflakeFileTransferMetadata - String[] fileNames = {TEST_DATA_FILE, TEST_DATA_FILE_2}; - for (String fileName : fileNames) { - String srcPath = getFullPathFileInResource(fileName); - try (InputStream inputStream = new FileInputStream(srcPath)) { - // upload file 1 - String targetFileName = fileName + ".gz"; - SnowflakeFileTransferAgent.uploadWithoutConnection( - SnowflakeFileTransferConfig.Builder.newInstance() - .setSnowflakeFileTransferMetadata(oneMetadata) - .setUploadStream(inputStream) - .setDestFileName(targetFileName) - .setRequireCompress(true) - .setNetworkTimeoutInMilli(0) - .setOcspMode(OCSPMode.FAIL_OPEN) - .build()); - assertTrue( - "Failed to get files with down-scoped token", - statement.execute( - "GET @" + testStageName + " 'file://" + destFolderCanonicalPath + "/'")); - assertTrue( - isFileContentEqual( - srcPath, false, destFolderCanonicalPath + "/" + targetFileName, true)); - } - } - } finally { - statement.execute("DROP STAGE if exists " + testStageName); + SFSession sfSession = connection.unwrap(SnowflakeConnectionV1.class).getSfSession(); + + // Test put file with internal compression + String putCommand = "put file:///dummy/path/file1.gz @" + testStageName; + SnowflakeFileTransferAgent sfAgent = + new SnowflakeFileTransferAgent(putCommand, sfSession, new SFStatement(sfSession)); + List metadataList = sfAgent.getFileTransferMetadatas(); + assert (metadataList.size() == 1); + SnowflakeFileTransferMetadata oneMetadata = metadataList.get(0); + assert (!oneMetadata.isForOneFile()); + + // Upload multiple file with the same SnowflakeFileTransferMetadata + String[] fileNames = {TEST_DATA_FILE, TEST_DATA_FILE_2}; + for (String fileName : fileNames) { + String srcPath = getFullPathFileInResource(fileName); + InputStream inputStream = new FileInputStream(srcPath); + // upload file 1 + String targetFileName = fileName + ".gz"; + SnowflakeFileTransferAgent.uploadWithoutConnection( + SnowflakeFileTransferConfig.Builder.newInstance() + .setSnowflakeFileTransferMetadata(oneMetadata) + .setUploadStream(inputStream) + .setDestFileName(targetFileName) + .setRequireCompress(true) + .setNetworkTimeoutInMilli(0) + .setOcspMode(OCSPMode.FAIL_OPEN) + .build()); + assertTrue( + "Failed to get files with down-scoped token", + statement.execute( + "GET @" + testStageName + " 'file://" + destFolderCanonicalPath + "/'")); + assert (isFileContentEqual( + srcPath, false, destFolderCanonicalPath + "/" + targetFileName, true)); + inputStream.close(); + } + } finally { + if (connection != null) { + connection.createStatement().execute("DROP STAGE if exists " + testStageName); + connection.close(); } } } diff --git a/thin_public_pom.xml b/thin_public_pom.xml index 239e31e34..474f8e44c 100644 --- a/thin_public_pom.xml +++ b/thin_public_pom.xml @@ -44,7 +44,6 @@ 2.21.0 2.22.6 1.12.0 - 1.19.0 2.31.0 32.1.1-jre 1.43.3 @@ -145,11 +144,6 @@ gax ${google.gax.version}
- - com.google.auth - google-auth-library-oauth2-http - ${google.auth.library.oauth2.http.version} - com.google.cloud google-cloud-core