8000 Default MODIFY/CHANGE COLUMN to Nullable when schema metadata is unavailable by clchen-dev · Pull Request #1339 · Altinity/clickhouse-sink-connector · GitHub
[go: up one dir, main page]

Skip to content

Default MODIFY/CHANGE COLUMN to Nullable when schema metadata is unavailable - #1339

Merged
subkanthi merged 2 commits into
Altinity:2.10.0from
clchen-dev:fix-modify-column-nullable-fallback
Jul 19, 2026
Merged

subkanthi merged 2 commits into
Altinity:2.10.0from
clchen-dev:fix-modify-column-nullable-fallback

Conversation

@clchen-dev
@clchen-dev clchen-dev commented Jul 17, 2026 •
Copy link
Copy Markdown
Contributor

Summary

When a MODIFY COLUMN or CHANGE COLUMN DDL has no explicit NULL/NOT NULL constraint, MySqlDDLParserListenerImpl determines nullability by looking up the column's current state in ClickHouse. If that lookup is unavailable (broken DB connection or query error), the column falls back to non-Nullable.

In MySQL, omitting the nullability constraint on MODIFY/CHANGE COLUMN makes the column nullable. Replicating it as non-Nullable caused stuck mutations in our production environment: a MODIFY COLUMN DDL was translated to a non-Nullable ClickHouse mutation on a column that contained NULL values, and the mutation could never complete. We have been running this fix in production and verified it resolves the issue.

Changes

  • Set isNullColumn = true in the AlterByModifyColumnContext and AlterByChangeColumnContext branches, consistent with the existing AlterByAddColumnContext behavior.
  • Explicit NULL/NOT NULL constraints and the ClickHouse metadata lookup still take precedence. Only the fallback path (lookup unavailable or failed) changes.

Known trade-off

If the modified column is part of the ClickHouse table's ORDER BY / primary key and the schema lookup is unavailable at the same time, the generated MODIFY COLUMN ... Nullable(...) DDL will be rejected by ClickHouse ("Sorting key cannot contain nullable columns"). The old fallback happened to be correct for that narrow case, but silently produced stuck mutations for ordinary nullable columns. The new fallback fails loudly at DDL time instead of corrupting replication silently. The normal path is unaffected: when the metadata lookup succeeds, sorting-key columns still resolve to non-Nullable.

Tests

  • Updated 6 unit test expectations in MySqlDDLParserListenerImplTest that pinned the old non-Nullable fallback (unit tests run without a DB connection, so they exercise exactly this path).
  • Added 4 new unit tests verifying explicit constraints still win over the new default: testModifyColumnWithNotNull, testModifyColumnWithExplicitNull, testChangeColumnWithNotNull, testChangeColumnWithExplicitNull.
  • MySqlDDLParserListenerImplTest: 99 run, 0 failures.
  • AlterTableModifyColumnIT (testcontainers, live MySQL + ClickHouse): passes unchanged, confirming the live-connection path is unaffected.

Files Changed

  • sink-connector-lightweight/src/main/java/com/altinity/clickhouse/debezium/embedded/ddl/parser/MySqlDDLParserListenerImpl.java (2 branches)
  • sink-connector-lightweight/src/test/java/com/altinity/clickhouse/debezium/embedded/ddl/parser/MySqlDDLParserListenerImplTest.java (6 updated expectations, 4 new tests)

…ailable

When a MODIFY COLUMN or CHANGE COLUMN DDL has no explicit NULL/NOT NULL
constraint, the parser looks up the column's current nullability from
ClickHouse. If that lookup fails (no DB connection or query error), the
column previously defaulted to non-Nullable, which can produce stuck
mutations in ClickHouse when existing rows contain NULL values.

In MySQL, omitting the nullability constraint on MODIFY/CHANGE COLUMN
makes the column nullable, so default to Nullable in the fallback path,
consistent with the existing ADD COLUMN behavior. Explicit NULL/NOT NULL
constraints and the ClickHouse metadata lookup still take precedence.
@clchen-dev
clchen-dev force-pushed the fix-modify-column-nullable-fallback branch from 7b81ab1 to ea98c1e Compare July 17, 2026 19:42
@clchen-dev
Copy link
Copy Markdown
Contributor Author

Hi @subkanthi, could you take a look at this PR when you get a chance? The CI workflows also need maintainer approval to run since this is my first contribution here. Thanks!

@subkanthi
subkanthi changed the base branch from develop to 2.10.0 July 17, 2026 22:16
- Add explanatory comment to the AlterByChangeColumnContext branch,
  matching the MODIFY COLUMN branch above.
- Add testChangeColumnWithExplicitNull to complete the explicit
  constraint test matrix (MODIFY/CHANGE x NULL/NOT NULL).
- Fix missing blank line before testAddConstraints.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@clchen-dev
Copy link
Copy Markdown
Contributor Author

🤖 AI Review (Claude)

This review was performed by an AI assistant (Claude, Anthropic) at the author's request, including tracing the affected code paths and running the test suite locally.

Correctness

Traced the full isNullColumn data flow through parseAlterTable on this branch and confirmed the change behaves exactly as described in the PR summary:

  • Explicit NULL / NOT NULL constraints still take precedence — the NullColumnConstraintContext branch sets nullExplicitlySet and overwrites isNullColumn after the new initialization.
  • The ClickHouse metadata lookup still takes precedence — on the success path all three branches (nullable / column-not-found / non-nullable) explicitly assign isNullColumn, so the new default is only observable when the lookup is unavailable (writer == null) or throws.
  • The new default matches MySQL semantics — MODIFY/CHANGE COLUMN replace the entire column definition, and omitting the constraint makes the column nullable. It is also consistent with the existing ADD COLUMN default and with the pre-existing "column not found in metadata → nullable" behavior.
  • CHANGE COLUMN metadata lookup uses the old column name — correct, since it queries the pre-change state of the column.

Trade-off

One narrow regression scenario exists in the fallback path: if the modified column is part of the ClickHouse sorting key and the metadata lookup is down at the same moment, the generated Nullable(...) DDL is rejected by ClickHouse instead of succeeding. That failure is loud and recoverable at DDL time, whereas the old fallback silently produced stuck mutations for ordinary nullable columns — a reasonable trade. The normal (lookup-success) path is unchanged. This is now documented in the PR description.

Tests

  • MySqlDDLParserListenerImplTest: 99 run, 0 failures (verified locally, JDK 17 / Maven 3.9.9). Unit tests run without a DB connection, so they exercise exactly the changed fallback path.
  • The explicit-constraint matrix is fully covered: MODIFY/CHANGE × NULL/NOT NULL (testModifyColumnWithNotNull, testModifyColumnWithExplicitNull, testChangeColumnWithNotNull, testChangeColumnWithExplicitNull).
  • Note: the updated expectations pin some pre-existing whitespace quirks of the nullable code path (double space in Nullable(Bool) first, trailing space before \n). These predate this PR — the ADD COLUMN nullable path behaves identically — and are harmless to ClickHouse; cleaning them up would belong in a separate PR.

Verdict

The fix is correct, minimally scoped, consistent with existing behavior, and well tested. Earlier review nits (comment symmetry on the CHANGE COLUMN branch, the missing CHANGE + explicit NULL test, a formatting nit) were addressed in eb3019e.

@subkanthi
subkanthi merged commit fcc59b0 into Altinity:2.10.0 Jul 19, 2026
14 of 15 checks passed
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.

2 participants

0