Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 15 additions & 11 deletions .plans/JDBC_REMOVAL_PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ eliminate the JDBC dependency entirely.

**This project is a pure mechanical migration. There must be no functional changes.**

- **Always replicate** — no matter how many dependencies, replicate the JDBC original
verbatim. Never create "simplified replacements" or "minimal viable alternatives."
- Copy JDBC classes verbatim into this repo. Compare against the actual source file
in the JDBC repo (not decompiled output). Do not refactor, simplify, rename fields,
change method signatures, strip comments/Javadoc, or improve logic — even where
Expand Down Expand Up @@ -253,7 +255,7 @@ is replaced.

---

### Progress Summary (updated 2026-04-01)
### Progress Summary (updated 2026-04-06)

| Step | Status | PR |
|---|---|---|
Expand All @@ -274,18 +276,20 @@ is replaced.
| Step 8e — Swap ALL imports (pure import swaps) | ✅ MERGED | #1127 |
| Step 9a — Mechanical import swaps in replicated classes | ✅ MERGED | #1128 |
| Step 9b-prep — Replicate OOB telemetry deps | ✅ MERGED | #1129 |
| Step 9b — Replicate TelemetryEvent + TelemetryService | ✅ Open | #1130 |
| Step 9c — Swap telemetry imports | ✅ Open | #1131 |
| Step 10a — Replicate SFException, ExecTimeTelemetryData, etc. | ✅ Open | #1132 |
| Step 10b — Swap SFException imports | ✅ Open | #1134 |
| Step 9b — Replicate TelemetryEvent + TelemetryService | ✅ MERGED | #1130 |
| Step 9c — Swap telemetry imports | ✅ MERGED | #1131 |
| Step 10a — Replicate SFException, ExecTimeTelemetryData, etc. | ✅ MERGED | #1132 |
| Step 10b — Swap SFException imports | ✅ MERGED | #1134 |
| Step 10c — Remove SFSession from storage stack | ✅ Open | #1135 |
| Step 10c2 — Remove SFSession from exceptions + telemetry | ✅ Open | #1136 |
| Step 11a — Replace JDBC HTTP calls with HttpRequestHelper | ⬜ TODO | — |
| Step 11b — Remove FQN SnowflakeSQLException from throws | ⬜ TODO | — |
| Step 11c — Clean up remaining FQN JDBC references | ⬜ TODO | — |
| Step 11d — Demote JDBC to test scope | ⬜ TODO | — |

**Closed PRs:** #1117 (reverted 7b approach), #1122 (reverted 8c approach)
| Step 11a — Replicate RestRequest and HTTP retry infrastructure | ✅ Open | #1143 |
| Step 11a-p2 — Replicate HttpUtil, swap callers | ✅ Open | #1144 |
| Step 11b — Clean up remaining FQN JDBC references | ✅ Open | #1145 |
| Step 11d — Demote JDBC to test scope | ✅ Open | #1146 |

**Closed PRs:** #1117 (reverted 7b approach), #1122 (reverted 8c approach),
#1137 (superseded 10d), #1138 (superseded 11a), #1139-#1141 (superseded 11b-d),
#1142 (combined 11a-d, split into #1143-#1146)
**Other PRs:** #1118 (error/exception tests on master), #1133 (Maven retry config)

