JDBC sources
Introduction
A source can front any database that ships a JDBC driver: NetSuite, Snowflake, Databricks, BigQuery, SQL Server, Oracle, Trino, and the thirty-odd others in the preset list below. You bring the driver jar; swarmvia loads it in an isolated Java runtime that belongs to your organization alone, dials the database with a login that never leaves swarmvia, and serves the result over the same endpoint every database source has.
To a caller a JDBC source is a database source: the
same POST / query body, the same /structure, the same job handles,
the same MCP tools, the same concurrency limit and access log. Only the leg
after admission differs, and nothing about it is specific to a vendor. Presets
are data. A vendor swarmvia has never heard of works with the generic preset.
Use the native Postgres and MySQL backends for those engines. A JDBC source exists for everything else, and for the rare case where a driver feature matters more than the lighter native path.
The endpoints
POST https://{source}.swarmvia.cloud
GET https://{source}.swarmvia.cloud/structure
GET https://{source}.swarmvia.cloud/__nth/jobs/{jobId}Identical to a database source: X-Swarmvia-Key, queries with bound
parameters, maxRows, waitMs, rowFormat. Two differences a caller sees:
- Placeholders are
?, never$1. JDBC drivers take positional?markers and every vendor agrees on that. - Every cell is text. The driver's
getString()of each value is returned as the JSON string it printed, ornull. Column types are the driver's own names (NUMBER,varchar,TIMESTAMP_NTZ). Nothing is cast on the way out, because the vendor's text form is the one its users recognize.
Drivers
A driver is the jar a source loads. There are two ways to set it, both on the source:
- Maven coordinates (
group:artifact:version) for drivers published on Maven Central, which most are. Vendor templates fill these in. swarmvia fetches the jar when you save, verifies its SHA-1 against Central, and stores it, so a query never depends on Central being up. Sources with the same coordinates share one stored jar. - Upload the jar for drivers a vendor only hands out from its own site (NetSuite, BigQuery's Simba driver, Dremio, Sybase, Netezza, Denodo).
If a vendor's download page asks for an operating system, choose Linux 64-bit (x86-64, glibc). Every source runs there, on Java 21, so take a build for Java 8 through 21; a build for a newer Java will not load. Take the JDBC download, not ODBC.
Every jar is inspected before it is accepted: it must be a real jar and declare
at least one java.sql.Driver in META-INF/services. Up to 150 MB per jar and
1 GB per organization.
To upgrade one source, change its coordinates. To upgrade every source on a driver, use Change version (or Replace, for an upload) under Drivers in the sidebar. Each source picks the new jar up on its next connection; the old version is removed once every source has been told about the new one. A driver still used by a source cannot be deleted; point those sources elsewhere first.
The jar runs only in your organization's runtime, with your sources' logins, which it receives per request. It never shares a process with another customer's code and never sees another organization's secret.
Presets
A preset fills the form: the driver to fetch, the URL template, the property rows the driver expects, and where an access token goes. Pick one under Sources → New source → JDBC data source, then fill the placeholders. The JDBC URL and the public properties stay editable, so a preset is a head start, not a cage.
| Preset | Driver | Auth |
|---|---|---|
| NetSuite SuiteAnalytics Connect | upload from the vendor | password, OAuth 2.0 |
| Snowflake | net.snowflake:snowflake-jdbc (Maven Central) |
password, key or service-account file, OAuth 2.0 |
| Databricks SQL | com.databricks:databricks-jdbc (Maven Central) |
token or key, OAuth 2.0 |
| Google BigQuery | upload from the vendor | key or service-account file |
| Google Cloud Spanner | com.google.cloud:google-cloud-spanner-jdbc (Maven Central) |
key or service-account file |
| Amazon Redshift | com.amazon.redshift:redshift-jdbc42 (Maven Central) |
password |
| Amazon Athena | com.amazonaws.athena:athena-jdbc (Maven Central) |
password |
| Microsoft SQL Server / Azure SQL / Synapse | com.microsoft.sqlserver:mssql-jdbc (Maven Central) |
password, OAuth 2.0 |
| Oracle Database / Autonomous Database | com.oracle.database.jdbc:ojdbc11 (Maven Central) |
password, OAuth 2.0 |
| IBM Db2 | com.ibm.db2:jcc (Maven Central) |
password |
| IBM Informix | com.ibm.informix:jdbc (Maven Central) |
password |
| SAP HANA | com.sap.cloud.db.jdbc:ngdbc (Maven Central) |
password, OAuth 2.0 |
| Teradata | com.teradata.jdbc:terajdbc (Maven Central) |
password |
| Trino / Starburst | io.trino:trino-jdbc (Maven Central) |
password, OAuth 2.0 |
| Presto | com.facebook.presto:presto-jdbc (Maven Central) |
password |
| ClickHouse | com.clickhouse:clickhouse-jdbc (Maven Central) |
password, OAuth 2.0 |
| SingleStore | com.singlestore:singlestore-jdbc-client (Maven Central) |
password |
| Vertica | com.vertica.jdbc:vertica-jdbc (Maven Central) |
password, OAuth 2.0 |
| Exasol | com.exasol:exasol-jdbc (Maven Central) |
password, OAuth 2.0 |
| Firebolt | io.firebolt:firebolt-jdbc (Maven Central) |
token or key |
| MotherDuck | org.duckdb:duckdb_jdbc (Maven Central) |
token or key |
| Dremio | upload from the vendor | password, token or key |
| Apache Hive / Spark Thrift | org.apache.hive:hive-jdbc (Maven Central) |
password |
| Apache Druid | org.apache.calcite.avatica:avatica-core (Maven Central) |
password |
| Apache Phoenix | org.apache.phoenix:phoenix-queryserver-client (Maven Central) |
password |
| CrateDB | io.crate:crate-jdbc (Maven Central) |
password |
| Elasticsearch SQL | upload from the vendor | password, token or key |
| OpenSearch SQL | org.opensearch.driver:opensearch-sql-jdbc (Maven Central) |
password, token or key |
| Sybase / SAP ASE | upload from the vendor | password |
| IBM Netezza | upload from the vendor | password |
| Denodo | upload from the vendor | password |
| PostgreSQL-compatible via JDBC | org.postgresql:postgresql (Maven Central) |
password, OAuth 2.0 |
| MySQL-compatible via JDBC | com.mysql:mysql-connector-j (Maven Central) |
password, OAuth 2.0 |
Other (generic JDBC) takes any driver, any jdbc: URL, and any property
bag. It is how a vendor not listed here is connected, and the list above is
nothing more than this form with the fields filled in.
Properties and secrets
A JDBC driver is configured by a flat bag of named strings. swarmvia splits that bag by who may see it:
- Public properties live on the source: account, warehouse, role, application name, TLS mode. They appear in the dashboard and in the source's settings.
- Secret properties live in the credential: password, token, client secret, passphrase. They are written once and never shown back.
- Files live in the credential too: a private key, a service-account JSON,
a wallet. Up to eight, 64 KB each. Reference one as
${file:name}in a property value or in the URL; it is written to a private directory for the connection and removed when the connection ends.${files}is that directory, for a driver that wants one (an Oracle wallet location,TNS_ADMIN).
The secret bag wins. A name set in both places takes the credential's value, so a value typed into the source form can never override a secret, and a JDBC URL is refused if it carries a property the credential marks secret. Secrets go in the credential; the URL is shown and logged.
A JDBC login is one credential, reusable across sources like any other. Rotating it walks every source on it back to needs connectivity until Test connection passes again.
OAuth2 access tokens
Drivers that take a short-lived access token (Snowflake, Databricks, Azure SQL
and Synapse, Oracle, Trino, Vertica, Exasol, HANA, ClickHouse) get one from
swarmvia. Give the credential an OAuth 2.0 client-credentials grant
and name where the driver wants the token: a property (token,
Auth_AccessToken, accessToken, OAuth2Token) or a file (Oracle reads
one from oracle.jdbc.tokenLocation).
swarmvia mints the token at the identity provider, caches it until shortly before it expires, and hands it to the driver on every connection. The driver never refreshes anything itself, which matters because every query is a fresh connection and a driver left to its own devices would hit your identity provider per query. Sources that share a credential share the token.
A rejected client is answered the way an HTTP source answers one: 503 with
the identity provider's error, a reconnect link, and no secret in the body.
Limits and sizing
Query limits are the database-source limits:
| Setting | Default | Ceiling |
|---|---|---|
| Statement timeout | 30s | 10m |
| Max rows | 10,000 | 50,000 |
| Max result bytes | 8 MiB | 16 MiB |
| Result TTL | 1h | 24h |
Two things are JDBC's own:
Runtime memory. A JDBC source runs in a Java runtime with 1 GB, which
fits a JVM, a driver, and sixteen concurrent queries at the 8 MiB result
ceiling. A driver that buffers wide results can still exhaust it; lower
maxRows first, and if queries against the source keep failing, contact
[email protected].
When no runtime is available. The runtimes come from a shared pool of
instances. When none can be started, a source either fails the query with
503 dialer_at_capacity and a Retry-After the caller should honour, or
queues it as a job to run when an instance frees up. Queueing needs Async
on. Choose under Concurrency; the default is to fail, because a hidden
queue is the one thing an operator cannot budget for.
Plan limits on JDBC sources, separate from the source count:
| Plan | JDBC sources |
|---|---|
| Free | 0 |
| Starter | 1 |
| Team | 3 |
| Business | 10 |
A scheduled job against a JDBC source keeps a runtime awake for as long as it runs; the per-plan cap is what keeps a dozen hourly crons from becoming a bill nobody meant to run.
Read-only, and what that means here
swarmvia asks the driver for a read-only connection and runs each statement in
a transaction it rolls back. What that is worth depends entirely on the driver:
some enforce it, some record it as a hint, some ignore it. Test connection
reports what the driver said (readOnly: true or false), and the honest
statement is this: the login's grants are the whole boundary. Connect as a
role that can read what it should and nothing else, the same discipline a
Postgres source asks for, and treat a read-only connection as a convenience,
not a control.
Test connection
Sources → Settings → Test connection opens a real connection through the driver and reports which stage failed:
| Reason | Meaning |
|---|---|
driver_not_found |
The driver jar could not be fetched. Check the driver under JDBC drivers. |
driver_load_failed |
The jar was fetched but failed to load, or its checksum did not match. Replace it. |
driver_class_missing |
The jar declares no java.sql.Driver. It is not a JDBC driver, or not the right jar from the vendor's bundle. |
not_jdbc |
No loaded driver accepts this URL's jdbc: subprotocol. The URL and the driver disagree. |
unreachable, tls_refused, tls_verify_failed |
The network and TLS stages, as for any database source. |
auth_failed, database_missing, insufficient_privilege |
The login, the database name, or the grants. |
On success it records the product the driver reported (NetSuite, Snowflake,
Microsoft SQL Server) and the driver's own identifier quoting, which the MCP
source_count_rows tool uses to quote names for an engine it has never seen.
Errors
Failures carry the driver's SQLSTATE where the driver provides one, in the
same db_error shape as every database source. Statement timeouts and
cancellations are 57014. A failure before any statement ran (a driver that
would not load, a connection that would not open) is a 502 or 503 naming
the stage, never a 400: it is the source's configuration, not the caller's
statement.
Cancelled queries are cancelled in the driver, not just dropped, so a runaway statement stops at the database when the caller gives up.
From an agent
The same tools as any database source: source_schema, source_query,
get_query_result, source_count_rows. source_schema reads the driver's
own catalog (DatabaseMetaData), so engines without information_schema
work. A JDBC source lists in list_sources as backend: jdbc · <product>.
What this is not
Not ODBC. ODBC drivers are native code for a specific operating system and architecture, and every vendor's build is different; there is no way to load one safely in a shared runtime. Every vendor that ships ODBC also ships JDBC, and the JDBC driver is the portable one. If a system only has an ODBC driver, it will not connect here.
Not a driver host for your application. The runtime opens one connection per query and sleeps when idle. It is for agents, analysts and scheduled analytical work, like every other database source.
Not Kerberos. Drivers that can only authenticate with a Kerberos ticket have no keytab here. Use the vendor's password, token or OAuth2 path.