Skip to content

[Compatibility]: Parenthesized ALTER ADD COLUMN blocks Debezium JDBC schema evolution #29851

Closed

Description

@dengn

测试条件

  • 日期:2026-10-11;Debian13 / Linux x86_64;本地独立 standalone MatrixOne(1 CN / 1 TN / 1 LogService)。
  • 实际运行 SHA:652c643666428f1c434e03369834f2a9bead7c27;并未在最新 main 重新部署,验收需记录新的 SHA。本 issue 涉及路径未额外做最新 main 全链路 parity 核对。
  • 对照:真实 MySQL8.4.11,PyMySQL1.2.3;本地独立 synthetic database,非业务数据。
  • 本轮为完整工具进程与数据链路的正确性诊断,没有做长稳、吞吐或 exactly-once 认证。
  • 以下SQL最小用例已在两个数据库实跑;本地 receipt 是证据来源名称,不是公开附件下载地址。

完整运行链路与触发

MySQL8.4.11 ROW/FULL binlog→Kafka3.9.1 KRaft→Connectdistributed worker→DebeziumMySQLsource3.1.2.Final→DebeziumJDBCsink3.1.2.Final→MO。sink使用schema.evolution=basic、PKupsert和delete.enabled=true,source使用adaptive_time_microseconds。

宽类型快照、insert/update/物理delete、微秒读回已通过。源执行新增nullable列并更新后,sink自动发出的语句为:

ALTER TABLE kc_exact_records ADD COLUMN ( added_tag longtext NULL)

MO报1064语法错误,sink task FAILED,source仍RUNNING。仅看connector顶层状态会漏掉实际task失败。已有目标行仍存在,但新列/后续变更无法消费。

实跑最小SQL

MO与真实MySQL8.4.11分别运行:

CREATE TABLE probe_add(id INT);
ALTER TABLE probe_add ADD COLUMN (added_tag LONGTEXT NULL);

MySQL接受;MO报1064,错误位置在(added_tag LONGTEXT NULL)。没有其他FK/index/copy-mode条件。

原始过程、适配与恢复

  1. 三行宽类型源表:INT64/UINT64、大decimal、binary、中文emoji、DATETIME6微秒、JSON、NULL。
  2. snapshot精确;更新/新增/删除也精确。
  3. source ALTER TABLE records ADD COLUMN added_tag VARCHAR(100) NULL,随后更新id1新列为中文;自动schema evolution失败,source/sink逐字段比对失败。
  4. 手工在MO使用无括号ALTER TABLE kc_exact_records ADD COLUMN added_tag LONGTEXT NULL,restart failed sink task。
  5. 同一offset/config/status Kafka topics保留;worker停止期间继续source update/delete/insert,再重启worker,原checkpoint补追并收敛,PK总数=去重数。

步骤4是明确的DDL适配,不能据此宣称自动evolution原路径通过。本轮worker恢复是有序stop/restart,未认证SIGKILL/系统断电/跨系统exactly-once。

预期与验收

  • 支持MySQL合法的括号列定义列表,单列/多列、nullable/default/不同类型分别覆盖。
  • 原DebeziumJDBC basic evolution无需手工DDL即可新增列、消费新字段并保持旧行。
  • 保存connector与task状态、精确SQL/error、源目标schema和值;恢复后检查checkpoint/重复/漏行。
  • 列重命名、删除和类型变更按独立支持契约验证;basic ADD通过不能推出DROP/RENAME支持。

关联与区别

  • #29848 本轮完整运行与恢复认证;#27746 既有MySQL生态/Flink资格认证。
  • #28052 COPY ALTER组合ADD COLUMN/INDEX问题;#28995 ADD COLUMN/FK组合问题;这里仅单列括号语法,不依赖组合DDL。

原始receipt:kafka-runtime-result.json、runtime-minimal-sql-result.json、connector failure trace。

2026-10-11 第二轮:源列RENAME也触发同一ADD语法阻塞

实际SHA/版本与本文相同,独立 rt2_kafka.ren 源目标表预建为:

CREATE TABLE ren(
 id INT PRIMARY KEY,v VARCHAR(10),n SMALLINT,
 nullable VARCHAR(10),dropped VARCHAR(10)
);
INSERT INTO ren VALUES(1,'short',30000,NULL,'old');
-- 仅在MySQL源执行:
ALTER TABLE ren RENAME COLUMN v TO renamed_v;
UPDATE ren SET renamed_v='renamed' WHERE id=1;

Debezium JDBC3.1.2.Final、schema.evolution=basic,将新字段当作新增字段,向MO发出括号ADD COLUMN;目标仍有旧v字段,sink task FAILED。这个场景仍是本文已报的ADD语法条件,不能据此宣称连接器支持自动rename。

直接在MO执行 ALTER TABLE ren RENAME COLUMN v TO renamed_v 成功;显式同步目标模式,再restart/resume sink后,源目标值精确一致。本轮直接RENAME/DROP/MODIFY/NOT NULL/default均有真实MySQL8.4.11语义对照。其他模式边界:DROP保留旧目标字段、widen未扩型而被明确越界拒绝、nullable/default模式约束未传播,均详见#29848第二轮结果,避免将工具basic模式边界混成原生DDL缺陷。

第二轮还实际SIGKILL了worker、broker、MO目标进程:worker恢复通过;broker在默认300000ms重平衡等待后追平;MO和独立MySQL目标中断后,JDBC task均需显式restart才能补追。上述是#29848恢复profile证据,不是该ADD语法修复的验收替代。

receipt:kafka-expanded-result.json SHA256 7ea6bd2d1e30f01c345969986ee74115acd3bf2b1ab53a40d41a8519ebb2bcd5(本地证据名称,不是公开下载链接)。

Activity

  1. slyunnn commented on Oct 15, 2026

    @slyunnn
    Collaborator

    Regression and extended verification for #29851 (2026-10-15)

    Verification Environment

    • MatrixOne origin/main: eb18dbfa030b6309c5f5d0c2d5e7078a1466ac7f — fix(sql): preserve TIME fractional precision in ADDTIME and SUBTIME (#30264). A clean worktree at this commit produced image sha256:38849efac9b0ce44f954e01e299139af795bd00a32f5c2afc772725d06ef5854, used by all 5 MatrixOne containers. The detached-worktree Docker build reports git_version() as unknown; source commit, image ID, and running-container image IDs were checked instead.
    • MatrixOne topology: 2 CN / 1 TN / 1 Log service / Proxy. Proxy 6001, CN1 16001, and CN2 16002 were reachable. The original SQL was executed separately on all 3 endpoints via the MySQL text protocol; the JDBC sink connected through Proxy 6001 via Connector/J 9.1.0.
    • CDC topology: MySQL 8.4.11 with ROW/FULL binlog → Kafka 3.9.0 KRaft → Kafka Connect distributed-mode worker → Debezium MySQL source 3.1.2.Final → Debezium JDBC sink 3.1.2.Final → MatrixOne. Synthetic, isolated databases and a fresh Kafka topic/offset store were used.
    • Associated fix: PR #29963, merge commit fcad62a8ff06000e682824802f1155cbeea02a2f — fix(frontend): accept parenthesized ALTER ADD COLUMN lists.

    What Was Covered

    • OK — The original ALTER TABLE probe_add ADD COLUMN (added_tag LONGTEXT NULL) and row readback passed independently through Proxy, CN1, and CN2. MySQL 8.4.11 accepted the same syntax.
    • OK — Without manually creating or altering the target table, the sink completed the initial snapshot, then automatically added added_tag after source ALTER TABLE records ADD COLUMN added_tag VARCHAR(100) NULL. Existing and new rows retained the expected NULL/Chinese values.
    • OK — A repeated nullable-column evolution succeeded. Sink TRACE recorded the actual generated statement: ALTER TABLE records ADD COLUMN ( documented_tag longtext NULL); the new column and value appeared in MatrixOne.
    • OK — While the Connect worker was stopped, the source performed UPDATE, physical DELETE, and INSERT. After restarting the same worker, source/target rows converged; target COUNT(*)=COUNT(DISTINCT id)=2. Source and sink connector/task states were RUNNING, and both had committed offsets.
    • OK — The committed MOTR SQL case passed on this main commit: 1/1 case and 22/22 statements. It covers the original syntax, multi-column/default cases, empty-table and scalar controls, duplicate-column 1060, empty-list 1064, and unchanged data after errors.
    • Not covered — The exact original Kafka 3.9.1 patch version, a multi-worker Connect deployment, the wider type/microsecond dataset, long-duration throughput or exactly-once certification, and unrelated RENAME/DROP/type-change evolution modes.

    Findings

    The earlier fresh-run failure was a test-environment metadata collision, not a MatrixOne parser regression: several isolated databases reused a table named records. Debezium's metadata lookup encountered a same-named table outside the intended target database. Scoping Connector/J metadata to the current database with nullDatabaseMeansCurrent=true made automatic table creation and column evolution work without target-side DDL. This option's metadata behavior is documented by MySQL Connector/J; Debezium documents schema.evolution=basic as automatic table creation and missing-column addition in its JDBC sink documentation.

    Large-data regression is not needed for this parser-compatibility defect: acceptance does not depend on row count, block/batch boundaries, memory/spill, data skew, or engine worker count. The minimal snapshot-plus-change sequence crosses the relevant connector schema boundary.

    MOTR / BVT Coverage

    • Independent MOTR commit: a158d450c93d78eb1b031fd94fb1a524f9cb4b49, pushed on test/issue-29851-parenthesized-add-column.
    • Daily cherry-pick: b5d4d6635c757b34dabf582a9ef414f18f2b3787 in MOTR PR #242. The .test and .result were recorded and replayed successfully; a focused 4-case neighboring-ALTER replay passed 112/112 statements. MOTR -j 4 is case scheduling, not MatrixOne engine parallelism.
    • No MatrixOne service source files were modified. The external Kafka/Connect scenario was executed manually and is not part of MOTR CI.

    Final Conclusion

    Fixed. On the verified main commit eb18dbfa030b6309c5f5d0c2d5e7078a1466ac7f, both the original parenthesized SQL and the real Debezium JDBC automatic-add-column flow passed, including worker restart and catch-up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions