SqlToDatabaseModule Migration Guide
Overview
SqlToDatabaseModule is a retired compatibility shell. Version 1.0 accepted a caller-controlled JDBC URL, plaintext username and password, arbitrary SQL, named parameters, batch input, and transaction flags. It opened any driver-supported destination from the workflow worker, could execute reads or irreversible writes, returned unbounded rows and generated keys, surfaced raw provider errors, and labeled every operation idempotent. Workflow Studio also advertised a separate SqlToDatabaseConnectorModule class that did not exist in the backend while claiming two-database synchronization behavior.
Version 2.0 keeps the real Java class and Spring bean loadable so saved workflows can be inspected and migrated, but hides it from backend discovery and removes the phantom frontend fallback entry. Execution now fails closed with MODULE_RETIRED, performs no credential, driver, DNS, socket, database, query, transaction, batch, or mutation operation, and returns provider-specific migration targets.
Usage
- Find saved tasks whose class is
com.valkyrlabs.workflow.modules.database.SqlToDatabaseModuleor whose fallback type isconnector.sql.to_db. - Remove legacy JDBC URLs, usernames, passwords, SQL, and parameters. Rotate credentials if their prior execution or exposure is uncertain.
- Identify the actual provider, exact operation, selected fields, result limit, mutation intent, and reconciliation key.
- Replace the task with a governed provider-specific connector such as
SnowflakeModule,GoogleBigQueryModule,SupabaseModule, orMongoDBModuleonly when that connector supports the required operation. - Bind a least-privilege
IntegrationAccountin exactREADYstate. Do not copy credentials or arbitrary provider endpoints into module data. - Prefer an allowlisted provider operation over caller-authored SQL. For a write, require the connector's explicit confirmation and reconcile ambiguous provider state before retrying.
Inputs
The compatibility shell accepts legacy field names only so saved task configuration can be identified. It ignores every value.
| Input | Type | Active behavior |
|---|---|---|
jdbc_url | string | Ignored; never parsed, resolved, or contacted. |
username | string | Ignored; never used or emitted. |
password | string | Ignored; never used or emitted. |
sql | string | Ignored; never parsed, prepared, or executed. |
parameters | object | Ignored; never bound to a statement. |
batch_mode | boolean | Ignored; no batch is prepared. |
transaction | boolean | Ignored; no transaction is opened. |
Replacement inputs depend on the provider. Use fixed provider destinations, allowlisted operations and identifiers, bounded payloads and results, and explicit write controls.
Outputs
The retired module always returns:
| Output | Type | Description |
|---|---|---|
status | string | Always error. |
error | object | Safe MODULE_RETIRED, retryable:false, migration targets, and required action. |
It never returns rows, row counts, affected-row counts, generated keys, batch sizes, connection details, SQL text, credentials, JDBC errors, or provider messages.
IntegrationAccount Requirements
SqlToDatabaseModule never resolves an IntegrationAccount; no account, raw credential, configuration flag, or workflow role can re-enable it.
For the replacement:
- bind a provider-specific account in exact
READYstate; - grant only the database, schema, table, and operation privileges required by the workflow;
- keep credentials in
IntegrationAccountSecureFields; - fix the provider destination in the connector rather than accepting a workflow-controlled JDBC URL;
- separate read and mutation accounts when practical; and
- preserve provider receipts, caller correlation keys, and optimistic-concurrency values needed for reconciliation.
Configuration
The retired module has no active configuration. Saved JDBC URLs, usernames, passwords, SQL, named parameters, batch flags, and transaction flags are ignored.
A governed provider-specific write resembles:
{
"operation": "upsert_rows",
"table": "approved_customers",
"rows": [{ "external_id": "cust-42", "status": "active" }],
"confirm_write": true,
"correlation_key": "customer-sync-cust-42"
}
The exact fields vary by provider. Use only an operation documented by the selected connector; do not send the example to a provider that lacks the same contract.
Operations
SqlToDatabaseModule supports one compatibility operation: reject execution and identify migration targets. It does not load a JDBC driver, connect, authenticate, prepare SQL, bind parameters, read rows, begin or commit a transaction, batch statements, retry, or mutate data.
Provider-specific replacements expose only their documented operations. For example, Supabase provides bounded PostgREST row operations and RPC calls through a fixed project origin, while MongoDB exposes bounded document operations through its own IntegrationAccount contract. Choose the connector that matches the actual provider rather than treating generic SQL as a transport.
Errors and Failure Modes
| Failure | Behavior | Recovery |
|---|---|---|
| Any legacy execution | Returns MODULE_RETIRED with retryable:false. | Replace the task; retries cannot restore JDBC access. |
| Saved raw credential or credential-bearing JDBC URL | The value is ignored and not emitted. | Remove and rotate it if prior exposure is uncertain. |
| Unknown or unsupported provider | No generic JDBC fallback is attempted. | Add or harden a provider-specific connector with IntegrationAccount support. |
| Replacement account is not READY | Provider module fails before sending a request. | Repair or reauthorize the account. |
| Replacement read exceeds its bound | Provider module fails with its documented size or page error. | Narrow fields, filters, page size, or total limit. |
| Replacement write times out or returns an ambiguous response | The write is not assumed successful and must not be blindly replayed. | Reconcile provider state using its receipt or correlation key. |
| Replacement rejects a destructive operation | No mutation occurs. | Use an allowlisted operation and obtain the required confirmation or approval. |
Example
A saved legacy task reaches the compatibility shell:
{
"jdbc_url": "jdbc:postgresql://db.internal/app",
"username": "workflow_writer",
"password": "redacted",
"sql": "UPDATE accounts SET active = false WHERE id = :id",
"parameters": { "id": 42 },
"transaction": true
}
Expected result:
{
"status": "error",
"error": {
"code": "MODULE_RETIRED",
"message": "SqlToDatabaseModule is retired; use an approved provider-specific database connector",
"retryable": false,
"migrationTargets": [
"SnowflakeModule",
"GoogleBigQueryModule",
"SupabaseModule",
"MongoDBModule"
]
}
}
Notes
- Pagination: the compatibility shell never paginates because it performs no read. Configure provider-native cursors, page sizes, and total result bounds on the replacement.
- Limits: the shell returns a two-field response immediately and never materializes SQL, parameters, rows, batches, or generated keys.
- Idempotency: the retired response is deterministic and side-effect free. Version 1.0's universal idempotency claim was false for arbitrary SQL writes. A replacement write is idempotent only when the provider contract and caller-owned key prove it.
- API constraints: generic JDBC destinations, driver selection, arbitrary SQL, and credentials in workflow state are no longer accepted. Each replacement must fix or strictly derive its provider origin and enforce its own allowlist.
- Destructive behavior: the shell cannot mutate data. Replacement deletes, bulk updates, DDL, stored procedures, or other irreversible operations require a provider-specific contract, explicit confirmation, and independent reconciliation.
- Runtime deployment: source, tests, frontend fallback, and documentation can be merged and published independently, but live Workflow Studio continues to show version 1.0 until a normal backend deployment includes version 2.0.
- Unverified boundary: deterministic tests prove fail-closed output, secret non-disclosure, repeatability, discovery exclusion, direct compatibility lookup, and frontend fallback removal. No live database request is performed because the retired module intentionally has no provider behavior.