ClickHouse / ClickHouse/dbt-clickhouse
dbt Core 2.0 parity: General adapter behaviour
- Dominant language
- Python
- Stars
- 362
- Forks
- 177
- Avg merge
- 2d 10h
- Merged PRs (30d)
- 8
Description
Sub-issue of #660 — feature-parity tracking for the ClickHouse adapter in dbt Core 2.0 / Fusion versus the Python `dbt-clickhouse` adapter.
Covers adapter-wide behaviour: capability probes (EXCHANGE, lightweight deletes), server version checks, column schema introspection, macro sync with upstream, S3 source support, connection-level behaviour and usage tracking. Metadata-based source freshness is a dbt Core 2.0-only capability and is tracked in #736.
**Status legend:** ✅ implemented — merged and working on dbt-core 2.0 `origin/main` · 🟡 partial — partly working on `origin/main` (Notes say what works vs fails) · 🚧 in progress — implemented in an open PR (linked in Notes) · 🔴 not started — not working anywhere · ⚪️ future work — explicitly deferred, not being solved now (also listed in the future-work sub-issue) · Combined status "A-🚧->B": the feature is at A on origin/main today; an open PR is driving it to B (🟡 partially working / ✅ fully working)
| Feature | Subfeatures / details | Status | Notes (PR) |
| --------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **General adapter behaviour** | *(overall)* | 🟡 | Merged: version probe, DESCRIBE introspection, TLS, non-experimental registration, S3 (dbt-labs/dbt-core#16082), lw-delete probe (dbt-labs/dbt-core#16090), EXCHANGE probe (dbt-labs/dbt-core#16200), 0.1.1 driver (dbt-labs/dbt-core#16185), `dbt/` User-Agent (dbt-labs/dbt-core#16156). Missing: usage tracking (dbt first in the User-Agent), query comment, `query_id`, view replace fallback without `renameat2` |
| Server version checks | `SELECT version()` probe + `adapter.is_before_version` / `is_at_or_after_version` | ✅ | dbt-labs/dbt-core#16079: once-per-process probe, `compare_versions` mirrors util.py; used by the 26.6 `insert_overwrite` gate |
| `adapter.format_columns` / `get_column_schema_from_query` | `DESCRIBE TABLE (sql)` with the model's `query_settings`; ADBC/Arrow reports all columns Nullable, so the server-typed schema replaces the driver schema | ✅ | dbt-labs/dbt-core#16079 (fixes dbt-labs/dbt-core#14581) |
| TLS / secure connections | `secure` profile flag, HTTPS/TLS driver support | ✅ | Driver 0.1.0-a2 for TLS (dbt-labs/dbt-core#10391); `secure` registered with port/scheme autodetection |
| Adapter registration / onboarding | ClickHouse listed as a non-experimental adapter; `dbt init` flow | ✅ | Non-experimental (closes dbt-labs/dbt-core#15410); `dbt init` improvements (dbt-labs/dbt-core#10558) |
| Lightweight-delete capability probe | `use_lw_deletes` profile flag + settings/permission checks | ✅ | Probe in dbt-labs/dbt-core#16090; `allow_nondeterministic_mutations` sent for the disabled-but-changeable case in dbt-labs/dbt-core#16156 (adbc_clickhouse#70) |
| ADBC driver: literal `?` in SQL | A literal `?` must reach the server verbatim (the 0.1.0 driver treated it as a bind param, forcing `\x3F`/`??` escapes into seed.sql, adapters.sql and materialized_view.sql) | ✅ | adbc_clickhouse 0.1.1 (adbc_clickhouse#53) via dbt-labs/dbt-core#16185 sends a literal `?` verbatim; dbt-labs/dbt-core#16156 retired seed.sql's `??` escape. The `\x3F` regex escapes in adapters.sql/materialized_view.sql are harmless server-side escapes and stay until retired together with the v1 macro tree |
| S3 table function | `adapter.s3source_clause` (`clickhouse_s3source(...)` via project vars), incl. `external_id`/`role_arn` extra credentials | ✅ | dbt-labs/dbt-core#16082 with impl.py parity |
| UUID support in ADBC / Arrow | Driver-side: ADBC driver 0.1.0 (adbc_clickhouse#63); server-side: Arrow output of `UUID` columns requires ClickHouse 26.7+ | ✅ | Driver fix released (adbc_clickhouse#63). The server-side 26.7+ requirement is a Known limitation in #660; no adapter work |
| EXCHANGE capability check | Probe once per process: db-engine check + real `CREATE`/`EXCHANGE`/`DROP` scratch test; `check_exchange: false` skips; `relation.can_exchange` stamped on cached relations and used by the table / incremental / snapshot / materialized-view swaps | ✅ | dbt-labs/dbt-core#16200. Rebuilds and full refreshes of tables, incremental swaps, snapshot upserts and MV target rebuilds run `EXCHANGE TABLES` on Atomic/Replicated/Shared databases and fall back to rename elsewhere |
| Macro sync to upstream | Byte-identical macros; only documented Fusion divergences allowed | 🟡 | Most of the tree is byte-identical (dbt-labs/dbt-core#16023, #16079, #16082, #16200, #16153). Still differing on main: adapters.sql, persist_docs.sql (extra `validate_doc_columns` call), view.sql (no `supports_atomic_exchange` fallback), seed/distributed_table/incremental/distributed_incremental/schema_changes. Missing entirely: `macros/adapters/` (apply_grants.sql, relation.sql), `materializations/clone.sql`, `utils/datatypes.sql`. Deliberate divergences: adapters.sql `clickhouse__check_schema_exists`, seed.sql's literal-VALUES insert (the `format CSV` path is deferred, #731) |
| Connection profile keys parity | `cluster`, `cluster_mode`, `use_lw_deletes`, `check_exchange`, `local_suffix`, `local_db_prefix`, `allow_automatic_deduplication`, `custom_settings`, `database_engine`, `sync_request_timeout`, `compress_block_size`, `secure`, … | 🟡 | Consumed on main: `secure`, `custom_settings` (driver options, dbt-labs/dbt-core#16156), `check_exchange` (EXCHANGE probe, dbt-labs/dbt-core#16200), `use_lw_deletes` (lw-deletes probe, dbt-labs/dbt-core#16090), `allow_automatic_deduplication` (dedup default, dbt-labs/dbt-core#16079), `database_engine`/`cluster_mode` (connection settings + DDL), `local_suffix`/`local_db_prefix` (distributed macros). Missing: `cluster` is not consumed yet; the HTTP-client keys `verify`, `client_cert`/`client_cert_key`, `connect_timeout`, `send_receive_timeout`, `sync_request_timeout`, `compress_block_size` parse but are inert — the ADBC driver exposes no TLS-verification, client-certificate, timeout or compression options, so these need driver work first |
| Usage tracking | dbt identifies itself first in the HTTP `User-Agent` (`system.query_log.http_user_agent`), as `dbt/ …` | 🟡 | v1 sends `dbt-adapters/x dbt-clickhouse/y clickhouse-connect/z (lv:py/…; os:…; os_user:…)`. Merged (dbt-labs/dbt-core#16156): `dbt/` via the driver's `clickhouse.client.product_info` option — DDL/INSERT statements log `dbt/2.0.0-rc.1 adbc_clickhouse/0.1.1 clickhouse-rs/0.15.2 (…)`, but Arrow reads (SELECT/DESCRIBE) log `clickhouse-ext-arrow/0.1.0 dbt/2.0.0-rc.1 …` because clickhouse-ext-arrow tags the query last and clickhouse-rs prints the last-added product first. Missing: `dbt/…` always first — reported as ClickHouse/clickhouse-rs#469; the fix has to land there, then ship in a clickhouse-rs release, then in an adbc_clickhouse release, and only then can dbt Core 2.0 bump its driver pin (no dbt-side code change expected). Extra key/value pairs in the parenthesised comment are not possible either (clickhouse-rs hardcodes that section) |
| View replace fallback without `renameat2` | `adapter.supports_atomic_exchange()`; view.sql falls back to drop + create when the filesystem lacks `renameat2` (NFS), upstream #684 | 🔴 | Only the method name is registered on main (no implementation) and view.sql has no fallback, so `CREATE OR REPLACE VIEW` fails with `UNSUPPORTED_METHOD` on such filesystems (`test_view_no_renameat2`) |
| Query comment handling | `query-comment: null` honored; rendered macro comments re-validated | 🔴 | 2 integration tests fail (NullQueryComments, MacroInvalidQueryComments). Engine-generic fix |
| `adapter_response.query_id` | Engine-assigned `clickhouse.client.query_id` surfaced into run results/logs | 🔴 | 1 integration test fails |
| `dbt debug` target handling | Bad target should surface a connection-failure report, not a profile-resolution error | ⚪️ | Deferred (#731). An unknown `--target` errors out before the `dbt debug` report is printed |
| `dbt run --sample` (sample mode) | Models' inputs filtered by the `--sample` window | ⚪️ | Deferred (#731). A sampled model returns 0 rows on ClickHouse |
| Duplicate hook definitions | A node defining both `post-hook` and `post_hook` (or the `pre-` pair) must fail compilation | ⚪️ | Deferred (#731). v2 keeps one of the two hooks silently instead of failing |
| Port dbt-clickhouse 1.10.1 features | Bring the features added in v1 1.10.1 to 2.X | ⚪️ | Deferred (#731); not itemized yet |
| Port dbt-clickhouse 1.10.2 features | Bring the features added in v1 1.10.2 to 2.X | ⚪️ | Deferred (#731); not itemized yet |
Contributor guide
Research direction
Start by reading the remaining-status rows and comparing the listed macro paths—macros/adapters/, materializations/clone.sql, utils/datatypes.sql, and the differing adapter, view, seed, incremental, and schema-change macros—with upstream dbt Core. Review the notes for usage tracking, query comments, query_id, and view replacement fallback. Done means the remaining parity items are implemented or explicitly tracked as deferred.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- clickhouse, python
- Domain
- databases
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100