Skip to content

Add support to configure connection options - #71

Merged
abonander merged 2 commits into
mainfrom
clickhouse-connection-options
Aug 31, 2026
Merged

Add support to configure connection options#71
abonander merged 2 commits into
mainfrom
clickhouse-connection-options

Conversation

@koletzilla

@koletzilla koletzilla commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Summary

Before this change, the driver only accepted a fixed list of options. There was no way to set
general ClickHouse settings like mutations_sync, alter_sync or insert_quorum, which
clients often need to pin for correctness.

This PR adds two ways to pass any ClickHouse setting:

1. A passthrough option key:

clickhouse.setting.<setting_name> = <value>

It can be set on ClickhouseDatabase, ClickhouseConnection and ClickhouseStatement. The
value propagates to objects created lower in the hierarchy, and lower levels can override it —
the same model as clickhouse.client.product_info. Values can be read back with
get_option_string().

2. Query parameters in the connection URI:

http://localhost:8123?mutations_sync=3

Every URI query parameter (except the existing protocol pseudo-parameter) is treated as a
setting, exactly as if it were set with the option key above. Previously these parameters were
silently dropped. This helps ADBC consumers that can only pass a URI string.

Internally both map directly to the clickhouse-rs client: Client::set_setting(name, value).
The client then sends the setting as a URL query parameter on every request, which is the native
way to carry "connection settings" over the ClickHouse HTTP interface (there is no server-side
connection state).

Usage example

let mut driver = ClickhouseDriver::init();

// Applies to every connection and statement created from this Database.
let db = driver.new_database_with_opts([
    (OptionDatabase::Uri, "http://localhost:8123/?insert_quorum=auto".into()),
    ("clickhouse.setting.mutations_sync".into(), "3".into()),
])?;

let mut conn = db.new_connection()?;

// Settings can also be set or changed on a live connection o
conn.set_option("clickhouse.setting.alter_sync".into(), "3".into())?;

// Read-back:
assert_eq!(conn.get_option_string("clickhouse.setting.mutations_sync".into())?, "3");

Decisions taken

  • Why a key prefix? ADBC only offers flat SetOption(key, value) string pairs; there is no
    "pass a map" call. Encoding the setting name in a namespaced key is the standard ADBC pattern
    for open-ended option families (e.g. Flight SQL's adbc.flight.sql.rpc.call_header.<name>).
  • String values only. Same as every existing option in this driver, and it matches how
    settings travel anyway (text query parameters). Int/double support can be added later without
    breaking anything.
  • Database level stores a map. ClickhouseDatabase holds no client, so its settings are
    stored and replayed when a connection is created, before the per-connection options are
    applied, which is what makes lower levels win.
  • URI parameters and options share that map, so precedence is simply "last write wins per
    setting", in whichever order they are set. A protocol parameter on an http(s):// URL is
    now rejected with InvalidArguments (it is only meaningful for clickhouse:// rewriting;
    before, it was silently carried and dropped).
  • Small behavior change: URI query parameters used to be preserved in the stored URL (where
    clickhouse-rs dropped them at request time, so they never worked). Now they are folded into
    the settings map instead; test_set_uri expectations were updated.
  • Read-back of an unset setting returns NotFound; an empty setting name
    ("clickhouse.setting.") is rejected with InvalidArguments.
  • Overlap with clickhouse.client.* options is allowed. clickhouse.setting.session_id
    writes the same client state as clickhouse.client.session_id; last write wins. Note that
    query_id is regenerated for every new statement, so setting it higher up has no effect.
    This is documented on SETTING_PREFIX.
  • ClickhouseConnection::get_option_string() is now implemented (it was blanket
    NotImplemented). This also fixes an existing gap: the SESSION_ID docs promised read-back
    that was never implemented.
  • Prefix keys are handled with a strip_prefix early return instead of a match guard, because
    if-let match guards are not stable on the pinned Rust 1.91.0 toolchain.

Note for #67 (default database)

?database=x in the URI now folds like any other parameter and works through the HTTP
interface's database query parameter. If a dedicated default-database feature (#67) lands
later, it should take ownership of the database parameter s

Possible future changes

  • Route the dedicated clickhouse.client.* options through the same internal path. They already share the same underlying client state; the per-key match arms could become a small alias table. Kept out of this PR to stay minimal.

@abonander

Copy link
Copy Markdown
Collaborator

Your test fix is merged so this just needs a rebase.

@koletzilla
koletzilla force-pushed the clickhouse-connection-options branch from f27a45b to 621893a Compare August 31, 2026 09:41
@koletzilla
koletzilla marked this pull request as ready for review August 31, 2026 10:19
@koletzilla
koletzilla requested a review from abonander as a code owner August 31, 2026 10:19
@koletzilla

Copy link
Copy Markdown
Contributor Author

Rebase done!

@abonander
abonander merged commit 553db18 into main Aug 31, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants