Skip to content

Releases: ClickHouse/clickhouse-connect

v1.8.0rc2

v1.8.0rc2 Pre-release
Pre-release

Choose a tag to compare

@joe-clickhouse joe-clickhouse released this 20 Aug 17:38
dd867f5

clickhouse-connect v1.8.0rc2

This is the second release candidate for testing the optional Rust codec. RC2 updates the driver onto the 1.7.2 stable release, incorporating all of its bug fixes. The Rust codec itself is unchanged from RC1.

Please test this release with your workloads and report any issues. Install it with a pinned version:

pip install "clickhouse-connect[rust]==1.8.0rc2"

What's Changed Since v1.8.0rc1

Query and transport fixes

  • Queries ending in a semicolon now keep client-appended FORMAT clauses inside the statement, including trailing whitespace and comments. Insert detection now follows SQL token rules. Fixes
    #903.
  • The async client now preserves explicit proxy_path values exactly. Fixes #963.
  • The synchronous client now normalizes an empty request path to / when using a forwarding HTTP proxy. Fixes #951.
  • Server-side query parameter names can now contain $ where ClickHouse permits it, while preserving the driver's raw binary binding convention. Fixes [#936](https://github.com/ClickHouse/
  • ClickHouse type literals containing percent signs now compile safely alongside bound parameters. Fixes #966.
  • Generic literal_binds, DDL string clauses, comments, and Alembic comment operations now use ClickHouse-compatible backslash escaping. Fixes [#975](https://github.com/ClickHouse/clickhouse-
    connect/issues/975).
  • union(), intersect(), and except_() now emit explicit DISTINCT operations, preserving SQLAlchemy semantics. Use their _all() counterparts when duplicate-preserving behavior is
    intended. Fixes #973.
  • Applicable Select.with_hint() table hints now emit SAWarning instead of being silently ignored. Fixes #974.

Rust codec testing

The optional Rust codec remains experimental. The default python codec is unchanged.

To enable Rust with Python fallback:

client = clickhouse_connect.get_client(
    host="...",
    native_codec="rust",
)

For testing, native_codec="rust_strict" raises on unsupported paths instead of falling back.

Installation

For this release candidate:

pip install "clickhouse-connect[rust]==1.8.0rc2"

For the latest stable release:

pip install clickhouse-connect

v1.7.2

Choose a tag to compare

@joe-clickhouse joe-clickhouse released this 20 Aug 14:12
9283654

clickhouse-connect v1.7.2

This patch release fixes SQLAlchemy reflection and SQL generation, query formatting, server-side parameter names, and HTTP proxy path handling.

What's Changed

Bug Fixes

  • SQLAlchemy inspectors bound to an Engine now support get_columns() and reflect_table() on SQLAlchemy 2.x. Reflection also honors include_columns and exclude_columns. Closes #967.
  • Queries ending with a semicolon, whitespace, or trailing comment now place client-appended FORMAT clauses correctly. Insert detection also follows SQL token rules. Closes #903.
  • The async client now preserves explicit proxy_path values without adding extra slashes. Closes #963.
  • The synchronous client now sends a normalized / request path through forwarding HTTP proxies when no proxy_path is configured. Closes #951.
  • Server-side query placeholders now recognize $ in valid parameter names while preserving raw binary binding and ambiguity checks. Closes #936.
  • SQLAlchemy ClickHouse types now implement the public literal processor contract for TypeDecorator and with_variant(). Closes #965.
  • SQLAlchemy literals containing percent signs now compile safely alongside bound parameters and in server-side parameter mode. Closes #966.
  • SQLAlchemy now applies ClickHouse backslash escaping to generic literal strings, defaults, aliases, TTL clauses, comments, and Alembic comment operations. Custom pre-escaping workarounds should be removed. Closes #975.
  • SQLAlchemy union(), intersect(), and except_() now emit explicit DISTINCT operations. Use the corresponding _all() methods when duplicate-preserving behavior is required. Closes #973.
  • SQLAlchemy Select.with_hint() now emits SAWarning when an applicable table hint would otherwise be ignored. Generated SQL remains unchanged. Closes #974.

Full Changelog: v1.7.1...v1.7.2

Installation

pip install clickhouse-connect

v1.8.0rc1

v1.8.0rc1 Pre-release
Pre-release

Choose a tag to compare

@joe-clickhouse joe-clickhouse released this 12 Aug 21:11

clickhouse-connect v1.8.0rc1

This is a release candidate for testing the new optional Rust codec. Please try it and report any issues. Install it with a pinned version:

pip install "clickhouse-connect[rust]==1.8.0rc1"

Highlights

Experimental Rust native codec

This release adds an experimental native_codec client option that selects the codec used for FORMAT Native query decode and insert encode.

  • python is the default and uses the existing codec, so nothing changes unless you opt in.
  • rust prefers the compiled Rust codec and falls back to the Python codec for unsupported options and types (which should be (hopefully) rare).
  • rust_strict raises instead of falling back and is the recommended mode for testing.

The compiled codec is published as the separate clickhouse-connect-core wheel, installed automatically by the [rust] extra. Wheels cover CPython 3.10 through 3.14 on Linux x86_64 and aarch64 for glibc 2.28 and newer plus musl, macOS, and Windows x64 and arm64. Results and dtypes match the Python codec, and the Arrow methods are unaffected.

To enable it on a client:

client = clickhouse_connect.get_client(host=..., native_codec="rust")

This is early access for benchmarking and testing. See the rust-codec documentation page for details.

Also included

Everything in the 1.7.0 and 1.7.1 stable releases.

Installation

For this release candidate: pip install "clickhouse-connect[rust]==1.8.0rc1"

For the latest stable release: pip install clickhouse-connect

v1.7.1

Choose a tag to compare

@joe-clickhouse joe-clickhouse released this 12 Aug 18:00
d479216

clickhouse-connect v1.7.1

This is a patch release with two SQLAlchemy compatibility fixes.

What's Changed

Bug Fixes

  • SQLAlchemy 2.1 compatibility: Identifier quoting forwarded the deprecated force argument to IdentifierPreparer.quote, which SQLAlchemy 2.1 removed, causing any dialect use to raise TypeError on 2.1.0b3. The parent call now passes only the identifier. The optional force parameter remains available on the ClickHouse preparer for direct callers. Closes #954.
  • SQLAlchemy 1.4 compatibility: Column DDL using the clickhouse_materialized, clickhouse_alias, or clickhouse_ttl options raised AttributeError on SQLAlchemy 1.4 because it called a rendering helper that only exists in 2.0. The helper is now implemented locally. This appears to have been broken since 1.1.0.

Full Changelog: v1.7.0...v1.7.1

Installation

pip install clickhouse-connect

v1.7.0

Choose a tag to compare

@joe-clickhouse joe-clickhouse released this 11 Aug 17:36
f25bb0d

clickhouse-connect 1.7.0

clickhouse-connect 1.7.0 adds SQLAlchemy support for JSON subcolumns and materialized CTEs, introduces more control over error messages and naive datetime inserts, and fixes issues across parameter binding, streaming, JSON decoding, DB-API, and SQLAlchemy.

Highlights

Features and improvements

  • SQLAlchemy JSON columns now support storage-backed subcolumn access through column["segment"], column.subcolumn(...), and the typed json_subcolumn(...) helper. #899
  • SQLAlchemy statements can create materialized CTEs through .cte(..., materialized=True) and cc_sqlalchemy.cte(...). This requires ClickHouse 26.3 or later with enable_materialized_cte and the analyzer enabled. #900
  • show_clickhouse_errors="scrub" preserves useful server error details while removing the server URL and version trailer. Transport and streaming errors follow the same setting. Invalid values now raise ProgrammingError. #344
  • The new naive_datetime_insert setting controls whether naive Python datetime values use the client host timezone or the column and server timezone. The default remains "local" for compatibility. #938

