Skip to content

feat: add replicated parameter for ClickHouse connection - #835

Merged
dossy merged 1 commit into
amacneil:mainfrom
egorsavkin-plb:ch-replicated
Sep 19, 2026
Merged

dossy merged 1 commit into
amacneil:mainfrom
egorsavkin-plb:ch-replicated

Conversation

@egorsavkin-plb

Copy link
Copy Markdown
Contributor

This PR adds support for the modern Replicated table engine in the ClickHouse without the ON CLUSTER clause, which is often incompatible with the replicated databases. Wired this as replicated connection parameter and then reused zoo_path parameter.

Previously to avoid the issues we would need to do this manually, which defeats the purpose of the dbmate:

create table <migrations table>
(
    version String,
    ts      DateTime default now(),
    applied UInt8    default 1
)
    engine = ReplicatedReplacingMergeTree(ts)
        PRIMARY KEY version
        ORDER BY version
        SETTINGS index_granularity = 8192;

@egorsavkin-plb

Copy link
Copy Markdown
Contributor Author

@sofuture @hillna please review

@dossy

dossy commented Sep 16, 2026

Copy link
Copy Markdown
Collaborator

Thanks for the PR, @egorsavkin-plb.

You said "modern Replicated table engine" but I think you meant "modern Replicated database engine" that you get when you create the database using CREATE DATABASE ... ENGINE = Replicated(...) instead of the Atomic database engine which you get by default in open-source ClickHouse, or the Shared database engine that you get by default in ClickHouse Cloud?

You're absolutely right that in most situations, you won't use ON CLUSTER in a Replicated database engine setup (the ClickHouse documentation calls out one situation where you must, if the database's zoo_path contains the {uuid} macro, either explicitly specify the UUID value or use ON CLUSTER), and dbmate has no way to handle that currently.

I spent some time testing the behaviour against a two node cluster on ClickHouse 22.8 (what our current CI pipeline tests against) and 26.8 (current LTS). Results were identical on both.

A few things I'd like to discuss:

In self-hosted ClickHouse, the replicated parameter requires the Replicated database engine, and nothing says so

When tested against a plain self-hosted ClickHouse Atomic database, which is the default, the CREATE TABLE ... ENGINE clause this PR generates fails outright:

Version Error Code Error Message
22.8 Code: 62 Macro 'uuid' and empty arguments of ReplicatedMergeTree are supported only for ON CLUSTER queries with Atomic database engine. (SYNTAX_ERROR)
26.8 Code: 36 Macro 'uuid' in engine arguments is only supported when the UUID is explicitly specified, used within an ON CLUSTER query, or when using the Replicated database engine. (BAD_ARGUMENTS)

With ENGINE = Replicated(...) on the CREATE DATABASE it works exactly as you describe: the DDL propagates to every replica with no ON CLUSTER required and the migrations table appears on all of them, and rows replicate as intended.

How do you feel about checking the engine type of the database, e.g., using select engine from system.databases where name = ?, and making sure it's Replicated or Shared before proceeding with the replicated parameter behavior, and raising an error otherwise? I don't have a Cloud account to verify the Shared case, so if you're running there I'd welcome confirmation.

The zoo_path branch is not fail safe

The two branches behave in opposite ways on an Atomic database, which I don't think is intentional:

  • replicated on its own emits ReplicatedReplacingMergeTree(ts) and fails loudly, as above. Cryptic, but safe.

  • replicated with zoo_path set emits ReplicatedReplacingMergeTree('<zoo_path>', '{replica}', ts), which is perfectly valid SQL without ON CLUSTER. It succeeds, and creates the migrations table on exactly the one node dbmate connected to, and only that node. No error, and the migrations table now lives only on a single node of a cluster instead of being replicated across all nodes. Anything that later connects to a different node sees no migrations table.

I'd prefer this to be prevented in the code than only documented in a README, if possible. The same engine check mentioned above could be used to catch this.

dbmate can't create the database this feature needs

CreateDatabase issues a bare create database with no engine clause, which produces an Atomic (or Shared, in the case of ClickHouse Cloud) database. So dbmate cannot itself create a database that replicated will work against in a self-hosted setup. The user has to have pre-created it with ENGINE = Replicated(...). Worth stating explicitly in the docs, since dbmate create is otherwise expected to just work.

Smaller things

  • If on_cluster and replicated are both present: the code takes the OnCluster branch and silently ignores replicated. I'd make that an explicit error rather than a silent precedence rule.

  • extractZookeeperPath treats zoo_path= (present but empty) as unset, because it tests zookeeperPath == "" rather than v.Has(...). Probably fine, but worth making this clear by including a test case that shows this is the intended and expected behavior.

  • Please remove the version bump in version.go. Version bumps are handled as part of the release process.

One more thing ...

For anyone following #783: I checked, and the table's ZooKeeper path inside a Replicated database still comes from default_replica_path using the server macros, not from the database engine's own shard and replica arguments. On my test cluster it resolved to /clickhouse/tables/<uuid>/shard-01. So the {shard} concern discussed over in that issue applies here too, and this PR's no zoo_path branch inherits it.

@dossy dossy added feature request go Pull requests that update Go code needs review labels Sep 16, 2026
…ne gate, mutual exclusion for on_cluster and replicated, readme
@dossy

dossy commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator

Thanks, @egorsavkin-plb, this addresses everything from the earlier review: the engine check now covers both the bare (ts) branch and the zoo_path branch, CreateDatabase refuses to proceed with replicated set instead of silently creating an unusable Atomic database, and the version bump is gone. I checked the diff directly (not just the commit message) and ran go build / go vet against the branch, both clean.

...

One thing I can't verify myself: I only have access to self-hosted ClickHouse, so I've only exercised the Replicated database engine branch, not Shared. Do you happen to have access to ClickHouse Cloud, and if so, were you able to test replicated against a Shared database there? Not a blocker, just want to know what's actually been verified versus what's just read from the docs.

If that checks out (or if you haven't had a chance to test Cloud and that's fine too), this looks ready to merge from my side.

@egorsavkin-plb

Copy link
Copy Markdown
Contributor Author

@dossy Unfortunately I also don't have the access to CH Cloud, so couldn't verify this case...

@dossy

dossy commented Sep 19, 2026

Copy link
Copy Markdown
Collaborator

Going to merge this as it shouldn't break backwards-compatibility as it's new functionality, and if anyone who has ClickHouse Cloud tests this and finds it doesn't work right, they can open a new issue.

@dossy
dossy merged commit 3dbe454 into amacneil:main Sep 19, 2026
10 checks passed
@dossy dossy mentioned this pull request Sep 19, 2026
dossy added a commit that referenced this pull request Sep 19, 2026
Changes since v2.35.1:

* #835
* #803
* #834
* #827
* #785
* #833
* #825
* #823
* #837
* #705
* #814
* #840
* #826
* #841
* #839, #831
* #836
* #832
* #830
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature request go Pull requests that update Go code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants