diff --git a/NEXT_CHANGELOG.md b/NEXT_CHANGELOG.md index 6c27fbc1ac..c9388cda73 100644 --- a/NEXT_CHANGELOG.md +++ b/NEXT_CHANGELOG.md @@ -6,6 +6,7 @@ - Added `EnableThriftNativeMetadata` to request and consume supported Thrift-native SEA metadata results. ### Updated +- `UseBoundedSeaApi` and `EnableThriftNativeMetadata` now default to `1`; when unset, activation is controlled by the server-side `enableSqlExecForJdbc` rollout flag. - `DatabaseMetaData.getColumns(...)` with a `null` catalog now issues a single `SHOW COLUMNS IN ALL CATALOGS` statement (consistent with `getSchemas`/`getTables`) instead of enumerating every catalog and issuing a per-catalog `SHOW COLUMNS`. Older DBR versions that do not support the syntax transparently fall back to the previous enumerate-and-fan-out behavior. - Updated bundled Jackson, lz4-java, Netty, and Apache HttpComponents Client and Core dependencies to patched versions to address security findings. diff --git a/src/main/java/com/databricks/jdbc/api/impl/DatabricksConnectionContext.java b/src/main/java/com/databricks/jdbc/api/impl/DatabricksConnectionContext.java index 25f8d1bbe7..de58419856 100644 --- a/src/main/java/com/databricks/jdbc/api/impl/DatabricksConnectionContext.java +++ b/src/main/java/com/databricks/jdbc/api/impl/DatabricksConnectionContext.java @@ -1519,7 +1519,8 @@ public boolean isSeaSyncMetadataEnabled() { @Override public boolean isThriftNativeMetadataEnabled() { - return getParameter(DatabricksJdbcUrlParams.ENABLE_THRIFT_NATIVE_METADATA).equals("1"); + return resolveFeatureFlag( + DatabricksJdbcUrlParams.ENABLE_THRIFT_NATIVE_METADATA, SQL_EXEC_FLAG_NAME); } @Override @@ -1549,7 +1550,7 @@ public boolean isCloudFetchEnabled() { @Override public boolean isBoundedSeaApiEnabled() { - return getParameter(DatabricksJdbcUrlParams.USE_BOUNDED_SEA_API).equals("1"); + return resolveFeatureFlag(DatabricksJdbcUrlParams.USE_BOUNDED_SEA_API, SQL_EXEC_FLAG_NAME); } @Override diff --git a/src/main/java/com/databricks/jdbc/common/DatabricksJdbcUrlParams.java b/src/main/java/com/databricks/jdbc/common/DatabricksJdbcUrlParams.java index 5c983a003f..7b575910b7 100644 --- a/src/main/java/com/databricks/jdbc/common/DatabricksJdbcUrlParams.java +++ b/src/main/java/com/databricks/jdbc/common/DatabricksJdbcUrlParams.java @@ -215,11 +215,11 @@ public enum DatabricksJdbcUrlParams { USE_BOUNDED_SEA_API( "UseBoundedSeaApi", "Use bounded SEA API for CloudFetch: send row_offset on GetResultData, force StreamingChunkProvider, stop relying on total_chunk_count. Requires server support.", - "0"), + "1"), ENABLE_THRIFT_NATIVE_METADATA( "EnableThriftNativeMetadata", "Request Thrift-native SEA results for catalogs, schemas, tables, columns, functions, primary keys, imported keys, and cross references", - "0"), + "1"), DISABLE_OAUTH_REFRESH_TOKEN( "DisableOauthRefreshToken", "Disable requesting OAuth refresh tokens (omit offline_access unless explicitly provided)", diff --git a/src/test/java/com/databricks/jdbc/api/impl/DatabricksConnectionContextTest.java b/src/test/java/com/databricks/jdbc/api/impl/DatabricksConnectionContextTest.java index 3fcf26aff6..ed9c6df824 100644 --- a/src/test/java/com/databricks/jdbc/api/impl/DatabricksConnectionContextTest.java +++ b/src/test/java/com/databricks/jdbc/api/impl/DatabricksConnectionContextTest.java @@ -20,6 +20,7 @@ import com.databricks.jdbc.exception.DatabricksVendorCode; import com.databricks.sdk.core.ProxyConfig; import com.google.common.collect.ImmutableMap; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -27,6 +28,7 @@ import java.util.Map; import java.util.Properties; import java.util.stream.Stream; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -39,6 +41,7 @@ class DatabricksConnectionContextTest { private static final Properties properties = new Properties(); private static final Properties properties_with_pwd = new Properties(); + private final List featureFlagContextsToCleanUp = new ArrayList<>(); @BeforeAll public static void setUp() { @@ -46,6 +49,18 @@ public static void setUp() { properties_with_pwd.setProperty("pwd", "passwd2"); } + @AfterEach + public void cleanUpFeatureFlagContexts() { + featureFlagContextsToCleanUp.forEach( + DatabricksDriverFeatureFlagsContextFactory::removeInstance); + } + + private void setFeatureFlagsContext( + IDatabricksConnectionContext context, Map flags) { + featureFlagContextsToCleanUp.add(context); + DatabricksDriverFeatureFlagsContextFactory.setFeatureFlagsContext(context, flags); + } + @Test public void testBuildPropertiesMap() { String connectionParamString = "param1=value1;param2=value2"; @@ -1677,6 +1692,82 @@ public void testUseQueryForMetadata_clientExplicit0_overridesServerFlagEnabled() assertFalse(ctx.useQueryForMetadata()); } + @Test + public void testNativeMetadataViaSea_serverFlagEnabled_warehouseReturnsTrue() + throws DatabricksSQLException { + DatabricksConnectionContext ctx = + (DatabricksConnectionContext) + DatabricksConnectionContext.parse(TestConstants.VALID_URL_1, properties); + + Map flags = new HashMap<>(); + flags.put("databricks.partnerplatform.clientConfigsFeatureFlags.enableSqlExecForJdbc", "true"); + setFeatureFlagsContext(ctx, flags); + + assertEquals("1", DatabricksJdbcUrlParams.USE_BOUNDED_SEA_API.getDefaultValue()); + assertEquals("1", DatabricksJdbcUrlParams.ENABLE_THRIFT_NATIVE_METADATA.getDefaultValue()); + assertTrue(ctx.isBoundedSeaApiEnabled()); + assertTrue(ctx.isThriftNativeMetadataEnabled()); + } + + @Test + public void testNativeMetadataViaSea_serverFlagDisabled_warehouseReturnsFalse() + throws DatabricksSQLException { + DatabricksConnectionContext ctx = + (DatabricksConnectionContext) + DatabricksConnectionContext.parse(TestConstants.VALID_URL_1, properties); + + Map flags = new HashMap<>(); + flags.put("databricks.partnerplatform.clientConfigsFeatureFlags.enableSqlExecForJdbc", "false"); + setFeatureFlagsContext(ctx, flags); + + assertFalse(ctx.isBoundedSeaApiEnabled()); + assertFalse(ctx.isThriftNativeMetadataEnabled()); + } + + @Test + public void testNativeMetadataViaSea_serverFlagEnabled_clusterIgnored() + throws DatabricksSQLException { + DatabricksConnectionContext ctx = + (DatabricksConnectionContext) + DatabricksConnectionContext.parse(TestConstants.VALID_CLUSTER_URL, properties); + + Map flags = new HashMap<>(); + flags.put("databricks.partnerplatform.clientConfigsFeatureFlags.enableSqlExecForJdbc", "true"); + setFeatureFlagsContext(ctx, flags); + + assertFalse(ctx.isBoundedSeaApiEnabled()); + assertFalse(ctx.isThriftNativeMetadataEnabled()); + } + + @Test + public void testNativeMetadataViaSea_explicitParamsOverrideServerFlag() + throws DatabricksSQLException { + DatabricksConnectionContext enabledCtx = + (DatabricksConnectionContext) + DatabricksConnectionContext.parse( + TestConstants.VALID_URL_1 + ";UseBoundedSeaApi=1;EnableThriftNativeMetadata=1", + properties); + DatabricksConnectionContext disabledCtx = + (DatabricksConnectionContext) + DatabricksConnectionContext.parse( + TestConstants.VALID_URL_1 + ";UseBoundedSeaApi=0;EnableThriftNativeMetadata=0", + properties); + + Map disabledFlag = new HashMap<>(); + disabledFlag.put( + "databricks.partnerplatform.clientConfigsFeatureFlags.enableSqlExecForJdbc", "false"); + setFeatureFlagsContext(enabledCtx, disabledFlag); + Map enabledFlag = new HashMap<>(); + enabledFlag.put( + "databricks.partnerplatform.clientConfigsFeatureFlags.enableSqlExecForJdbc", "true"); + setFeatureFlagsContext(disabledCtx, enabledFlag); + + assertTrue(enabledCtx.isBoundedSeaApiEnabled()); + assertTrue(enabledCtx.isThriftNativeMetadataEnabled()); + assertFalse(disabledCtx.isBoundedSeaApiEnabled()); + assertFalse(disabledCtx.isThriftNativeMetadataEnabled()); + } + // --------------------------------------------------------------------------- // Geospatial flag independence from complex datatype flag // ---------------------------------------------------------------------------