8000 fix(python): compare the source table column set; detect replica-only columns and fail by default (Spec 11.02 sections 3.3, 3.9, FM-11.02-10) by minguyen9988 · Pull Request #1557 · Altinity/clickhouse-sink-connector · GitHub
[go: up one dir, main page]

Skip to content

fix(python): compare the source table column set; detect replica-only columns and fail by default (Spec 11.02 sections 3.3, 3.9, FM-11.02-10) - #1557

Merged
minguyen9988 merged 2 commits into
2.11.0from
fix-checksum-replica-only-columns
Oct 4, 2026
Merged

minguyen9988 merged 2 commits into
2.11.0from
fix-checksum-replica-only-columns

Conversation

@minguyen9988
@minguyen9988 minguyen9988 commented Oct 4, 2026 •
Copy link
Copy Markdown
Collaborator

Problem

The replica side of db_compare hashes every column in system.columns, the source side every column in information_schema.columns. A column added on ClickHouse only (for example ADD COLUMN name Nullable(String) DEFAULT JSONExtractString(payload, Name)) is hashed on one side only, so the table reports a checksum difference on every later run, with nothing pointing at the column, even though every replicated value agrees. Adding columns on the destination is also not good practice: the replica must conform to the source, so such columns should be detected and reported, not silently tolerated. We hit this on a production table whose replicas gained such a column.

Change (Spec 11.02 section 3.3 column set, section 3.9, new FM-11.02-10)

  • Driver: reads the source table column names (db.mysql.mysql_column_names) and passes them to every replica side as --source_columns, a JSON list so any column name survives the trip. The source side is unchanged.
  • Replica side (restrict_to_source_columns): keeps only the columns the source table also has, compared case-insensitively. A replica-only column contributes nothing to the row string and is reported once per table as Replica-only columns in table db.t: [...]. A source column the replica lacks is named and still reports DIFFERENT.
  • Detection: the driver parses that line (record_replica_only). Default: one WARNING REPLICA-ONLY COLUMNS -- host db.t: [...] exist on the ClickHouse destination but not in the source table, telling the owner to stop adding columns on the destination (drop them there, or add them to the source table so they replicate); a summary WARNING at the end; exit code 1. With --allow_replica_only_columns the columns are logged at INFO and the exit code is unaffected. Either way the table MATCH/DIFFERENT verdict covers the replicated columns only, so a replica-only column never shows up as a false checksum difference. A column in the job ignored_columns is excluded before the check, which is the reviewed per-column acceptance.
  • Without --source_columns (standalone side runs, test_db.sh, e2e recipes) nothing changes.
  • FM-11.02-9: history-replica columns are now reported as replica-only; pass --allow_replica_only_columns for a history replica.

Verification

  • On the affected production table, the replica-side aggregate generated by this code equals the source checksum; the same harness without the column set reproduces the failing replica checksum exactly.
  • Tests: TestReplicaOnlyColumns; TestSourceColumnSetReachesTheReplicaSide (default fails with the finding and keeps No difference, the flag keeps it green, no carry-over between runs); TestScheduledJobLogContract replica-only cases through main() with the scheduled job flags. Mutation-checked: keeping every column, dropping the option from the replica command, forcing the flag on, or ignoring it each turns the matching tests red.

Whole-Change-Verification: ran=cd sink-connector/python and python -m pytest db_compare/tests -q (330 passed, 1 skipped) plus python3 scripts/validate_specs.py (PASSED), both on this branch head on top of 2.11.0 befda7b; result=pass

Opened on behalf of our database team; the maintainers own the review and the merge.

minguyen9988 and others added 2 commits October 4, 2026 01:24
…mns are named, not hashed (Spec 11.02 sections 3.3, 3.9, FM-11.02-10)

The replica side of db_compare hashed every column in system.columns, the
source side every column in information_schema. A column added on
ClickHouse alone (for example ADD COLUMN name Nullable(String) DEFAULT
JSONExtractString(payload, 'Name')) was therefore hashed on one side only:
the table reported DIFFERENT on every later run, with nothing pointing at
the column, although every replicated value agreed.

- driver: reads the source table's column names
  (db.mysql.mysql_column_names) and passes them to every replica side as
  --source_columns, a JSON list so a column name holding a comma or a space
  survives the trip; the source side is unchanged.
- replica side: restrict_to_source_columns() keeps only the columns the
  source table also has (case-insensitive, as MySQL names columns), names
  replica-only columns in one coverage WARNING per table (relayed by the
  driver at INFO, like the float/JSON notes), and names source columns the
  replica lacks (those still report DIFFERENT: a real replication gap).
- without --source_columns (standalone side runs) behaviour is unchanged.
- spec 11.02: column set (3.3), coverage (3.9), new FM-11.02-10; FM-11.02-9
  notes that history columns are now left out as replica-only.

Verified on a production table whose replicas carry such a column: with the
column set restricted, the replica-side aggregate equals the source
checksum; without it, it reproduces the failing replica checksum.

Tests: TestReplicaOnlyColumns, TestSourceColumnSetReachesTheReplicaSide,
mutation-checked (keeping every column, or dropping the option from the
replica command, turns them red). db_compare suite: 325 passed, 1 skipped.
scripts/validate_specs.py: PASSED.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…; --allow_replica_only_columns accepts them (Spec 11.02 section 3.9, FM-11.02-10)

Adding columns on the ClickHouse destination is not supported practice:
the replica must conform to the source. The checksum therefore detects
such columns instead of only tolerating them.

- replica side: the report is a distinct, parseable line,
  "Replica-only columns in table db.t: [...]".
- driver: record_replica_only() parses it per (replica host, table).
  Default: one "WARNING REPLICA-ONLY COLUMNS -- host db.t: [...]" naming
  the remedy (stop adding columns on the destination; drop them there or
  add them to the source table), a summary WARNING at the end of the run,
  and exit code 1. With --allow_replica_only_columns the columns are logged
  at INFO and the exit code is unaffected.
- either way the columns stay out of the row string, so the table verdict
  is about replicated columns only (no false "Checksum difference").
- a column in the job ignored_columns is excluded before the check: the
  reviewed per-column acceptance.

Tests: TestSourceColumnSetReachesTheReplicaSide (default fails with the
finding and keeps "No difference"; the flag keeps it green; no carry-over
between runs), TestScheduledJobLogContract replica-only cases through main()
with the job flags. Mutation-checked: forcing the flag on fails the two
default tests, ignoring it fails the two flag tests. db_compare suite:
330 passed, 1 skipped; validate_specs.py PASSED.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@minguyen9988 minguyen9988 changed the title fix(python): compare the source table column set; replica-only columns are named, not hashed (Spec 11.02 sections 3.3, 3.9, FM-11.02-10) fix(python): compare the source table column set; detect replica-only columns and fail by default (Spec 11.02 sections 3.3, 3.9, FM-11.02-10) Oct 4, 2026
@minguyen9988
minguyen9988 merged commit 1154720 into 2.11.0 Oct 4, 2026
13 checks passed
@minguyen9988
minguyen9988 deleted the fix-checksum-replica-only-columns branch October 4, 2026 07:57
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.

1 participant

0