Skip to main content
Connecting a database takes the engine and a reference to its connection string. Your agents get three tools at once: List tables, Describe table and Query, which runs one read-only statement an agent writes, on the tables you allow, capped and masked. The query runs where the connection string lives, which on the hosted service is your organization’s data-plane agent; Danube stores a reference to the connection string and never the string. Named query tools come later, promoted from the statements agents actually run, or written as templates on the advanced path.

Engines

You write every template the same way, with :name placeholders; the engine rewrites them per driver. Whatever the engine, the template is validated before it runs: one SELECT (or WITH ... SELECT), no comments, no second statement, no data-modifying keyword anywhere.

The connection reference

connection_ref names where the connection string is, in one of three forms: A value in that field (anything with a scheme, a host or a password) is refused at registration, by the dashboard and by the agent. What the variable holds, per engine:

A read-only role

The validator refuses writes, and Postgres, Redshift, MySQL and ClickHouse refuse them a second time on the connection. For the others the role is the second layer, so create one that can only read:
BigQuery: grant the service account roles/bigquery.dataViewer on the dataset and roles/bigquery.jobUser on the project.

Drivers in the agent image

The published image ships no database driver. Build your own from dataplane-agent/ with the engines you need, comma-separated:
install_drivers.sh installs the pinned lines from requirements-drivers.txt for those engines and nothing else; an engine that is not built in fails a query with driver_missing. postgres and redshift share one driver.

Connect

From Dashboard > Connect a system, choose Database, the organization, the engine and the reference. Preview runs discovery through the agent and lists the tables and columns it found; Connect creates the service. Over the API:
The service is local_only and gets three method: SQL tools, none with a template of its own: Discovery reads every non-system schema (or the one in database.schema; on BigQuery a dataset is required) through the agent and stores the tables and columns on the service as metadata.discovery.tables, capped at 500 tables and 200 columns per table. With no agent online the service is still created and discovered.error is no_dataplane_agent; start the agent, then Discover again on the service page (POST /v1/organizations/{org_id}/connect/{service_id}/discover).

Allowlist and masking

The policy starts with no table allowed: a Query on any table answers permission_denied until you list some. On the service page, pick tables from what discovery found, or over the API:
allowed_tables and denied_tables take schema.table or table, case-insensitive; a deny wins over an allow, and List tables shows only what is allowed. masked_columns (table.column or column) come back as [REDACTED:<column>] in every row and are marked in Describe table. max_rows caps every call at 1,000 or less. A statement that names a table outside the allowlist, or anything but a single SELECT, is refused with error_type: permission_denied, fault: caller, and the message names the table; the agent skill tells agents to read that as policy, not as an outage.

Promote a statement

Once an agent has run a statement worth keeping, turn it into a named tool from the Audit Log (Promote to tool on the tool.execute row) or over the API, with the execution id or the statement itself:
The named tool is a method: SQL row at /queries/<slug> carrying the engine, the reference and the template, exactly like a template written by hand, and it is not subject to the allowlist: it does what its template says.

Templates (advanced)

A connector that declares its own query templates is still registered through POST /v1/organizations/{org_id}/services with source: database, or from the Connector Builder. Each template becomes one tool and no generic tools are created:
Each query becomes a method: SQL tool at /queries/<slug> with the engine, the reference and the template in its metadata. A parameter used in the template and not declared is reported as a warning: an agent will not know to send it, and a call without it fails with bad_request: missing parameter.

Limits

  • One read statement per template. Comments, ;, dollar quotes and # are refused.
  • At most 1,000 rows per call (max_rows on the connector lowers it); truncated: true in the result says more matched.
  • A 30 second statement timeout by default (timeout_seconds, up to 55 inside the 60 second dispatch budget) and a 10 second connect timeout.
  • Cells are returned JSON-safe: dates as ISO 8601, decimals as numbers, bytes as base64. Credential-shaped values in rows are masked like any other tool result.
  • POST /v1/connectors/database/test, /introspect, /infer and /dry-run connect from the control plane and are for self-hosted deployments; for a local_only connector they answer 400 and the test is a tool run after registration.

Troubleshooting