github ClickHouse/clickhouse-connect v1.1.0

6 hours ago

clickhouse-connect 1.1.0

This is the first minor release on the 1.x line. 1.1.0 consolidates everything from the 1.1.0a1 and 1.1.0a2 alphas i.e. the Alembic/SQLAlchemy integration work and adds a handful of bug fixes on top of 1.0.1.

If you're upgrading from a 0.15.x or earlier release, please read MIGRATION.md for the 1.0 breaking changes first.

Regarding Alembic support

This is the first clickhouse-connect release to ship Alembic integration. SQLAlchemy and Alembic each have a large surface area, and ClickHouse has plenty of dialect-specific quirks, so this release should best understood as a focused first cut. The common autogenerate/upgrade/downgrade flows for tables, columns, engines, dictionaries, comments, and operation-level settings rather than an exhaustive port of every Alembic feature. If you hit a gap, an inconvenience, or unexpected behavior, please open an issue with a repro. Enhancement requests are equally welcome and will help prioritize what to focus on.

Highlights

SQLAlchemy & Alembic

  • Alembic migration support. Full Alembic integration for ClickHouse schema migrations: autogeneration of migration scripts from SQLAlchemy metadata, upgrade/downgrade lifecycle, and round-tripping of ClickHouse-specific DDL. Supported operations include create/drop table, add/alter/drop/rename column, type and nullability changes, defaults, comments, IF EXISTS guards, column placement with AFTER, and operation-level clickhouse_settings. ClickHouse table engines (MergeTree, ReplacingMergeTree, etc.) and dictionaries are preserved through the migration lifecycle. Install via pip install clickhouse-connect[alembic]. See clickhouse_connect/cc_sqlalchemy/alembic/WORKED_EXAMPLE.md for an end-to-end walkthrough.
  • ClickHouse Dictionary type support. Reflect, create, and drop ClickHouse dictionaries through SQLAlchemy and Alembic.
  • New Select constructs: PREWHERE, LIMIT BY, and lambda expressions are now chainable on select() for ClickHouse-specific queries.
  • Multi-column ARRAY JOIN label preservation. ARRAY JOIN aliases now survive through compilation, fixing label-loss issues with parallel array expansion.
  • Migration shim for clickhouse-sqlalchemy users. New cc_sqlalchemy.types and cc_sqlalchemy.engines import-compatible modules ease migration from clickhouse-sqlalchemy. See clickhouse_connect/cc_sqlalchemy/MIGRATING_FROM_CLICKHOUSE_SQLALCHEMY.md.
  • SQLAlchemy 1.4 and 2.x compatibility improvements across the dialect and DDL compiler paths.
  • Inspector cloud quirk reflection fixes for ClickHouse Cloud-specific schema reflection edge cases.
  • DDL compiler improvements including better handling of nested container types and Tuple adaptation.

Compatibility

  • Async client now requires aiohttp>=3.9.0. This is required to support TLS SNI override via server_host_name, because aiohttp added the per-request server_hostname option in 3.9.
  • The alembic extra now requires alembic>=1.16 (previously >=1.9), to expose the IF EXISTS / IF NOT EXISTS operation kwargs used by the integration.

Bug fixes

  • Async client: server_host_name now also overrides the TLS SNI / certificate hostname, matching the sync client. Previously the async path only applied it to the HTTP Host header, so connecting to host A while presenting SNI B (the 0.x pool_mgr=urllib3.PoolManager(server_hostname=...) pattern, useful for ClickHouse Cloud VPC endpoints reached via external DNS) was not expressible against the new aiohttp-based client. Closes #752.
  • Drain the full retries budget on connection-error retries in _raw_request instead of only retrying once. Previously both the sync and async clients gated network-error retries on attempts == 1, so two consecutive aiohttp.ServerDisconnectedErrors (or ConnectionResetErrors on the sync path) surfaced as OperationalError even when query_retries would have allowed another attempt. Read paths will now drain query_retries. Insert/command paths still get one retry. Sync raw_query and raw_stream, the foundation for query_arrow & query_arrow_stream now also pass query_retries so they match their async counterparts. Adds a 0.1 * attempts backoff between connection-error retries to match the 429/503/504 branch. Closes #754.
  • quote_identifier now re-escapes inputs that start and end with ` or " but contain unescaped inner occurrences of the same quote character, instead of passing them through unchanged. Validly pre-quoted identifiers like backslash or doubled-quote escaping still pass through untouched. Closes #737.
  • SQLAlchemy: op.add_column(..., clickhouse_settings={...}) now works through the public Alembic operations API. Previously the stock Operations.add_column proxy had a fixed signature that rejected clickhouse_settings with TypeError, even though the underlying impl accepted it. Rendered AddColumnOp migrations also preserve extra ClickHouse kwargs on round-trip, so autogenerated scripts containing clickhouse_settings=... survive regeneration.
  • SQLAlchemy: Alembic migrations now handle comments with ClickHouse-compatible syntax. Column comments on CREATE TABLE / ADD COLUMN are rendered inline instead of emitting separate COMMENT ON COLUMN statements (which ClickHouse rejects). Table comments are now emitted in generated DDL, reflected for no-op autogenerate, and changed or dropped via ALTER TABLE ... MODIFY COMMENT. Inspector.get_table_comment(...) now raises NoSuchTableError for missing tables instead of silently returning {"text": None}.
  • SQLAlchemy: quote string-valued engine and operation settings as ClickHouse string literals when rendering SETTINGS clauses. Previously settings like MergeTree(settings={"storage_policy": "hot_cold"}) or op.add_column(..., clickhouse_settings={"mutations_sync": "2"}) emitted unquoted SQL (storage_policy = hot_cold), which ClickHouse rejected. Numeric and boolean settings are unchanged.
  • SQLAlchemy: preserve engine settings on reflection. build_engine() previously hardcoded engine.settings = {} even when the reflected DDL contained a SETTINGS clause, so callers reading engine.settings after reflection saw an empty dict. settings is now populated from the parsed engine kwargs, decoding ClickHouse string-literal escapes (\\, \', \n, etc.) and preserving float-valued settings as floats providing round-trip parity with the construction path.
  • SQLAlchemy: Inspector error messages from get_table_metadata() now report the resolved database name i.e. from currentDatabase() when schema was not provided instead of literal None.
  • SQLAlchemy: preserve FINAL, SAMPLE, PREWHERE, and LIMIT BY modifiers when a select() is built from ORM-mapped attributes e.g. select(Event.id) rather than Core columns. Previously the ORM compile path rebuilt the inner Select via Select._create_raw_select, which dropped the modifier instance attributes, so the compiled SQL silently emitted no modifier. The compiler now falls back to compile_state.select_statement which is the original user-built Select to recover the modifiers. Closes #730.
  • Alembic autogenerated migrations now render enum types (including nested container types) with the correct ClickHouse-compatible representation.

Pre-release tags rolled into 1.1.0

  • v1.1.0a1 (2026-05-06) - initial alembic / SQLAlchemy alpha
  • v1.1.0a2 (2026-05-07) - ORM modifier compile-path fix

Install

pip install clickhouse-connect

For Alembic integration:

pip install clickhouse-connect[alembic]

Don't miss a new clickhouse-connect release

NewReleases is sending notifications on new releases.