Bug fixes

  • SQLAlchemy and DB-API now handle percent signs in identifiers correctly, including %2E JSON key encodings.
  • datetime.time and datetime.timedelta query parameters now bind correctly for Time and Time64, including nested, negative, extended-duration, timezone-aware, and nanosecond values. SQLAlchemy inserts, comparisons, and literal_binds now support these values too. #919
  • The DB-API module now provides the standard Binary, Date, Time, Timestamp, and ticks-based constructors. This also fixes SQLAlchemy LargeBinary inserts. #919
  • Fractional DateTime64 values before the Unix epoch now serialize to the correct second. #938
  • Nested compound types containing enum values with escaped quotes now parse correctly. #878
  • Nested None values in arrays, tuples, and map-formatted maps now render as SQL NULL. #879
  • Empty bytes inserted into non-nullable FixedString columns are now padded correctly. #880
  • Settings unavailable through system.settings, including custom role settings, are now forwarded to ClickHouse for validation. #530
  • SQLAlchemy reflection and metadata queries continue returning string identifiers when the global String format is configured as bytes. #920
  • Removing SQL block comments no longer joins adjacent query tokens or causes incorrect client-side LIMIT handling. #928
  • Native streaming now detects complete mid-stream ClickHouse exception blocks across transport chunk boundaries. #915
  • DB-API Cursor.description now reports accurate top-level nullability and handles empty-result metadata probes more safely. #902, #907, #909
  • Compound and temporal values stored in JSON shared data now decode to Python values instead of raw bytes. #897
  • Async streaming cleanup now runs on the event-loop thread, preserving the original StreamFailureError when TLS queries fail mid-stream.

Compatibility notes

  • Runtime compatibility branches for unsupported ClickHouse versions older than 25.8 have been removed. ClickHouse 25.8 is now the supported baseline.
  • datetime.time and datetime.timedelta parameters are now quoted by the driver. Remove manual quotes around existing %(name)s placeholders. #919
  • Naive datetime query parameters now represent wall time in the target timezone. Set common.set_setting("naive_datetime_binding", "legacy") to restore the previous host-timezone conversion behavior. #938

Installation

pip install clickhouse-connect

v1.6.0

Choose a tag to compare

@joe-clickhouse joe-clickhouse released this 23 Jul 17:45
2417137

What's Changed

clickhouse-connect 1.6.0 adds an experimental in-process chDB backend, resolves several sync/async client parity bugs, and replaces the zstandard dependency with the standard library/a backport. Internally, the sync and async HTTP clients were unified onto a shared backend core, which is what enables the chDB backend and fixes the async issues below.

Features

  • Added an experimental in-process chDB backend. get_client(interface='chdb') or a chdb:// DSN returns a standard client that runs queries against an embedded chDB engine instead of a ClickHouse server, supporting the full query, insert, streaming, and Arrow client surface. Use the path argument or a chdb:///on/disk/path DSN for a persistent database. Requires the chdb package, installable with pip install clickhouse-connect[chdb]. chDB allows one engine per process, has no async client, and does not support external data. (#872)