---
Expand Down
4 changes: 4 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -985,6 +985,10 @@
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcutil-jdk18on</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
import java.util.LinkedList;
import java.util.Objects;
import java.util.concurrent.Future;
import net.snowflake.client.core.HttpUtil;
import net.snowflake.client.jdbc.SnowflakeSQLException;
import net.snowflake.ingest.streaming.internal.fileTransferAgent.JdbcHttpUtil;
import net.snowflake.ingest.streaming.internal.fileTransferAgent.ObjectMapperFactory;
import net.snowflake.ingest.streaming.internal.fileTransferAgent.SnowflakeSQLException;
import net.snowflake.ingest.streaming.internal.fileTransferAgent.TelemetryThreadPool;
import net.snowflake.ingest.streaming.internal.fileTransferAgent.log.SFLogger;
import net.snowflake.ingest.streaming.internal.fileTransferAgent.log.SFLoggerFactory;
Expand Down Expand Up @@ -275,11 +275,11 @@ private boolean sendBatch() throws IOException {

try {
response =
HttpUtil.executeGeneralRequest(
JdbcHttpUtil.executeGeneralRequest(
post,
TELEMETRY_HTTP_RETRY_TIMEOUT_IN_SEC,
0,
(int) HttpUtil.getSocketTimeout().toMillis(),
(int) JdbcHttpUtil.getSocketTimeout().toMillis(),
0,
this.httpClient);
stopwatch.stop();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Replicated from snowflake-jdbc (v3.25.1)
* Source: https://github.com/snowflakedb/snowflake-jdbc/blob/v3.25.1/src/main/java/net/snowflake/client/core/AttributeEnhancingHttpRequestRetryHandler.java
*
* Permitted differences: package declaration.
*/
package net.snowflake.ingest.streaming.internal.fileTransferAgent;

import java.io.IOException;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.protocol.HttpContext;

/**
* Extends {@link DefaultHttpRequestRetryHandler} to store the current execution count (attempt
* number) in the {@link HttpContext}. This allows interceptors to identify retry attempts.
*
* <p>The execution count is stored using the key defined by {@link #EXECUTION_COUNT_ATTRIBUTE}.
*/
class AttributeEnhancingHttpRequestRetryHandler extends DefaultHttpRequestRetryHandler {
/**
* The key used to store the current execution count (attempt number) in the {@link HttpContext}.
* Interceptors can use this key to retrieve the count. The value stored will be an {@link
* Integer}.
*/
static final String EXECUTION_COUNT_ATTRIBUTE = "net.snowflake.client.core.execution-count";

@Override
public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
context.setAttribute(EXECUTION_COUNT_ATTRIBUTE, executionCount);
return super.retryRequest(exception, executionCount, context);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Replicated from snowflake-jdbc (v3.25.1)
* Source: https://github.com/snowflakedb/snowflake-jdbc/blob/v3.25.1/src/main/java/net/snowflake/client/core/Constants.java
*
* Permitted differences: package declaration,
* SnowflakeUtil.systemGetProperty -> StorageClientUtil.systemGetProperty.
*/
package net.snowflake.ingest.streaming.internal.fileTransferAgent;

import static net.snowflake.ingest.streaming.internal.fileTransferAgent.StorageClientUtil.systemGetProperty;

/*
* Constants used in JDBC implementation
*/
public final class Constants {
// Session expired error code as returned from Snowflake
public static final int SESSION_EXPIRED_GS_CODE = 390112;

// Cloud storage credentials expired error code
public static final int CLOUD_STORAGE_CREDENTIALS_EXPIRED = 240001;

// Session gone error code as returned from Snowflake
public static final int SESSION_GONE = 390111;

// Error code for all invalid id token cases during login request
public static final int ID_TOKEN_INVALID_LOGIN_REQUEST_GS_CODE = 390195;

public static final int OAUTH_ACCESS_TOKEN_EXPIRED_GS_CODE = 390318;

public static final int OAUTH_ACCESS_TOKEN_INVALID_GS_CODE = 390303;

// Error message for IOException when no space is left for GET
public static final String NO_SPACE_LEFT_ON_DEVICE_ERR = "No space left on device";

public enum OS {
WINDOWS,
LINUX,
MAC,
SOLARIS
}

private static OS os = null;

public static synchronized OS getOS() {
if (os == null) {
String operSys = systemGetProperty("os.name").toLowerCase();
if (operSys.contains("win")) {
os = OS.WINDOWS;
} else if (operSys.contains("nix") || operSys.contains("nux") || operSys.contains("aix")) {
os = OS.LINUX;
} else if (operSys.contains("mac")) {
os = OS.MAC;
} else if (operSys.contains("sunos")) {
os = OS.SOLARIS;
}
}
return os;
}

public static void clearOSForTesting() {
os = null;
}

public static final int MB = 1024 * 1024;
public static final long GB = 1024 * 1024 * 1024;
}
Loading
Loading