[SNOW-3249917] JDBC removal Step 8d: Replicate storage client implementations#1124
Open
sfc-gh-ggeng wants to merge 12 commits intojdbc-removal-step8c-swap-all-importsfrom
Open
[SNOW-3249917] JDBC removal Step 8d: Replicate storage client implementations#1124sfc-gh-ggeng wants to merge 12 commits intojdbc-removal-step8c-swap-all-importsfrom
sfc-gh-ggeng wants to merge 12 commits intojdbc-removal-step8c-swap-all-importsfrom
Conversation
9b988de to
9bed824
Compare
6e81a56 to
38b099c
Compare
4 tasks
Restructured remaining steps: - Step 8c: helper classes + interface (PR #1123, done) - Step 8d: storage client implementations (S3/Azure/GCS + factory + uploadWithoutConnection) — next PR - Step 8e: swap ALL imports at once (after full stack replicated) - Steps 9a-9c and 10 unchanged Added progress summary table with all PRs. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…metadata impls, helpers Verbatim replication of remaining JDBC storage infrastructure: - StorageClientFactory (241 lines) — creates cloud-specific clients - S3ObjectMetadata (67 lines) — S3 StorageObjectMetadata impl - CommonObjectMetadata (84 lines) — Azure/GCS StorageObjectMetadata impl - FileCompressionType enum (47 lines) — from snowflake-common - HttpHeadersCustomizer interface (47 lines) — HTTP header customization - HeaderCustomizerHttpRequestInterceptor (159 lines) — HTTP interceptor Also fixed SnowflakeFileTransferConfig: restored SFSession type (was incorrectly replaced with Object). StorageClientFactory references SnowflakeS3Client/SnowflakeAzureClient/ SnowflakeGCSClient which are not yet replicated — will compile once the three client implementations are added. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…clients + helpers Verbatim replication of the three JDBC cloud storage client implementations: - SnowflakeS3Client (1043 lines) — S3 upload/download with encryption - SnowflakeAzureClient (1058 lines) — Azure Blob upload/download - SnowflakeGCSClient (1283 lines) — GCS upload/download with presigned URLs Plus additional helper classes discovered during replication: - S3HttpUtil (132 lines) — S3 proxy configuration - S3StorageObjectMetadata (80 lines) — S3 metadata wrapper - QueryIdHelper (11 lines) — encryption material query ID helper Does not yet compile — session-dependent code paths reference JDBC types (SFSession.getHttpClientKey(), session.getHttpHeaderCustomizers(), renewExpiredToken). These paths are never executed (session always null) and will be resolved in a follow-up commit. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add GCSAccessStrategy interface + GCSDefaultAccessStrategy + GCSAccessStrategyAwsSdk implementations (646 lines total) - Add renewExpiredToken stub to SnowflakeFileTransferAgent (session-only, never called from streaming ingest) - Add createCaseInsensitiveMap(Header[]) and convertSystemPropertyToBooleanValue to StorageClientUtil - Fix S3HttpUtil.setProxyForS3 to accept JDBC's HttpClientSettingsKey (session.getHttpClientKey() returns JDBC type) - Wrap session.getHttpClientKey() calls in try-catch for JDBC's SnowflakeSQLException (different class from ingest's) - Fix HttpClientSettingsKey type bridge in GCS presigned URL upload - Fix SqlState imports in GCS access strategies All 30 compile errors resolved. Production and test code compile cleanly. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ated SnowflakeFileTransferAgent Verbatim replication of upload methods from JDBC's SnowflakeFileTransferAgent: - uploadWithoutConnection(SnowflakeFileTransferConfig) — main upload entry point - pushFileToRemoteStore — S3/Azure upload via SnowflakeStorageClient - pushFileToRemoteStoreWithPresignedUrl — GCS upload with presigned URLs - computeDigest, compressStreamWithGZIP, compressStreamWithGZIPNoDigest - InputStreamWithMetadata inner class - remoteLocation inner class + extractLocationAndPath - MAX_BUFFER_SIZE constant Also fixed: removed stale JDBC CommandType bridge (now uses ingest's CommandType directly since SnowflakeFileTransferMetadataV1 is ingest's), fixed return type of getFileTransferMetadatas to use ingest's SnowflakeFileTransferMetadata interface. Full JDBC storage stack now compiles. Step 8d replication complete. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…es exactly The Step 7a replication incorrectly simplified these method signatures by dropping parameters (queryId, session). This caused cascading unexpected differences in all storage client replications. StorageClientUtil now matches JDBC's SnowflakeFileTransferAgent exactly: - throwJCEMissingError(String, Exception) — deprecated, delegates to 3-arg - throwJCEMissingError(String, Exception, String queryId) — main impl - throwNoSpaceLeftError(SFSession, String, Exception) — deprecated, delegates - throwNoSpaceLeftError(SFSession, String, Exception, String queryId) — main Updated all callers: - Snowflake clients (S3/Azure/GCS): now pass (operation, ex, queryId) and (session, operation, ex, queryId) — matching JDBC verbatim - Iceberg clients: pass null for session (no session available) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…auses Instead of catching and wrapping JDBC's SnowflakeSQLException in session-dependent code paths, add it to the throws clause — matching JDBC's original behavior where session.getHttpClientKey() throws it. Updated throws clauses in: - SnowflakeS3Client: constructor + setupSnowflakeS3Client + renew - SnowflakeAzureClient: createSnowflakeAzureClient + setupAzureClient + renew - SnowflakeGCSClient: createSnowflakeGCSClient + setupGCSClient + renew - GCSAccessStrategyAwsSdk: constructor - StorageClientFactory: createClient + createS3Client + createAzureClient + createGCSClient - SnowflakeStorageClient: renew interface method Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The replicated Snowflake storage clients should use JDBC's HttpClientSettingsKey (net.snowflake.client.core.HttpClientSettingsKey) everywhere — matching JDBC verbatim. Ingest's HttpClientSettingsKey is only for the Iceberg clients. Changes: - SnowflakeFileTransferAgent.uploadWithoutConnection: use JDBC's SnowflakeUtil.convertProxyPropertiesToHttpClientKey (returns JDBC type) - SnowflakeStorageClient interface: uploadWithPresignedUrlWithoutConnection and upload take JDBC's HttpClientSettingsKey - SnowflakeGCSClient: uploadWithPresignedUrl takes JDBC's type, removed null placeholder and HttpUtil.getHttpClient bridge — now matches JDBC verbatim: session.getHttpClientKey() passed directly - pushFileToRemoteStoreWithPresignedUrl: takes JDBC's HttpClientSettingsKey Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ceptor directly The replicated Snowflake stack should use JDBC's types for session- dependent code, not ingest's. session.getHttpHeadersCustomizers() returns JDBC's List<HttpHeadersCustomizer> — pass it directly to JDBC's HeaderCustomizerHttpRequestInterceptor. Removed the unchecked cast workaround in SnowflakeS3Client and GCSAccessStrategyAwsSdk. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Now includes mimeSubTypes list, mimeSubTypeToCompressionMap, and lookupByMimeSubType/lookupByFileExtension methods — matching the full snowflake-common decompiled source. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…PathFromCommand Replaced stubs with verbatim copies from JDBC, using JDBC imports for SFStatement, ExecTimeTelemetryData, SFException, SecretDetector, and SnowflakeUtil.checkErrorAndThrowException. Also restored pushFileToRemoteStore's requirePresignedUrl() block and ArgSupplier lambda in debug log — both were previously removed. No more stubs or omissions in the replicated SnowflakeFileTransferAgent. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
renewExpiredToken throws both ingest and JDBC SnowflakeSQLException. Propagate the JDBC exception through all callers in the storage client interface and implementations (S3, Azure, GCS). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
4582b92 to
b124d44
Compare
9bed824 to
b7666c2
Compare
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Verbatim replication of the full JDBC storage client stack (~7,000 lines total).
Storage client implementations
SnowflakeS3Client(1043 lines) — S3 upload/download with encryptionSnowflakeAzureClient(1058 lines) — Azure Blob upload/downloadSnowflakeGCSClient(1283 lines) — GCS upload/download with presigned URLsFactory and helpers
StorageClientFactory(241 lines) — creates cloud-specific clientsS3HttpUtil(132 lines) — S3 proxy configurationS3ObjectMetadata(67 lines),S3StorageObjectMetadata(80 lines) — S3 metadataCommonObjectMetadata(84 lines) — Azure/GCS metadataQueryIdHelper(11 lines) — encryption query ID helperFileCompressionType(47 lines) — compression type enumHttpHeadersCustomizer(47 lines) — HTTP header customization interfaceHeaderCustomizerHttpRequestInterceptor(159 lines) — HTTP request interceptorGCSAccessStrategy(50 lines),GCSDefaultAccessStrategy(250 lines),GCSAccessStrategyAwsSdk(346 lines)uploadWithoutConnection in SnowflakeFileTransferAgent
uploadWithoutConnection(SnowflakeFileTransferConfig)— main upload methodpushFileToRemoteStore,pushFileToRemoteStoreWithPresignedUrlcomputeDigest,compressStreamWithGZIP,compressStreamWithGZIPNoDigestInputStreamWithMetadata,remoteLocation,extractLocationAndPath,MAX_BUFFER_SIZEStorageClientUtil additions
createCaseInsensitiveMap(Header[])— overload for Apache HTTP headersconvertSystemPropertyToBooleanValue— boolean system property readerthrowJCEMissingError— fixed to match JDBC's exact signatures (2-arg + 3-arg with queryId)throwNoSpaceLeftError— fixed to match JDBC's exact signatures (3-arg + 4-arg with session + queryId)Stacked on #1123.
Replication Verification Diff Report
All classes are line-by-line replications of JDBC v3.25.1 sources. Common permitted mechanical differences across all files:
net.snowflake.ingest.streaming.internal.fileTransferAgentSFLogger/SFLoggerFactory→ ingest's replicated versions@SnowflakeJdbcInternalApi/@SnowflakeOrgInternalApiremovedSnowflakeUtilstatic methods →StorageClientUtilequivalentsSFPair/Stopwatch→net.snowflake.ingest.utilsversionsSFSession/SFBaseSession/SFSessionPropertykept from JDBC temporarily (always null from callers)SnowflakeS3Client
JDBC source :
net/snowflake/client/jdbc/cloud/storage/SnowflakeS3Client.java@ v3.25.1Permitted differences (mechanical):
SFSSLConnectionSocketFactory→IngestSSLConnectionSocketFactoryConstants.CLOUD_STORAGE_CREDENTIALS_EXPIRED→ErrorCode.CLOUD_STORAGE_CREDENTIALS_EXPIREDSnowflakeFileTransferAgent.throwJCEMissingError→StorageClientUtil.throwJCEMissingErrorSnowflakeFileTransferAgent.throwNoSpaceLeftError→StorageClientUtil.throwNoSpaceLeftErrorHttpUtil.isSocksProxyDisabled()→ ingest'sHttpUtil.isSocksProxyDisabled()net.snowflake.client.jdbc.SnowflakeSQLExceptionadded to throws clauses (session.getHttpClientKey() throws it)Unexpected differences:
SnowflakeUtil.assureOnlyUserAccessibleFilePermissionskept from JDBC (download path only, no ingest equivalent)SnowflakeAzureClient
JDBC source :
net/snowflake/client/jdbc/cloud/storage/SnowflakeAzureClient.java@ v3.25.1Permitted differences (mechanical):
HttpUtil.setProxyForAzure/setSessionlessProxyForAzurekept from JDBCnet.snowflake.client.jdbc.SnowflakeSQLExceptionadded to throws clausesUnexpected differences:
SnowflakeUtil.assureOnlyUserAccessibleFilePermissionskept from JDBC (download path only)SnowflakeGCSClient
JDBC source :
net/snowflake/client/jdbc/cloud/storage/SnowflakeGCSClient.java@ v3.25.1Permitted differences (mechanical):
HttpClientSettingsKeythroughout (matching JDBC verbatim)HttpUtil,RestRequest,ExecTimeTelemetryData,HttpResponseContextDtofor presigned URL uploadnet.snowflake.client.jdbc.SnowflakeSQLExceptionadded to throws clausesUnexpected differences:
SnowflakeUtil.assureOnlyUserAccessibleFilePermissionskept from JDBC (download path only)StorageClientFactory
JDBC source :
net/snowflake/client/jdbc/cloud/storage/StorageClientFactory.java@ v3.25.1Permitted differences (mechanical):
HttpUtil.isSocksProxyDisabled()→ ingest'sHttpUtilnet.snowflake.client.jdbc.SnowflakeSQLExceptionadded to throws clausesUnexpected differences: NONE
S3HttpUtil
JDBC source :
net/snowflake/client/jdbc/cloud/storage/S3HttpUtil.java@ v3.25.1Permitted differences (mechanical):
setProxyForS3takes JDBC'snet.snowflake.client.core.HttpClientSettingsKey(matching JDBC — session.getHttpClientKey() returns this type)SFLoggerUtil.isVariableProvidedkept from JDBCUnexpected differences: NONE
GCSAccessStrategy / GCSDefaultAccessStrategy / GCSAccessStrategyAwsSdk
JDBC sources :
net/snowflake/client/jdbc/cloud/storage/GCSAccessStrategy*.java@ v3.25.1Permitted differences (mechanical):
net.snowflake.client.jdbc.SnowflakeSQLExceptionadded to throws clausesUnexpected differences: NONE
S3ObjectMetadata / S3StorageObjectMetadata / CommonObjectMetadata
JDBC sources :
S3ObjectMetadata.java,S3StorageObjectMetadata.java,CommonObjectMetadata.java@ v3.25.1Unexpected differences: NONE
HttpHeadersCustomizer / HeaderCustomizerHttpRequestInterceptor
JDBC sources :
HttpHeadersCustomizer.java,HeaderCustomizerHttpRequestInterceptor.java@ v3.25.1Unexpected differences:
AttributeEnhancingHttpRequestRetryHandler.EXECUTION_COUNT_ATTRIBUTEinlined as constant stringFileCompressionType / QueryIdHelper
JDBC sources :
FileCompressionType.java(from snowflake-common),QueryIdHelper.java@ v3.25.1Unexpected differences:
SnowflakeFileTransferAgent (modifications)
Added methods replicated from JDBC's
SnowflakeFileTransferAgent.java@ v3.25.1:Permitted differences (mechanical):
OCSPMode→ ingest's version inuploadWithoutConnectionSnowflakeUtil.convertProxyPropertiesToHttpClientKey(returns JDBC'sHttpClientSettingsKey)HttpClientSettingsKeyinpushFileToRemoteStoreWithPresignedUrlgetFileTransferMetadatasreturn type uses ingest'sSnowflakeFileTransferMetadataCommandTypeuses ingest's version (same package)Unexpected differences:
StorageClientUtil (modifications)
Added methods replicated from JDBC's
SnowflakeUtil:createCaseInsensitiveMap(Header[])— verbatimconvertSystemPropertyToBooleanValue— verbatimthrowJCEMissingError— now matches JDBC's exact signatures (2-arg deprecated + 3-arg with queryId)throwNoSpaceLeftError— now matches JDBC's exact signatures (3-arg deprecated + 4-arg with session + queryId)Test plan
mvn compiler:compilepasses (0 errors)mvn test-compilepasses (0 errors)./format.shpasses🤖 Generated with Claude Code