[split 18/22] core: DDL schema-change waiter, source-schema integrity validator, replication freeze manager, error classifier (new classes, not yet wired) - #1373
Merged
minguyen9988 merged 2 commits intoAug 18, 2026
Conversation
…plication freeze manager, error classifier (new classes, not yet wired) Adds four new core classes with their unit tests. NOT yet referenced by any existing code path - wiring happens in the executor PR - so this PR is behavior-neutral by construction. - DDLSchemaChangeWaiter: after a DDL, polls system.columns (bounded by ddl.schema.change.timeout.ms) until the destination schema reflects the change, so DML following a DDL never binds against a stale column set. Exempts the replication-history table (its audit schema never mirrors source columns; gating on it starved the shared system pool on the combined PR). - SourceSchemaIntegrityValidator + SourceSchemaColumns: compares source-event columns against the destination insert cache; genuinely missing columns block the batch (data-loss protection), while MySQL generated columns (MATERIALIZED on the destination, excluded from the insert cache by design) are filtered out - counting them as missing caused an 8,208-rebuild livelock on the combined PR. - TableReplicationFreezeManager: freezes replication for a table on unrecoverable schema mismatch instead of silently dropping records. - ClickHouseErrorClassifier: classifies ClickHouse exceptions into retryable vs fatal so the batch loop can stop retrying permanently-failing batches. Merge order: after the config PR (uses ddl.schema.change.* keys). Part of the split of #1353 into independently mergeable sub-PRs (each <= 10 files), so the 2.10.0 branch can absorb the fixes incrementally.
…tements, TRUNCATE guard on CDC path, version sentinel guard (#1374) * batch: destination-only column omission in prepared statements, TRUNCATE guard on CDC path, version sentinel guard Merge after the db-ops PR (uses the QueryFormatter overload) and the config PR (reads disable.drop.truncate). - PreparedStatementFieldMapper / PreparedStatementExecutor: destination-only columns are omitted from binds (paired with the QueryFormatter overload); the CDC data path now honors disable.drop.truncate before executing TRUNCATE - previously this path applied every TRUNCATE unconditionally, so the guard silently failed to protect it. - GroupInsertQueryWithBatchRecords: passes the destination column set through (new overload; the old signature is kept); dead failedRecords list removed (was never read). - VersionSentinelGuardTest: pins that a missing version column can never silently bind the 0 sentinel (_version=0 rows lose every ReplacingMergeTree merge - silent row loss). Part of the split of #1353 into independently mergeable sub-PRs (each <= 10 files), so the 2.10.0 branch can absorb the fixes incrementally. * [split 20/22] executor: offset re-insert fix, volatile pause barrier, per-thread cache invalidation generations, schema-cache TTL (#1375) * executor: offset re-insert fix, volatile pause barrier, per-thread cache invalidation generations, schema-cache TTL Wires the new core classes into the batch path. The heart of the race-condition fixes. Merge after config, db-ops, core-classes and batch PRs. - Duplicate-insert fix: an already-flushed batch waiting on offset commit was re-INSERTED on every retry pass (one record observed 1,000 times on the combined PR). A flushed batch now only re-checks committability - never re-inserts. - ClickHouseBatchExecutor.isPaused becomes volatile: it is the DDL-vs-DML barrier, written by the Debezium thread and read in the batch threads' spin loop with no other happens-before edge. Without volatile the read can be hoisted and a batch thread can apply DML against a schema mid-DDL - silent corruption, not a stall. - Cache invalidation by generation: the previous remove-on-read signal let the FIRST worker thread consume the invalidation, leaving every other thread on a stale DbWriter (stale column list) forever. Per-table monotonic generation counters let every thread invalidate independently; plus a schema-cache TTL (default 1h) so a missed DDL self-heals. CacheInvalidationManagerTest / CacheInvalidationManagerTtlTest. - DebeziumOffsetManagement.acknowledgeRecord for the single-record path; beginFlush no longer collides with an in-flight flush (the original OffsetStorageWriter "already flushing" crash from the production log). - Integrity gate + freeze manager + error classifier wired into ClickHouseBatchRunnable / ClickHouseBatchWriter; DbWriter carries the cache generation. Part of the split of #1353 into independently mergeable sub-PRs (each <= 10 files), so the 2.10.0 branch can absorb the fixes incrementally. * [split 21/22] tests: race-condition suites for DDL waiter, offset commit, pause visibility (test-only) (#1376) * tests: race-condition suites for DDL waiter, offset commit, pause visibility (test-only) Test-only. Merge after the executor PR. Multi-threaded race harnesses: concurrent DDL + batch threads against the schema-change waiter (DDLSchemaChangeWaiterRaceConditionTest, DDLFreezeRaceConditionTest), concurrent offset acknowledgement vs flush (OffsetCommitConcurrencyTest), executor pause visibility under the JMM (ExecutorPauseVisibilityTest), and lazy system-connection construction (LazySystemConnectionTest). Split from the executor PR only to respect the 10-file-per-PR limit. Part of the split of #1353 into independently mergeable sub-PRs (each <= 10 files), so the 2.10.0 branch can absorb the fixes incrementally. * lightweight engine: single-threaded DDL pause NPE, snapshot DDL exemption, restart-loop fixes, sequence race (#1377) Final wiring PR for the lightweight connector; merge last. - Single-threaded NPE: in single.threaded mode no batch executor exists, but the DDL branch called executor.pause() unconditionally - NPE on the very first DDL of every run (upstream swallowed it in a log-only catch). Null-safe pause/resume helpers; in single-threaded mode DML is synchronous on the DDL thread, so the no-op is semantically correct. SingleThreadedDdlPauseTest. - Snapshot DDL exemption: the (now actually working) disable.drop.truncate guard suppressed the DROP half of Debezium's snapshot DROP+CREATE replay, so every CREATE hit TABLE_ALREADY_EXISTS in a retry freeze. Snapshot-phase DDL is exempt - its delivery is already governed by enable.snapshot.ddl; streaming DROP/TRUNCATE stays blocked. DropTruncateSnapshotExemptionTest pins all four quadrants. - Restart handling: engine rebuild moved off the callback thread (inline rebuild nested a stack frame per retry); stop() uses shutdownNow(); upstream retry budget restored (11 attempts). DebeziumEngineRestartTest. - Sequence race: out-of-order batches could re-arm the version-counter reset so two rows shared one _version (measured 199/200 duplicates) - the anchor no longer moves backward. SequenceNumberRaceTest. - IgnoreDDLRegexLoader case handling + IgnoreDDLRegexLoaderTest; Version280CompatibilityTest pins the 2.8.0 _version formula byte-for-byte. Part of the split of #1353 into independently mergeable sub-PRs (each <= 10 files), so the 2.10.0 branch can absorb the fixes incrementally. Co-authored-by: minguyen9988 <minguyen9988@users.noreply.github.com> --------- Co-authored-by: minguyen9988 <minguyen9988@users.noreply.github.com> --------- Co-authored-by: minguyen9988 <minguyen9988@users.noreply.github.com> --------- Co-authored-by: minguyen9988 <minguyen9988@users.noreply.github.com>
minguyen9988
added a commit
that referenced
this pull request
Aug 18, 2026
…DDL translation regression suite (#1372) * ddl parser: case-insensitive built-in ignore patterns, DDL translation regression suite - The built-in ANALYZE PARTITION ignore pattern gains (?i) (its ADD/DROP PARTITION siblings already had it), and the built-in ignore branch now records lastIgnoredDDL exactly like the user-configured IGNORE_DDL_REGEX branch - previously a built-in-ignored statement was invisible to operators. - MySqlDDLParserListenerImpl: DATETIME(p) precision translation, generated-column and charset clause handling, extractTableName helper. - DDLTranslationRegressionTest (new) + DropTruncateDetectionTest pin MySQL -> ClickHouse DDL translation end-to-end; MySqlDDLParserListenerImplTest expanded. - DataTypeConverter DateTime64 precision fix rides along because the translation tests assert through it. Part of the split of #1353 into independently mergeable sub-PRs (each <= 10 files), so the 2.10.0 branch can absorb the fixes incrementally. * [split 18/22] core: DDL schema-change waiter, source-schema integrity validator, replication freeze manager, error classifier (new classes, not yet wired) (#1373) * core: DDL schema-change waiter, source-schema integrity validator, replication freeze manager, error classifier (new classes, not yet wired) Adds four new core classes with their unit tests. NOT yet referenced by any existing code path - wiring happens in the executor PR - so this PR is behavior-neutral by construction. - DDLSchemaChangeWaiter: after a DDL, polls system.columns (bounded by ddl.schema.change.timeout.ms) until the destination schema reflects the change, so DML following a DDL never binds against a stale column set. Exempts the replication-history table (its audit schema never mirrors source columns; gating on it starved the shared system pool on the combined PR). - SourceSchemaIntegrityValidator + SourceSchemaColumns: compares source-event columns against the destination insert cache; genuinely missing columns block the batch (data-loss protection), while MySQL generated columns (MATERIALIZED on the destination, excluded from the insert cache by design) are filtered out - counting them as missing caused an 8,208-rebuild livelock on the combined PR. - TableReplicationFreezeManager: freezes replication for a table on unrecoverable schema mismatch instead of silently dropping records. - ClickHouseErrorClassifier: classifies ClickHouse exceptions into retryable vs fatal so the batch loop can stop retrying permanently-failing batches. Merge order: after the config PR (uses ddl.schema.change.* keys). Part of the split of #1353 into independently mergeable sub-PRs (each <= 10 files), so the 2.10.0 branch can absorb the fixes incrementally. * [split 19/22] batch: destination-only column omission in prepared statements, TRUNCATE guard on CDC path, version sentinel guard (#1374) * batch: destination-only column omission in prepared statements, TRUNCATE guard on CDC path, version sentinel guard Merge after the db-ops PR (uses the QueryFormatter overload) and the config PR (reads disable.drop.truncate). - PreparedStatementFieldMapper / PreparedStatementExecutor: destination-only columns are omitted from binds (paired with the QueryFormatter overload); the CDC data path now honors disable.drop.truncate before executing TRUNCATE - previously this path applied every TRUNCATE unconditionally, so the guard silently failed to protect it. - GroupInsertQueryWithBatchRecords: passes the destination column set through (new overload; the old signature is kept); dead failedRecords list removed (was never read). - VersionSentinelGuardTest: pins that a missing version column can never silently bind the 0 sentinel (_version=0 rows lose every ReplacingMergeTree merge - silent row loss). Part of the split of #1353 into independently mergeable sub-PRs (each <= 10 files), so the 2.10.0 branch can absorb the fixes incrementally. * [split 20/22] executor: offset re-insert fix, volatile pause barrier, per-thread cache invalidation generations, schema-cache TTL (#1375) * executor: offset re-insert fix, volatile pause barrier, per-thread cache invalidation generations, schema-cache TTL Wires the new core classes into the batch path. The heart of the race-condition fixes. Merge after config, db-ops, core-classes and batch PRs. - Duplicate-insert fix: an already-flushed batch waiting on offset commit was re-INSERTED on every retry pass (one record observed 1,000 times on the combined PR). A flushed batch now only re-checks committability - never re-inserts. - ClickHouseBatchExecutor.isPaused becomes volatile: it is the DDL-vs-DML barrier, written by the Debezium thread and read in the batch threads' spin loop with no other happens-before edge. Without volatile the read can be hoisted and a batch thread can apply DML against a schema mid-DDL - silent corruption, not a stall. - Cache invalidation by generation: the previous remove-on-read signal let the FIRST worker thread consume the invalidation, leaving every other thread on a stale DbWriter (stale column list) forever. Per-table monotonic generation counters let every thread invalidate independently; plus a schema-cache TTL (default 1h) so a missed DDL self-heals. CacheInvalidationManagerTest / CacheInvalidationManagerTtlTest. - DebeziumOffsetManagement.acknowledgeRecord for the single-record path; beginFlush no longer collides with an in-flight flush (the original OffsetStorageWriter "already flushing" crash from the production log). - Integrity gate + freeze manager + error classifier wired into ClickHouseBatchRunnable / ClickHouseBatchWriter; DbWriter carries the cache generation. Part of the split of #1353 into independently mergeable sub-PRs (each <= 10 files), so the 2.10.0 branch can absorb the fixes incrementally. * [split 21/22] tests: race-condition suites for DDL waiter, offset commit, pause visibility (test-only) (#1376) * tests: race-condition suites for DDL waiter, offset commit, pause visibility (test-only) Test-only. Merge after the executor PR. Multi-threaded race harnesses: concurrent DDL + batch threads against the schema-change waiter (DDLSchemaChangeWaiterRaceConditionTest, DDLFreezeRaceConditionTest), concurrent offset acknowledgement vs flush (OffsetCommitConcurrencyTest), executor pause visibility under the JMM (ExecutorPauseVisibilityTest), and lazy system-connection construction (LazySystemConnectionTest). Split from the executor PR only to respect the 10-file-per-PR limit. Part of the split of #1353 into independently mergeable sub-PRs (each <= 10 files), so the 2.10.0 branch can absorb the fixes incrementally. * lightweight engine: single-threaded DDL pause NPE, snapshot DDL exemption, restart-loop fixes, sequence race (#1377) Final wiring PR for the lightweight connector; merge last. - Single-threaded NPE: in single.threaded mode no batch executor exists, but the DDL branch called executor.pause() unconditionally - NPE on the very first DDL of every run (upstream swallowed it in a log-only catch). Null-safe pause/resume helpers; in single-threaded mode DML is synchronous on the DDL thread, so the no-op is semantically correct. SingleThreadedDdlPauseTest. - Snapshot DDL exemption: the (now actually working) disable.drop.truncate guard suppressed the DROP half of Debezium's snapshot DROP+CREATE replay, so every CREATE hit TABLE_ALREADY_EXISTS in a retry freeze. Snapshot-phase DDL is exempt - its delivery is already governed by enable.snapshot.ddl; streaming DROP/TRUNCATE stays blocked. DropTruncateSnapshotExemptionTest pins all four quadrants. - Restart handling: engine rebuild moved off the callback thread (inline rebuild nested a stack frame per retry); stop() uses shutdownNow(); upstream retry budget restored (11 attempts). DebeziumEngineRestartTest. - Sequence race: out-of-order batches could re-arm the version-counter reset so two rows shared one _version (measured 199/200 duplicates) - the anchor no longer moves backward. SequenceNumberRaceTest. - IgnoreDDLRegexLoader case handling + IgnoreDDLRegexLoaderTest; Version280CompatibilityTest pins the 2.8.0 _version formula byte-for-byte. Part of the split of #1353 into independently mergeable sub-PRs (each <= 10 files), so the 2.10.0 branch can absorb the fixes incrementally. Co-authored-by: minguyen9988 <minguyen9988@users.noreply.github.com> --------- Co-authored-by: minguyen9988 <minguyen9988@users.noreply.github.com> --------- Co-authored-by: minguyen9988 <minguyen9988@users.noreply.github.com> --------- Co-authored-by: minguyen9988 <minguyen9988@users.noreply.github.com> --------- Co-authored-by: minguyen9988 <minguyen9988@users.noreply.github.com> --------- Co-authored-by: minguyen9988 <minguyen9988@users.noreply.github.com>
minguyen9988
added a commit
that referenced
this pull request
Aug 18, 2026
…TER/CREATE quoting fixes (#1371) * db ops: QueryFormatter destination-column awareness, ALTER/CREATE quoting fixes Builds on the config PR (merge after it). - QueryFormatter.getInsertQueryUsingInputFunction: new overload accepting the destination's known columns so destination-only columns (e.g. added via ALTER TABLE ADD COLUMN before the connector saw the DDL) are OMITTED from the insert - ClickHouse then fills their DEFAULT - instead of force-binding NULL, which poisons the whole batch on non-nullable columns and replays it forever (observed as a 165/200 data-loss failure on the combined PR). - ClickHouseAlterTable / ClickHouseAutoCreateTable / ClickHouseCreateDatabase: identifier quoting per dotted component; ClickHouseDbConstants gains the shared column-name constants. - DbKafkaOffsetWriter aligned with the quoting rules. - QueryFormatterTest + ClickHouseAlterTableTest expanded to pin all of the above. Part of the split of #1353 into independently mergeable sub-PRs (each <= 10 files), so the 2.10.0 branch can absorb the fixes incrementally. * [split 17/22] ddl parser: case-insensitive built-in ignore patterns, DDL translation regression suite (#1372) * ddl parser: case-insensitive built-in ignore patterns, DDL translation regression suite - The built-in ANALYZE PARTITION ignore pattern gains (?i) (its ADD/DROP PARTITION siblings already had it), and the built-in ignore branch now records lastIgnoredDDL exactly like the user-configured IGNORE_DDL_REGEX branch - previously a built-in-ignored statement was invisible to operators. - MySqlDDLParserListenerImpl: DATETIME(p) precision translation, generated-column and charset clause handling, extractTableName helper. - DDLTranslationRegressionTest (new) + DropTruncateDetectionTest pin MySQL -> ClickHouse DDL translation end-to-end; MySqlDDLParserListenerImplTest expanded. - DataTypeConverter DateTime64 precision fix rides along because the translation tests assert through it. Part of the split of #1353 into independently mergeable sub-PRs (each <= 10 files), so the 2.10.0 branch can absorb the fixes incrementally. * [split 18/22] core: DDL schema-change waiter, source-schema integrity validator, replication freeze manager, error classifier (new classes, not yet wired) (#1373) * core: DDL schema-change waiter, source-schema integrity validator, replication freeze manager, error classifier (new classes, not yet wired) Adds four new core classes with their unit tests. NOT yet referenced by any existing code path - wiring happens in the executor PR - so this PR is behavior-neutral by construction. - DDLSchemaChangeWaiter: after a DDL, polls system.columns (bounded by ddl.schema.change.timeout.ms) until the destination schema reflects the change, so DML following a DDL never binds against a stale column set. Exempts the replication-history table (its audit schema never mirrors source columns; gating on it starved the shared system pool on the combined PR). - SourceSchemaIntegrityValidator + SourceSchemaColumns: compares source-event columns against the destination insert cache; genuinely missing columns block the batch (data-loss protection), while MySQL generated columns (MATERIALIZED on the destination, excluded from the insert cache by design) are filtered out - counting them as missing caused an 8,208-rebuild livelock on the combined PR. - TableReplicationFreezeManager: freezes replication for a table on unrecoverable schema mismatch instead of silently dropping records. - ClickHouseErrorClassifier: classifies ClickHouse exceptions into retryable vs fatal so the batch loop can stop retrying permanently-failing batches. Merge order: after the config PR (uses ddl.schema.change.* keys). Part of the split of #1353 into independently mergeable sub-PRs (each <= 10 files), so the 2.10.0 branch can absorb the fixes incrementally. * [split 19/22] batch: destination-only column omission in prepared statements, TRUNCATE guard on CDC path, version sentinel guard (#1374) * batch: destination-only column omission in prepared statements, TRUNCATE guard on CDC path, version sentinel guard Merge after the db-ops PR (uses the QueryFormatter overload) and the config PR (reads disable.drop.truncate). - PreparedStatementFieldMapper / PreparedStatementExecutor: destination-only columns are omitted from binds (paired with the QueryFormatter overload); the CDC data path now honors disable.drop.truncate before executing TRUNCATE - previously this path applied every TRUNCATE unconditionally, so the guard silently failed to protect it. - GroupInsertQueryWithBatchRecords: passes the destination column set through (new overload; the old signature is kept); dead failedRecords list removed (was never read). - VersionSentinelGuardTest: pins that a missing version column can never silently bind the 0 sentinel (_version=0 rows lose every ReplacingMergeTree merge - silent row loss). Part of the split of #1353 into independently mergeable sub-PRs (each <= 10 files), so the 2.10.0 branch can absorb the fixes incrementally. * [split 20/22] executor: offset re-insert fix, volatile pause barrier, per-thread cache invalidation generations, schema-cache TTL (#1375) * executor: offset re-insert fix, volatile pause barrier, per-thread cache invalidation generations, schema-cache TTL Wires the new core classes into the batch path. The heart of the race-condition fixes. Merge after config, db-ops, core-classes and batch PRs. - Duplicate-insert fix: an already-flushed batch waiting on offset commit was re-INSERTED on every retry pass (one record observed 1,000 times on the combined PR). A flushed batch now only re-checks committability - never re-inserts. - ClickHouseBatchExecutor.isPaused becomes volatile: it is the DDL-vs-DML barrier, written by the Debezium thread and read in the batch threads' spin loop with no other happens-before edge. Without volatile the read can be hoisted and a batch thread can apply DML against a schema mid-DDL - silent corruption, not a stall. - Cache invalidation by generation: the previous remove-on-read signal let the FIRST worker thread consume the invalidation, leaving every other thread on a stale DbWriter (stale column list) forever. Per-table monotonic generation counters let every thread invalidate independently; plus a schema-cache TTL (default 1h) so a missed DDL self-heals. CacheInvalidationManagerTest / CacheInvalidationManagerTtlTest. - DebeziumOffsetManagement.acknowledgeRecord for the single-record path; beginFlush no longer collides with an in-flight flush (the original OffsetStorageWriter "already flushing" crash from the production log). - Integrity gate + freeze manager + error classifier wired into ClickHouseBatchRunnable / ClickHouseBatchWriter; DbWriter carries the cache generation. Part of the split of #1353 into independently mergeable sub-PRs (each <= 10 files), so the 2.10.0 branch can absorb the fixes incrementally. * [split 21/22] tests: race-condition suites for DDL waiter, offset commit, pause visibility (test-only) (#1376) * tests: race-condition suites for DDL waiter, offset commit, pause visibility (test-only) Test-only. Merge after the executor PR. Multi-threaded race harnesses: concurrent DDL + batch threads against the schema-change waiter (DDLSchemaChangeWaiterRaceConditionTest, DDLFreezeRaceConditionTest), concurrent offset acknowledgement vs flush (OffsetCommitConcurrencyTest), executor pause visibility under the JMM (ExecutorPauseVisibilityTest), and lazy system-connection construction (LazySystemConnectionTest). Split from the executor PR only to respect the 10-file-per-PR limit. Part of the split of #1353 into independently mergeable sub-PRs (each <= 10 files), so the 2.10.0 branch can absorb the fixes incrementally. * lightweight engine: single-threaded DDL pause NPE, snapshot DDL exemption, restart-loop fixes, sequence race (#1377) Final wiring PR for the lightweight connector; merge last. - Single-threaded NPE: in single.threaded mode no batch executor exists, but the DDL branch called executor.pause() unconditionally - NPE on the very first DDL of every run (upstream swallowed it in a log-only catch). Null-safe pause/resume helpers; in single-threaded mode DML is synchronous on the DDL thread, so the no-op is semantically correct. SingleThreadedDdlPauseTest. - Snapshot DDL exemption: the (now actually working) disable.drop.truncate guard suppressed the DROP half of Debezium's snapshot DROP+CREATE replay, so every CREATE hit TABLE_ALREADY_EXISTS in a retry freeze. Snapshot-phase DDL is exempt - its delivery is already governed by enable.snapshot.ddl; streaming DROP/TRUNCATE stays blocked. DropTruncateSnapshotExemptionTest pins all four quadrants. - Restart handling: engine rebuild moved off the callback thread (inline rebuild nested a stack frame per retry); stop() uses shutdownNow(); upstream retry budget restored (11 attempts). DebeziumEngineRestartTest. - Sequence race: out-of-order batches could re-arm the version-counter reset so two rows shared one _version (measured 199/200 duplicates) - the anchor no longer moves backward. SequenceNumberRaceTest. - IgnoreDDLRegexLoader case handling + IgnoreDDLRegexLoaderTest; Version280CompatibilityTest pins the 2.8.0 _version formula byte-for-byte. Part of the split of #1353 into independently mergeable sub-PRs (each <= 10 files), so the 2.10.0 branch can absorb the fixes incrementally. Co-authored-by: minguyen9988 <minguyen9988@users.noreply.github.com> --------- Co-authored-by: minguyen9988 <minguyen9988@users.noreply.github.com> --------- Co-authored-by: minguyen9988 <minguyen9988@users.noreply.github.com> --------- Co-authored-by: minguyen9988 <minguyen9988@users.noreply.github.com> --------- Co-authored-by: minguyen9988 <minguyen9988@users.noreply.github.com> --------- Co-authored-by: minguyen9988 <minguyen9988@users.noreply.github.com> --------- Co-authored-by: minguyen9988 <minguyen9988@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked PR: based on the previous PR in the series (
omniwatcher/split-17-ddl-parser); this PR's own diff is only its listed files. Merge the series in order; after the predecessor merges, retarget this PR to2.10.0.Adds four new core classes with their unit tests. NOT yet referenced by any existing code path - wiring happens in the executor PR - so this PR is behavior-neutral by construction.
Merge order: after the config PR (uses ddl.schema.change.* keys).
Part of the split of #1353 into independently mergeable sub-PRs (each <= 10 files), so the 2.10.0 branch can absorb the fixes incrementally.
Split out of #1353, which this series replaces. Each sub-PR is <= 10 files; the union of all 22 reproduces the #1353 tree exactly (verified by tree SHA).