Bug Fixes

  • AsyncClient initialization no longer overwrites user-supplied session settings with generated defaults which no matches the sync client. (#872)
  • An AsyncClient created with both client certificates and an access token now sends the mutual TLS authentication headers and the Authorization: Bearer header together which now also matches the sync client. (#872)
  • Dict-valued settings such as additional_table_filters no longer crash with DB::Exception: Cannot parse quoted string when passed through query()'s settings parameter. Closes #501.

Improvements

  • Async clients now emit URL query parameters in the same order as the sync client on every request. (#872)
  • Client creation no longer fails when the client_protocol_version capability probe errors on the sync client; it now falls back gracefully and logs at debug level, matching the async client.
  • Replaced the zstandard dependency with the stdlib compression.zstd module (Python 3.14+) and backports.zstd (Python 3.10-3.13), giving a single consistent call surface across all supported Python versions. zstd compression remains fully supported on all standard Python installs. Closes #577.

Under the hood

  • The sync and async HTTP clients were refactored onto a shared, internal pluggable-backend core (asyncclient.py shrank by roughly 1,200 lines of duplicated logic). This is an internal change with no public API surface, but it's the basis for the chDB backend and the sync/async parity fixes above. (#872)

Installation

pip install clickhouse-connect

v1.5.0

Choose a tag to compare

@joe-clickhouse joe-clickhouse released this 15 Jul 17:00
b878607

clickhouse-connect 1.5.0

This is a feature release focused on the SQLAlchemy and Alembic integration, alongside two important correctness fixes on the core driver. Alembic gains first-class support for ClickHouse-specific DDL, SQLAlchemy gains per-query settings and typed ClickHouse query chainables, and Variant columns gain a new lossless read format. On the driver side, this release fixes a data-corruption bug when decoding large varints on the compiled path and a QBit corruption bug for dimensions greater than 8.

Highlights

Features

  • Alembic support for ClickHouse-specific DDL. New runtime Alembic operations cover skip indexes, projections, table settings, materialized views, and dictionaries, including plural add/drop helpers for indexes and projections. The plural helpers emit a single comma-joined ALTER TABLE so replicated deployments avoid the Code: 517 CANNOT_ASSIGN_ALTER race. Helpers render valid SQL in offline --sql mode. #839
  • Per-query ClickHouse settings in SQLAlchemy. execution_options(settings={...}) now forwards per-query settings through the dialect and DB-API cursor for Core and text() statements, execute, executemany, and the bulk-insert path. Settings set at the connection or engine level compose with per-statement settings, and per-statement values take precedence, so a connection-level default applies to implicit ORM queries such as selectinload and lazy loads. #838, #846
  • Chainable JOIN modifiers. A new Select.ch_join() lets ClickHouse JOIN modifiers be written in normal SQLAlchemy chaining style. It takes the strictness modifiers ALL, ANY, ASOF, SEMI, and ANTI, the GLOBAL distribution modifier, plus USING and CROSS as keyword arguments. The existing ch_join() factory is unchanged. #827
  • Typed ClickHouse select. cc_sqlalchemy.select() returns a ClickHouseSelect exposing ch_join, final, sample, array_join, prewhere, and limit_by as typed methods, so static type checkers accept them without suppressions. The standard sqlalchemy.select() path is unchanged. #837
  • typed read format for Variant columns. When two members of a Variant share a Python type, such as Variant(Float32, Float64), reading with the typed format wraps each value as a TypedVariant carrying both the value and its type_name, and these feed straight back into inserts. Enable per query with query_formats={'Variant': 'typed'} or globally with set_read_format('Variant', 'typed'). The default native format is unchanged. #825

Bug Fixes

  • Fixed corruption of QBit columns with a dimension greater than 8 on native inserts and reads. Data written by earlier clients was stored incorrectly and should be re-inserted. See the upgrade note below. #866
  • The compiled Cython response buffer now decodes LEB128 varint values of 2^31 and larger correctly. Each 7-bit group was shifted in signed 32-bit arithmetic before being widened, so any varint of 2^31 or more was truncated or corrupted. This affected string and nullable string column lengths and every other varint read on the compiled path. The pure Python reader was already correct. #828
  • command() now returns an empty string for a read that produces an empty result set, instead of a truthy QuerySummary that made if result: misleading. #865
  • DB API Cursor.executemany no longer falls off the bulk-insert fast path when an INSERT names backtick-quoted dotted columns such as the wire form of Nested sub-columns. unescape_identifier now removes backtick quoting from compound identifiers correctly, which previously degraded the operation to slow per-row execution and could raise ProgrammingError with dict rows and pyformat placeholders. #820

SQLAlchemy Bug Fixes

  • MergeTree engine key clauses order_by, partition_by, primary_key, sample_by, and ttl now accept arbitrary SQL expressions such as col.desc(), func.cityHash64(a, b), tuple_(...), and interval TTL expressions, in scalar and list forms. Expression engines round-trip through repr() for Alembic autogeneration. #845
  • has_database() now uses EXISTS DATABASE instead of querying system.databases. On servers from 25.10 through 26.4, system.databases omitted DataLakeCatalog and other remote databases by default, so has_database() reported False for databases that actually exist. #849
  • MATERIALIZED and ALIAS columns now keep their comment, codec, and ttl options in generated DDL, and column clauses are emitted in the order ClickHouse requires, COMMENT then CODEC then TTL. This also fixes a pre-existing case where a column combining a codec with a comment produced invalid SQL. #856
  • ClickHouseSelect now keeps its typed ClickHouse chainables after column-shape methods such as add_columns(), with_only_columns(), column(), and reduce_columns(). cc_sqlalchemy.select() also works on SQLAlchemy 1.4. #844
  • Wrapping a ClickHouse type in a SQLAlchemy TypeDecorator no longer raises TypeError: result_processor() takes 0 positional arguments but 2 were given when reading results. #847
  • The Alembic op.rename_table now emits RENAME TABLE old TO new instead of the ALTER TABLE old RENAME TO new form ClickHouse rejects. Standard SQLAlchemy indexes are filtered from ClickHouse autogenerate output, and Column(index=True), Index(...), op.create_index, and op.drop_index raise a clear Alembic error before partially applying DDL. Use op.add_clickhouse_index and op.drop_clickhouse_index for data-skipping indexes. #839
  • Fixed several Alembic ClickHouse DDL helper edge cases: raw SQL fragments containing :name are no longer parsed as bind parameters, dictionary comments escape backslashes correctly, explicit schemas are honored for legal dotted table names, CREATE MATERIALIZED VIEW no longer accepts a misleading clickhouse_settings suffix, and custom ClickHouse operation objects render through autogenerate instead of raising ValueError. #839

Upgrade notes

  • QBit dimension greater than 8. Values written by earlier clients were stored incorrectly on the wire. After upgrading, re-insert any affected QBit data. #866
  • command() return value. A read that returns no rows now yields an empty string rather than a truthy QuerySummary. Code that relied on command() for a read always being truthy should check the returned value explicitly. #865

Installation

pip install clickhouse-connect

Full Changelog: v1.4.2...v1.5.0

v1.4.2

Choose a tag to compare

@joe-clickhouse joe-clickhouse released this 06 Jul 20:15

clickhouse-connect 1.4.2

Patch release with a single bug fix on top of 1.4.1. No new features and no breaking changes.

Bug Fixes

  • Async inserts and queries with an in-memory body larger than 1 MiB no longer emit an aiohttp ResourceWarning about sending a large body directly with raw bytes. Bytes and string request bodies are now wrapped in an io.BytesIO so aiohttp writes them in chunks. This affects the async Arrow insert methods and any large raw insert or query body. Closes #850.

Full Changelog: v1.4.1...v1.4.2

v1.4.1

Choose a tag to compare

@joe-clickhouse joe-clickhouse released this 30 Jun 19:06
c2db020

clickhouse-connect 1.4.1

This is a patch release with two bug fixes. One restores correct Alembic autogenerate output for non-ClickHouse dialects after the ClickHouse integration is imported. The other completes the return-type annotations on the async client so callers running mypy in strict mode no longer get errors.

What's Changed

Bug Fixes

  • SQLAlchemy: importing the ClickHouse Alembic integration no longer changes Alembic autogenerate output for other database dialects. The ClickHouse renderers for CreateTableOp, AddColumnOp, and DropTableOp were registered as process-wide replacements with no dialect guard, because Alembic renderers have no per-dialect dispatch. Any non-ClickHouse autogenerate run in the same process then used the ClickHouse renderers, which dropped the nullable argument from columns whose nullability was not set explicitly and injected cc_sqlalchemy imports. The renderers now fall back to Alembic's built-in rendering for non-ClickHouse dialects. Closes #832.
  • Several public AsyncClient methods now carry the return-type annotations their sync Client counterparts already had. close, close_connections, query_np, query_df, query_arrow, set_client_setting, and set_access_token were missing them, so downstream projects running mypy with --disallow-untyped-calls got no-untyped-call errors on calls like await client.close() once the package began shipping py.typed in 1.4.0. The async client surface is now fully annotated. This is a type-only change with no runtime effect. Closes #831.

Installation

pip install clickhouse-connect

v1.4.0

Choose a tag to compare

@joe-clickhouse joe-clickhouse released this 29 Jun 18:39
584ae6a

clickhouse-connect 1.4.0

This is a minor release. It adds experimental free-threading support, ships type information for downstream type checkers, and fixes bugs across the core client, the DB-API cursor, and the SQLAlchemy dialect.

Highlights

Features and improvements

  • Free-threading compatibility. The Cython extension modules now declare free-threading support, so importing clickhouse-connect on a free-threaded build such as Python 3.14t no longer silently re-enables the GIL. Free-threading support remains experimental. The CI suite now runs the full test matrix on 3.14t as a non-blocking job.
  • PEP 561 type information. The package now ships a py.typed marker so downstream type checkers can use its annotations. #692
  • None for port and database. create_client, create_async_client, connect(), and the DB-API Connection constructor now accept None to request the driver's defaults, in addition to omitting them. The internal sentinel values are still accepted, so this is backward compatible. #801
  • QueryResult.query_id now returns an empty string instead of None when the server reported no query id. This matches QuerySummary and keeps the property consistently typed as str.

Bug fixes

  • QueryResult.first_item and QueryResult.first_row now return None for an empty result set instead of raising IndexError. #824
  • Cursor.executemany now resets rowcount and reports the number of inserted rows after a bulk insert, and appends the insert summary to cursor.summary. Passing a generator as seq_of_parameters no longer raises TypeError. The bulk-insert optimization is skipped for non-indexable iterables and falls through to the row-by-row path as PEP 249 requires.
  • A connection failure partway through reading a query result is no longer silently treated as a complete result. A mid-stream read failure now raises StreamFailureError, carrying the server-side error message when ClickHouse reported one. #802
  • Client.insert_arrow and AsyncClient.insert_arrow no longer drop the transport_settings argument. It was passed positionally into the compression parameter, so transport settings were ignored. It is now forwarded correctly.
  • command now raises ProgrammingError when binary parameter binds are combined with command data or external data, instead of placing binary content into the URL query string. This applies to both the sync and async clients.
  • Importing clickhouse-connect no longer emits a DeprecationWarning for the array 'u' type code. This also lets projects that run with -W error import the package. #815
  • The SQLAlchemy Nullable and LowCardinality DDL helpers are now functions that return a concrete ChSqlaType, so Array(LowCardinality(String)) no longer raises a spurious mypy error. Runtime behavior is unchanged. #819

Compatibility

  • Client.insert, AsyncClient.insert, and raw_insert now require column_names to be a Sequence rather than a bare Iterable. A one-shot iterator such as a generator already failed at runtime because the column names are measured and iterated more than once, so the type hint now matches the real requirement.

Upgrade notes

  • Building from source now requires Cython 3.1 or later.
  • If you pass column_names as a generator or other one-shot iterator, switch to a Sequence such as a list or tuple. This path already failed at runtime.

Installation

pip install clickhouse-connect