Skip to content

Tap 12846 query timeout - #975

Open
jarad0628 wants to merge 16 commits into
developfrom
TAP-12846-query-timeout
Open

jarad0628 wants to merge 16 commits into
developfrom
TAP-12846-query-timeout

Conversation

@jarad0628

Copy link
Copy Markdown
Collaborator

No description provided.

- GROUP BY keys normalize -0.0 to 0.0 so both zeros share one group
- ORDER BY comparison collapses signed zeros, matching the documented total order
- add maxBufferedRows (default 100000) so ordered queries fail instead of buffering unlimited rows
- update en/zh_CN/zh_TW docs and add regression tests
- Bound materialized groups for GROUP BY ... ORDER BY by maxBufferedRows, and
  cover the gap with a regression test that previously returned rows silently.
- Report fractional or out-of-range integer literals as "not representable as
  <type>" instead of wrapping them in "invalid SELECT syntax"; drop the now
  unreachable Double/DECIMAL literal branches and assert the message in tests.
- Normalize signed zeros for grouped float columns so the displayed sign does
  not depend on scan order; reject ORDER BY references to another table.
- Sample the sort deadline (first comparison, then every 1024) instead of
  reading the clock on every comparison, and stop pinning the tick count.
- Cache execute-override detection per class, ignore private/bridge methods,
  and fail with a clear error when the legacy overload delegates back instead
  of overflowing the stack.
- Keep the deprecated SqlExecuteCommandFunction path on the streaming path so
  queryTimeoutSeconds is no longer silently dropped.
- Compile production code with <release>8</release> (testRelease 11) so Java 9+
  APIs fail at build time.
- Document the MySQL streaming timeout scope, ordered aggregate buffering and
  integer literal rules in all three languages; fix the stale "write only"
  limitation and the incomplete zh_CN timeout range; move PaimonService
  construction inside the integration test's try block.
@jarad0628

Copy link
Copy Markdown
Collaborator Author

AI PR Review — ✅ 可通行

  • PR: #975
  • Head: efcc6a520dd601d4409a76adaa4b4aaf15bf2463
  • Reviewers: codexcli, claudecli, reasonix

最终总结

最终评审结论

评审覆盖情况

评审者 覆盖范围 结论
codexcli part 1 + part 2 PASS
claudecli part 2(docs/spec/测试) PASS(claudecli 的 part 1 因网关 503 未产生输出)
我的独立复核 part 1(sql-core / mysql)+ 关键 Paimon 实现 未发现实质缺陷

由于 claudecli 的 part 1 缺失,part 1 只有单一评审覆盖,因此我独立核对了这一片的代码并做了构建/测试验证,而不是直接采信 codexcli 的 PASS:

  • connectors-common/sql-core、connectors/paimon-plus-connector 主代码与测试代码均离线编译通过(mvn -o -pl ... -am test-compile,BUILD SUCCESS)。
  • SqlCommandTimeoutTest 13/13 通过;PaimonQueryPlanTest + PaimonSqlQueryParserTest + PaimonServiceExecuteQueryIntegrationTest 33/33 通过;MysqlConnectorTest 7/7 通过(真实 Paimon 临时 warehouse,含 UTC/Asia/Shanghai/America/Los_Angeles 三个时区参数化)。
  • 逐点核对:SqlCommandParams 的 batchSize/timeout 解析(全整数、范围、四舍五入拒绝);JdbcQueryExecutor 的 setQueryTimeout → SQLFeatureNotSupportedException 显式失败路径、fetchSize 保留(MySQL 仍是 Integer.MIN_VALUE 流式读取)、仅在非 autocommit 时 commit;CommonDbConnector 的 ClassValue 覆写探测与 ThreadLocal 防递归(现有仓库内唯一 3 参覆写方 MysqlConnector 同时覆写了 4 参重载,因此不会进入 legacy 委派分支,也不会抛 UnsupportedOperationException);Paimon 侧 putIfAbsent 使命令参数优先于连接配置 queryAllowFullScan(默认 true,getter 对 null 视为 true,与 spec.json 和文档一致);forLegacyQuery() 保留原 started/timeoutNanos,只放开 maxScanRows/maxGroups 默认上限,符合“历史 SELECT */COUNT(1) 不受新默认上限约束但仍受显式上限约束”;排序比较器对 signed zero/NaN 的排序语义、nullsFirst 默认(ASC→FIRST)与文档一致;流式批次与空结果回调逻辑、以及回调抛异常后释放 ingress/reader(集成测试已验证 row 1001 停止后可继续下一次查询)。

处置说明

  • 无 P0/P1/高 级主张需要驳回(两位评审均未提出)。
  • 无 P2 需要单独豁免或自行确立:唯一被提及的问题是 zh_CN 参数表 maxScanRows/maxGroups 默认值未带“对新查询”限定(en_US/zh_TW 有)。这是纯文档措辞、无行为影响,属低级别,按收敛策略抑制,不作为 BLOCK 依据,也不会转成行内评论或修复任务。

下一步:无阻塞项,可以合并。若要收尾,唯一可选动作是把 zh_CN 表格默认值补上“(对新建查询)”,属可选跟进,不需要在本 PR 阻塞。

FINAL_VERDICT: PASS

===FINDINGS===
===END===

codexcli (part 1/2) review

No actionable defects found in part 1. I reviewed the changed files and hunks; no tests were run.

VERDICT: PASS

codexcli (part 2/2) review

No actionable defects found in part 2’s documentation, configuration schema, or tests.

VERDICT: PASS

claudecli (part 2/2) review

I reviewed every hunk in part 2: the Paimon docs in en_US, zh_CN and zh_TW, spec.json, the three Paimon test files and the Postgres docs. I found no medium-or-higher defects. This was a read-only review and I ran no tests.

  • queryAllowFullScan setting: the new switch in spec.json defaults to true, and so does PaimonConfig.java:108. The getter treats a null value as true. PaimonService.java:3141 and PaimonService.java:3154 use putIfAbsent, so a command's allowFullScan overrides the connection setting. That matches what the docs say.
  • Default limits: the documented defaults (10,000,000 for maxScanRows, 100,000 for maxGroups, uncapped for older SELECT */COUNT(1) queries, and 100,000 for maxBufferedRows in all cases) match PaimonQueryLimits.java:26-54. The test that checks the older-query defaults asserts the same values.
  • Postgres docs: PostgresConnector extends CommonDbConnector, so the documented batchSize and queryTimeoutSeconds behaviour comes from SqlCommandParams and JdbcQueryExecutor. That code does what the docs claim:
    • batchSize zero or negative falls back to 1000, and a non-whole or overflowing value is rejected.
    • queryTimeoutSeconds accepts 0 to 2147483647 and rejects negative, fractional and overflowing values.
    • If the driver can't enforce the timeout, the command fails with a SQLFeatureNotSupportedException explaining why.
  • Tests:
    • The new test classes cover the limit checks, the time limit (using an injected clock), signed zeros and NaN, sort order, ordered aggregates hitting maxBufferedRows, and a callback error stopping the stream.
    • The timestamp() fixture helper now builds UTC epoch values, so results no longer change with the JVM time zone. The tests that set the default time zone restore it in finally.
    • Renaming the test table to DRSRedemptions is safe because each test uses a fresh @TempDir warehouse.

One minor wording gap, which doesn't block: in the zh_CN parameter table the maxScanRows and maxGroups defaults leave out "for new queries", which the en_US and zh_TW tables include.

VERDICT: PASS

reasonix review

最终评审结论

评审覆盖情况

评审者 覆盖范围 结论
codexcli part 1 + part 2 PASS
claudecli part 2(docs/spec/测试) PASS(claudecli 的 part 1 因网关 503 未产生输出)
我的独立复核 part 1(sql-core / mysql)+ 关键 Paimon 实现 未发现实质缺陷

由于 claudecli 的 part 1 缺失,part 1 只有单一评审覆盖,因此我独立核对了这一片的代码并做了构建/测试验证,而不是直接采信 codexcli 的 PASS:

  • connectors-common/sql-core、connectors/paimon-plus-connector 主代码与测试代码均离线编译通过(mvn -o -pl ... -am test-compile,BUILD SUCCESS)。
  • SqlCommandTimeoutTest 13/13 通过;PaimonQueryPlanTest + PaimonSqlQueryParserTest + PaimonServiceExecuteQueryIntegrationTest 33/33 通过;MysqlConnectorTest 7/7 通过(真实 Paimon 临时 warehouse,含 UTC/Asia/Shanghai/America/Los_Angeles 三个时区参数化)。
  • 逐点核对:SqlCommandParams 的 batchSize/timeout 解析(全整数、范围、四舍五入拒绝);JdbcQueryExecutor 的 setQueryTimeout → SQLFeatureNotSupportedException 显式失败路径、fetchSize 保留(MySQL 仍是 Integer.MIN_VALUE 流式读取)、仅在非 autocommit 时 commit;CommonDbConnector 的 ClassValue 覆写探测与 ThreadLocal 防递归(现有仓库内唯一 3 参覆写方 MysqlConnector 同时覆写了 4 参重载,因此不会进入 legacy 委派分支,也不会抛 UnsupportedOperationException);Paimon 侧 putIfAbsent 使命令参数优先于连接配置 queryAllowFullScan(默认 true,getter 对 null 视为 true,与 spec.json 和文档一致);forLegacyQuery() 保留原 started/timeoutNanos,只放开 maxScanRows/maxGroups 默认上限,符合“历史 SELECT */COUNT(1) 不受新默认上限约束但仍受显式上限约束”;排序比较器对 signed zero/NaN 的排序语义、nullsFirst 默认(ASC→FIRST)与文档一致;流式批次与空结果回调逻辑、以及回调抛异常后释放 ingress/reader(集成测试已验证 row 1001 停止后可继续下一次查询)。

处置说明

  • 无 P0/P1/高 级主张需要驳回(两位评审均未提出)。
  • 无 P2 需要单独豁免或自行确立:唯一被提及的问题是 zh_CN 参数表 maxScanRows/maxGroups 默认值未带“对新查询”限定(en_US/zh_TW 有)。这是纯文档措辞、无行为影响,属低级别,按收敛策略抑制,不作为 BLOCK 依据,也不会转成行内评论或修复任务。

下一步:无阻塞项,可以合并。若要收尾,唯一可选动作是把 zh_CN 表格默认值补上“(对新建查询)”,属可选跟进,不需要在本 PR 阻塞。

FINAL_VERDICT: PASS

===FINDINGS===
===END===

标记:✅ 可通行

@jarad0628

Copy link
Copy Markdown
Collaborator Author

AI PR Review — ✅ 可通行

  • PR: #975
  • Head: d29f00c59860ef0252e20c297447bdf472f24282
  • Reviewers: codexcli, claudecli, reasonix

最终总结

本轮评审总结

增量范围确认(efcc6a52..d29f00c5):仅 connectors/mysql-connector/src/main/java/io/tapdata/connector/mysql/MysqlConnector.java,2 行改动(+2/-2)。

历史发现状态:上一轮评审(head efcc6a52)结案时无任何 finding,故无 已修复/仍存在/部分修复 逐条状态可列;此前的 P3 级噪声(命名/文档措辞类)按策略统一抑制,不再重述。

代码核验(我自己在 checkout 中执行,而非仅采信 reviewer):

  • git diff efcc6a52..HEAD 确认改动仅是把私有 helper 由 createCallableStatement 重命名为 createMysqlCallableStatement,方法体字节级未变。
  • 全仓 grep -rn createCallableStatement --include=*.java:仅剩 CommonDbConnector.java:1227/1239 与 DefaultSqlExecutor.java:111/123 两处同名方法,均属其它类自己的私有方法,与本次重命名无冲突;MysqlConnector 内调用点(1248)与声明点(1261)已同步为新名,无残留旧引用。
  • 方法为 private,九个继承 MysqlConnector 的子连接器不可见,不存在子类调用点或覆写语义被破坏;无反射/测试引用(grep 全仓无其它命中)。
  • Sonar 告警("与父类私有方法同名")根因即与 CommonDbConnector:1239 撞名,重命名后该根因消除。

评审者一致性:codexcli 与 claudecli 两位独立 reviewer 均给出 PASS,结论与我的代码核验一致,无分歧需调和;无人类新评论待回应。

P2 豁免说明:本轮无任何 reviewer 上报 P2,无需豁免。P0/P1 复核:无 reviewer 提出高severity 主张,故无可驳回或需阻塞项。

唯一待外部确认项(非阻塞):重命名是否真正清除 Sonar 质量门禁告警,需等本次 CI 扫描结果;这属于流水线验证,不构成本 PR 的代码缺陷。

下一步:无需修复动作。合并前仅需等 CI 扫描确认 Quality Gate 通过即可。

FINAL_VERDICT: PASS

===FINDINGS===
===END===

codexcli review

No historical findings to re-verify. The incremental diff only renames the private helper and updates its call site; both references match. No human comments were provided.

VERDICT: PASS

claudecli review

I found no defects in this round. There were no earlier findings to re-check and no new human comments to answer.

This round's diff, from efcc6a52 to d29f00c5, touches only MysqlConnector.java. It renames the private helper createCallableStatement to createMysqlCallableStatement and updates its single call site at connectors/mysql-connector/src/main/java/io/tapdata/connector/mysql/MysqlConnector.java:1248. The new declaration is at line 1261. The method body is unchanged.

  • Nothing still uses the old name: within mysql-connector, both references use the new name. The createCallableStatement in CommonDbConnector.java:1239 and DefaultSqlExecutor.java:123 belongs to those classes, not to MySQL.
  • Sonar warning: the MySQL method was flagged for having the same name as a private method in its parent class, CommonDbConnector. That class has no createMysqlCallableStatement, so the rename removes the name clash.
  • Subclasses: nine connectors extend MysqlConnector (MariaDB, PXC, OceanBase, Aliyun/AWS/Tencent RDS, PolarDB, and others). The method is private, so none of them can call it and none of them break.
  • Tests: no test file calls createCallableStatement, including by reflection, so no fixture breaks.
  • Build files, APIs and concurrency: no build files changed, no new APIs are used, and the rename doesn't affect concurrency.

I didn't compile the code or run tests; this was a read-only review.

VERDICT: PASS

reasonix review

本轮评审总结

增量范围确认(efcc6a52..d29f00c5):仅 connectors/mysql-connector/src/main/java/io/tapdata/connector/mysql/MysqlConnector.java,2 行改动(+2/-2)。

历史发现状态:上一轮评审(head efcc6a52)结案时无任何 finding,故无 已修复/仍存在/部分修复 逐条状态可列;此前的 P3 级噪声(命名/文档措辞类)按策略统一抑制,不再重述。

代码核验(我自己在 checkout 中执行,而非仅采信 reviewer):

  • git diff efcc6a52..HEAD 确认改动仅是把私有 helper 由 createCallableStatement 重命名为 createMysqlCallableStatement,方法体字节级未变。
  • 全仓 grep -rn createCallableStatement --include=*.java:仅剩 CommonDbConnector.java:1227/1239 与 DefaultSqlExecutor.java:111/123 两处同名方法,均属其它类自己的私有方法,与本次重命名无冲突;MysqlConnector 内调用点(1248)与声明点(1261)已同步为新名,无残留旧引用。
  • 方法为 private,九个继承 MysqlConnector 的子连接器不可见,不存在子类调用点或覆写语义被破坏;无反射/测试引用(grep 全仓无其它命中)。
  • Sonar 告警("与父类私有方法同名")根因即与 CommonDbConnector:1239 撞名,重命名后该根因消除。

评审者一致性:codexcli 与 claudecli 两位独立 reviewer 均给出 PASS,结论与我的代码核验一致,无分歧需调和;无人类新评论待回应。

P2 豁免说明:本轮无任何 reviewer 上报 P2,无需豁免。P0/P1 复核:无 reviewer 提出高severity 主张,故无可驳回或需阻塞项。

唯一待外部确认项(非阻塞):重命名是否真正清除 Sonar 质量门禁告警,需等本次 CI 扫描结果;这属于流水线验证,不构成本 PR 的代码缺陷。

下一步:无需修复动作。合并前仅需等 CI 扫描确认 Quality Gate 通过即可。

FINAL_VERDICT: PASS

===FINDINGS===
===END===

标记:✅ 可通行

SonarQube quality gate on TAP-12846-query-timeout fails on
new_maintainability_rating (actual D/4.0, required A), 17 code smells /
79min technical debt, all in MysqlConnector.java:

- java:S1161 (x9): add @OverRide to methods that override CommonDbConnector
  (batchReadWithoutHashSplit, clearTable, dropTable, createConstraint,
  makeTapIndex, getCreateIndexSql, getAfterUniqueAutoIncrementFields,
  call, getOutputFromCall).
- java:S5411 (x6): replace boxed Boolean conditions with Boolean.TRUE.equals
  (oldVersionTimezone x2, highPerformance x3, createAutoInc).
- java:S1155 (x2): use isEmpty() instead of size() >= 1.

No behaviour change intended.
@jarad0628

Copy link
Copy Markdown
Collaborator Author

AI PR Review — ✅ 可通行

  • PR: #975
  • Head: f5dd4db8583a67e54ffb9095073130adc1cde6e4
  • Reviewers: codexcli, claudecli, reasonix

最终总结

最终评审结论

评审覆盖情况

评审者 覆盖范围 结论
codexcli 增量 d29f00c5..f5dd4db8 PASS
claudecli 增量 d29f00c5..f5dd4db8(逐 hunk + head f5dd4db8 交叉核对) PASS

历史发现状态:上一轮(head d29f00c5)接受 0 条发现,无历史遗留项需要标 已修复/仍存在/部分修复。上一轮未产生被抑制的 P3 清单(无),因此无需分组处理。

本轮增量(仅 MysqlConnector.java,+17/−8)我独立复核的结论

  • 9 处 @Override:逐个与父类 CommonDbConnector 声明比对,签名与可见性完全一致 —— clearTable:402、dropTable:412、createConstraint:503、makeTapIndex:545、getCreateIndexSql:685、batchReadWithoutHashSplit:765、getAfterUniqueAutoIncrementFields:1118、call:1216、getOutputFromCall:1319,MysqlConnector 确实 extends CommonDbConnector(第 88 行)。属编译期可校验的纯注解,不改字节码;本地 mvn test(mysql-connector,21/21 通过)已验证其可编译性。
  • 6 处 Boolean.TRUE.equals(...):getOldVersionTimezone、getHighPerformance、getCreateAutoInc 三个 getter 均声明为 Boolean(MysqlConfig.java:207、CommonDbConfig.java:328)。true/false 分支行为不变,唯一差别是 null 从抛 NPE 变为走 false 分支(getAfterUniqueAutoIncrementFields 返回空列表)—— 更安全的降级,非缺陷。
  • 2 处 size() >= 1 → !isEmpty():queryAllTables 返回 List,语义等价。

P0/P1:两位评审均无高/严重发现,我复核后也确认增量无高危输入(无并发、无公共 API 签名变更、无构建/JDK 兼容性影响),无需要驳回的误报。P2:无单一评审上报的 P2,故无豁免事项。

下一步:无需代码改动。合并前仅剩 CI 的 Sonar Quality Gate 复核(本轮提交的目的即清零 New Code 债务 new_maintainability_rating,需等 Scan-Connectors 扫描结果确认)。

FINAL_VERDICT: PASS

===FINDINGS===
===END===

codexcli review

本轮增量只改动了 MysqlConnector.java。前一轮没有遗留发现;本轮检查未发现新增的可操作缺陷。布尔值改为 Boolean.TRUE.equals(...) 可避免这些条件处的空值拆箱异常,新增的 @Override 也与父类方法签名相符。未运行测试。

VERDICT: PASS

claudecli review

I found no defects in this round. There were no earlier findings to re-check and no new human comments to answer.

I reviewed the incremental diff d29f00c5..f5dd4db8, which only touches MysqlConnector.java, against the head checkout at f5dd4db8:

  • 9 new @Override annotations: each matches a method in CommonDbConnector with the same signature and visibility (lines 402, 412, 503, 545, 685, 765, 1118, 1216 and 1319). The compiler checks them, and they don't change the bytecode the subclasses rely on. Those subclasses are MariadbConnector, OceanbaseConnector, the RDS, PolarDB and PXC connectors, and others.
  • 6 Boolean.TRUE.equals(...) changes (getOldVersionTimezone, getHighPerformance, getCreateAutoInc): all three getters return a Boolean that defaults to false (CommonDbConfig.java:50-51, MysqlConfig.java:165). For true and false, behavior is the same as before. The only difference is that a null value now counts as false instead of throwing a NullPointerException. In getAfterUniqueAutoIncrementFields, !Boolean.TRUE.equals(null) returns an empty list, which is the safe outcome.
  • 2 size() >= 1 → !isEmpty() changes (clearTable and dropTable): the result is the same, since queryAllTables returns a list.

Nothing here affects concurrency, the public API, the build or JDK compatibility. The PR doesn't add tests for these lines, which is acceptable because they don't change behavior for valid configurations. This was a read-only review: I didn't compile the code or run tests.

VERDICT: PASS

reasonix review

最终评审结论

评审覆盖情况

评审者 覆盖范围 结论
codexcli 增量 d29f00c5..f5dd4db8 PASS
claudecli 增量 d29f00c5..f5dd4db8(逐 hunk + head f5dd4db8 交叉核对) PASS

历史发现状态:上一轮(head d29f00c5)接受 0 条发现,无历史遗留项需要标 已修复/仍存在/部分修复。上一轮未产生被抑制的 P3 清单(无),因此无需分组处理。

本轮增量(仅 MysqlConnector.java,+17/−8)我独立复核的结论

  • 9 处 @Override:逐个与父类 CommonDbConnector 声明比对,签名与可见性完全一致 —— clearTable:402、dropTable:412、createConstraint:503、makeTapIndex:545、getCreateIndexSql:685、batchReadWithoutHashSplit:765、getAfterUniqueAutoIncrementFields:1118、call:1216、getOutputFromCall:1319,MysqlConnector 确实 extends CommonDbConnector(第 88 行)。属编译期可校验的纯注解,不改字节码;本地 mvn test(mysql-connector,21/21 通过)已验证其可编译性。
  • 6 处 Boolean.TRUE.equals(...):getOldVersionTimezone、getHighPerformance、getCreateAutoInc 三个 getter 均声明为 Boolean(MysqlConfig.java:207、CommonDbConfig.java:328)。true/false 分支行为不变,唯一差别是 null 从抛 NPE 变为走 false 分支(getAfterUniqueAutoIncrementFields 返回空列表)—— 更安全的降级,非缺陷。
  • 2 处 size() >= 1 → !isEmpty():queryAllTables 返回 List,语义等价。

P0/P1:两位评审均无高/严重发现,我复核后也确认增量无高危输入(无并发、无公共 API 签名变更、无构建/JDK 兼容性影响),无需要驳回的误报。P2:无单一评审上报的 P2,故无豁免事项。

下一步:无需代码改动。合并前仅剩 CI 的 Sonar Quality Gate 复核(本轮提交的目的即清零 New Code 债务 new_maintainability_rating,需等 Scan-Connectors 扫描结果确认)。

FINAL_VERDICT: PASS

===FINDINGS===
===END===

标记:✅ 可通行

…ctors

- csv-connector: enable jacoco prepare-agent/report like the other connector
  modules. Without the agent SonarQube recorded 0% coverage for every csv
  file (CsvConnector 217/217 and CsvValueConverter 166/166 uncovered).
- CsvValueConverterTest: assert wall-clock DATETIME parsing for both the
  determineDateFormat and FLEXIBLE_DATETIME paths (New Code lines 184/206).
- MysqlConnectorTest: add NewCodeCoverageTest covering clearTable, dropTable,
  getAfterUniqueAutoIncrementFields, call, streamRead,
  streamReadMultiConnection and both timestampToStreamOffset branches.
@jarad0628

Copy link
Copy Markdown
Collaborator Author

AI PR Review — ✅ 可通行

  • PR: #975
  • Head: 3aa837ef7b3ea54cd29f36c74de79ef27efe77f5
  • Reviewers: codexcli, claudecli, reasonix

最终总结

最终评审结论

评审范围:增量 f5dd4db8..3aa837ef,共 3 个文件、+218/−0(connectors/csv-connector/pom.xml、CsvValueConverterTest、MysqlConnectorTest),无生产代码改动。

历史发现状态:上一轮(head f5dd4db8)接受 0 条发现,因此没有需要标注 已修复 / 仍存在 / 部分修复 的条目;也没有历史 P3 分组需要抑制。上一轮已讨论过的既有行为(streamReadMultiConnection 的 highPerformance 分支没有提前 return,会再走一次 debezium binlog)依然存在于 origin/develop(0879afe9),本 PR 未改动它,属于既有行为,本轮新增测试只是把它固定下来,因此不作为本轮发现,也不阻塞。

本轮我独立复核的结论

  • csv-connector/pom.xml 新增 jacoco:与 connectors/mysql-connector/pom.xml:276-295 等模块的写法逐行一致,版本继承父 connectors/pom.xml:283-287 的 0.8.12(非 SNAPSHOT),prepare-agent + report(test) 两个 execution,本模块无重复声明。父 POM 的 JDK 9+ profile 通过 @{argLine} 把 agent 传给 surefire,本地实跑已确认生效。
  • 实测(离线 Maven,-pl connectors/csv-connector,connectors/mysql-connector test):MysqlConnectorTest 28 + MysqlDataTypeMappingTest 1 全绿;CsvConnectorTest 24 + CsvValueConverterTest 6 全绿;BUILD SUCCESS。新增 NewCodeCoverageTest 全部通过,说明其 mock/stub 与被测代码签名(clearTable/dropTable/getAfterUniqueAutoIncrementFields/call/streamRead/streamReadMultiConnection/timestampToStreamOffset)一致,times(2).setFetchSize(Integer.MIN_VALUE)(MysqlConnector.java:1260 + :1290)、{call demo_proc()}、ALTER TABLE ... AUTO_INCREMENT 等断言均与 main 代码吻合。
  • CsvValueConverterTest 新增用例:两条断言分别命中 determineDateFormat 与 FLEXIBLE_DATETIME 分支,均返回 LocalDateTime 墙钟值(CsvValueConverter.java:169-207),不依赖默认时区;LocalDateTime 在 JDK 8 可用(模块 java.version=8)。
  • 覆盖率产物实测:connectors/csv-connector/target/jacoco.exec 与 target/site/jacoco/jacoco.xml 已生成,CsvValueConverter.java 统计为 LINE 149 covered / 0 missed,证明该模块此前缺失的覆盖率数据现在能提供给 Sonar 读取,方向正确。

一致性与 P2 豁免:两位独立评审(codexcli、claudecli)均为 PASS,无高/中危发现,也就不存在单一评审上报的 P2 需要豁免或独立证实。我复核后同样没有发现新增缺陷:本轮改动不触碰生产逻辑、公共 API、并发或 JDK 兼容性,故无 P0/P1 可驳回项,也没有需要保留的 P2。

下一步:无需代码改动。剩余唯一动作是等 Scan-Connectors 的 Sonar Quality Gate 复算 New Code Coverage(MysqlConnector.java、CsvValueConverter.java)——这依赖外部 CI,不是本 PR 的代码问题。

FINAL_VERDICT: PASS

===FINDINGS===
===END===

codexcli review

No historical findings were recorded in the previous review. I found no actionable defects in the three files changed since that review. The JaCoCo executions match the connector’s existing setup, and the added tests introduce no apparent compatibility or correctness issue.

I did not run tests; this was a read-only review.

VERDICT: PASS

claudecli review

I found no defects in this round. The previous review had no findings to re-check, and there are no new human comments to answer.

This round (f5dd4db8..3aa837ef) changes only tests and build config. No production code is touched. I checked the changes against the head checkout at 3aa837ef:

  • connectors/csv-connector/pom.xml: the new jacoco-maven-plugin takes its version from the parent connectors/pom.xml:283-287 (0.8.12, not a SNAPSHOT). It isn't declared twice in this module, and the report goal runs in the test phase, as in other modules. The parent's JDK 9+ profile passes @{argLine} to surefire, so the agent set up by prepare-agent reaches the tests. Failsafe's own argLine drops the agent, but integration tests are skipped (skipITs=true), so coverage isn't affected.
  • CsvValueConverterTest: the new datetime test exercises the two parse paths for times without a zone: one falls through to determineDateFormat, the other matches FLEXIBLE_DATETIME and returns a LocalDateTime. The assertions can fail, and LocalDateTime exists in JDK 8, which this module targets.
  • MysqlConnectorTest.NewCodeCoverageTest: each stubbed or verified path matches the code at head:
    • Stream reads (streamRead at line 888, streamReadMultiConnection at line 899): both the high-performance and binlog branches are exercised.
    • timestampToStreamOffset (line 944): both the high-performance and plain-timestamp results are covered.
    • call: setFetchSize is expected twice. That matches the code: call sets it once at line 1260, and the test's comment says createMysqlCallableStatement sets it too.
    • mockConstruction: it needs mockito-inline, which the module gets from the parent (connectors/pom.xml:125-128, Mockito 4.11.0).
  • High-performance multi-connection read: the test asserts that this path also starts the binlog reader. That behavior predates this PR (it is already in the base at 0879afe9), so the test locks in existing behavior and no new defect comes from it.

I didn't compile the code or run the tests. Reasonix's earlier local run says the tests pass, but I haven't confirmed it. Whether new-code coverage now clears the Sonar Quality Gate is still waiting on the next CI scan.

VERDICT: PASS

reasonix review

最终评审结论

评审范围:增量 f5dd4db8..3aa837ef,共 3 个文件、+218/−0(connectors/csv-connector/pom.xml、CsvValueConverterTest、MysqlConnectorTest),无生产代码改动。

历史发现状态:上一轮(head f5dd4db8)接受 0 条发现,因此没有需要标注 已修复 / 仍存在 / 部分修复 的条目;也没有历史 P3 分组需要抑制。上一轮已讨论过的既有行为(streamReadMultiConnection 的 highPerformance 分支没有提前 return,会再走一次 debezium binlog)依然存在于 origin/develop(0879afe9),本 PR 未改动它,属于既有行为,本轮新增测试只是把它固定下来,因此不作为本轮发现,也不阻塞。

本轮我独立复核的结论

  • csv-connector/pom.xml 新增 jacoco:与 connectors/mysql-connector/pom.xml:276-295 等模块的写法逐行一致,版本继承父 connectors/pom.xml:283-287 的 0.8.12(非 SNAPSHOT),prepare-agent + report(test) 两个 execution,本模块无重复声明。父 POM 的 JDK 9+ profile 通过 @{argLine} 把 agent 传给 surefire,本地实跑已确认生效。
  • 实测(离线 Maven,-pl connectors/csv-connector,connectors/mysql-connector test):MysqlConnectorTest 28 + MysqlDataTypeMappingTest 1 全绿;CsvConnectorTest 24 + CsvValueConverterTest 6 全绿;BUILD SUCCESS。新增 NewCodeCoverageTest 全部通过,说明其 mock/stub 与被测代码签名(clearTable/dropTable/getAfterUniqueAutoIncrementFields/call/streamRead/streamReadMultiConnection/timestampToStreamOffset)一致,times(2).setFetchSize(Integer.MIN_VALUE)(MysqlConnector.java:1260 + :1290)、{call demo_proc()}、ALTER TABLE ... AUTO_INCREMENT 等断言均与 main 代码吻合。
  • CsvValueConverterTest 新增用例:两条断言分别命中 determineDateFormat 与 FLEXIBLE_DATETIME 分支,均返回 LocalDateTime 墙钟值(CsvValueConverter.java:169-207),不依赖默认时区;LocalDateTime 在 JDK 8 可用(模块 java.version=8)。
  • 覆盖率产物实测:connectors/csv-connector/target/jacoco.exec 与 target/site/jacoco/jacoco.xml 已生成,CsvValueConverter.java 统计为 LINE 149 covered / 0 missed,证明该模块此前缺失的覆盖率数据现在能提供给 Sonar 读取,方向正确。

一致性与 P2 豁免:两位独立评审(codexcli、claudecli)均为 PASS,无高/中危发现,也就不存在单一评审上报的 P2 需要豁免或独立证实。我复核后同样没有发现新增缺陷:本轮改动不触碰生产逻辑、公共 API、并发或 JDK 兼容性,故无 P0/P1 可驳回项,也没有需要保留的 P2。

下一步:无需代码改动。剩余唯一动作是等 Scan-Connectors 的 Sonar Quality Gate 复算 New Code Coverage(MysqlConnector.java、CsvValueConverter.java)——这依赖外部 CI,不是本 PR 的代码问题。

FINAL_VERDICT: PASS

===FINDINGS===
===END===

标记:✅ 可通行

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jarad0628

Copy link
Copy Markdown
Collaborator Author

AI PR Review — ✅ 可通行

  • PR: #975
  • Head: 52cd69c2ae3cc28d71181e61f4f0a6ec0d0ececa
  • Reviewers: codexcli, claudecli, reasonix

最终总结

我先自己核对这次增量 diff 与相关代码,再下结论。

最终评审结论

本轮范围:3aa837ef7b3ea54cd29f36c74de79ef27efe77f5..52cd69c2ae3cc28d71181e61f4f0a6ec0d0ececa,仅 2 个文件(MysqlConnector.java +21/−2、MysqlConnectorTest.java +47/−2)。

评审覆盖与一致性

评审者 范围 结论
codexcli 增量 2 文件 PASS
claudecli 增量 2 文件(含调用方、子类、测试分析) PASS

上轮历史发现状态:上一轮(head 3aa837ef)未接受任何发现,因此无历史条目需复述;历史 P3 类噪声本轮为空,统一抑制、不逐条列出。

我的独立核对(不依赖两位评审的结论)

  1. 包装器语义正确:columnLabelMetaData 只拦截「1 个参数、方法名 getColumnName」的调用,转成 getColumnLabel,空白/空串标签回退到真实列名(EmptyKit.isBlank,connectors-common/connector-core 中已存在,导入齐全,不会编译失败);其余方法(含 0 参数调用,args == null)原样委托。
  2. 异常链正确:InvocationTargetException 被解包为 e.getCause() 抛出,SQLException 能原样冒泡,不会被包成反射异常。
  3. 无驱动/实现类强转风险:全仓 grep 未发现对 ResultSetMetaData 的具体实现类强转或 unwrap,所以代理替换不会造成 ClassCastException;MysqlConnector.class.getClassLoader() 加载 java.sql.ResultSetMetaData(platform 层接口)是合法的。
  4. 影响面收敛:只有 4 参 execute 使用包装器(3 参重载转调它,方向正确,不会触发 CommonDbConnector 的 LEGACY_DELEGATION 死循环保护);批读、hash split、queryByAdvanceFilterWithOffset、call/getOutputFromCall 仍用原始 metadata,键名不变。
  5. 子类:9 个 extends MysqlConnector 的模块都没有覆盖 execute;OceanbaseConnector 的 5 参 filterTimeForMysql 是独立重载(签名不同、当前无调用点),本增量不改其行为。
  6. 测试真实有效:新测试 executeKeysRowsBySqlAliasAndKeepsTypeConversion 断言了别名键、空标签回退列名、TIMESTAMP 走类型转换,并 assertFalse(row.containsKey("id")),去掉修复就会失败。
  7. 实测(我本地跑了):mvn -o -s /tmp/settings-offline.xml -pl connectors/mysql-connector test -Dtest=MysqlConnectorTest → Tests run: 8, Failures: 0, Errors: 0,新测试在列。未跑整个模块、未连真实 MySQL。

未采纳的低价值项(抑制,不进入 FINDINGS):call(存储过程)结果仍按列名建键,与命令查询的别名键语义不一致——属于范围外的风格一致性问题,无已声明需求,无实际影响;SELECT a.id, b.id 别名冲突与旧行为完全相同;每个 ResultSet 新建一个 Proxy 实例的开销可忽略。

需要做什么:无需修复,可以合并。唯一建议是留一次真实 MySQL + 自定义 SQL 别名的联调(含 executeCommand 路径),因为当前证据只来自单元测试。

FINAL_VERDICT: PASS

===FINDINGS===
===END===

codexcli review

本轮只检查了 3aa837ef7b3ea54cd29f36c74de79ef27efe77f5..52cd69c2ae3cc28d71181e61f4f0a6ec0d0ececa:改动限于 MysqlConnector.java 和对应测试文件。

  • 上轮无已接受发现,本轮无需复核历史条目。
  • 新增包装器仅将 getColumnName() 映射为 SQL 输出标签;标签为空时回退到列名,其余元数据调用仍委托原对象。现有 MySQL 时间类型转换路径保持使用。未发现可报告缺陷。
  • 未发现上轮之后的新人工评论;PR 的行内评论为空。
  • 未运行测试。

VERDICT: PASS

claudecli review

I found no defects in this round. There were no earlier findings to re-check, and there are no new human comments to answer.

Scope: the incremental range 3aa837ef..52cd69c2 changes two files: MysqlConnector.java (+20/−1) and MysqlConnectorTest.java (+47/−2).

What I checked in the change:

  • New wrapper columnLabelMetaData: only one-argument getColumnName(int) calls are redirected to getColumnLabel. A blank label falls back to the real column name. Every other call goes to the original metadata object unchanged. That includes no-argument calls, which pass null arguments safely. Errors from the original object are rethrown as-is, and ResultSetMetaData has no default methods for the wrapper to miss.
  • Which callers are affected: only execute(sql, consumer, batchSize, timeout) uses the wrapper. The 3-argument execute calls it with a timeout of 0. Batch reads, hash-split reads and queryByAdvanceFilterWithOffset still pass the original metadata, so their output keys don't change. Stored-procedure calls (call) are also untouched.
  • Subclasses: of the subclasses I listed, none overrides execute. Only OceanbaseConnector overrides filterTimeForMysql. It will now receive the wrapper, but it still calls getColumnName, so it picks up the alias keys without any change.
  • Duplicate column names: a query like SELECT a.id, b.id still produces the same colliding id key as before, so this is no worse than the old code.
  • Behavior change: the old executeCommand path also returns alias keys now. This matches the PR's intent, and I didn't treat it as a regression.
  • Tests:
    • The existing test now matches the wrapped metadata with any(ResultSetMetaData.class), so it can still fail if the conversion step isn't called.
    • The new test covers an alias, a blank label falling back to the column name, and TIMESTAMP conversion on an aliased column. It also asserts that the original column names are absent, so it would fail without the fix.
  • Build: no build files changed in this round, and java.lang.reflect.Proxy is available on every supported JDK.

I didn't run any tests; this was a read-only review.

VERDICT: PASS

reasonix review

我先自己核对这次增量 diff 与相关代码,再下结论。

最终评审结论

本轮范围:3aa837ef7b3ea54cd29f36c74de79ef27efe77f5..52cd69c2ae3cc28d71181e61f4f0a6ec0d0ececa,仅 2 个文件(MysqlConnector.java +21/−2、MysqlConnectorTest.java +47/−2)。

评审覆盖与一致性

评审者 范围 结论
codexcli 增量 2 文件 PASS
claudecli 增量 2 文件(含调用方、子类、测试分析) PASS

上轮历史发现状态:上一轮(head 3aa837ef)未接受任何发现,因此无历史条目需复述;历史 P3 类噪声本轮为空,统一抑制、不逐条列出。

我的独立核对(不依赖两位评审的结论)

  1. 包装器语义正确:columnLabelMetaData 只拦截「1 个参数、方法名 getColumnName」的调用,转成 getColumnLabel,空白/空串标签回退到真实列名(EmptyKit.isBlank,connectors-common/connector-core 中已存在,导入齐全,不会编译失败);其余方法(含 0 参数调用,args == null)原样委托。
  2. 异常链正确:InvocationTargetException 被解包为 e.getCause() 抛出,SQLException 能原样冒泡,不会被包成反射异常。
  3. 无驱动/实现类强转风险:全仓 grep 未发现对 ResultSetMetaData 的具体实现类强转或 unwrap,所以代理替换不会造成 ClassCastException;MysqlConnector.class.getClassLoader() 加载 java.sql.ResultSetMetaData(platform 层接口)是合法的。
  4. 影响面收敛:只有 4 参 execute 使用包装器(3 参重载转调它,方向正确,不会触发 CommonDbConnector 的 LEGACY_DELEGATION 死循环保护);批读、hash split、queryByAdvanceFilterWithOffset、call/getOutputFromCall 仍用原始 metadata,键名不变。
  5. 子类:9 个 extends MysqlConnector 的模块都没有覆盖 execute;OceanbaseConnector 的 5 参 filterTimeForMysql 是独立重载(签名不同、当前无调用点),本增量不改其行为。
  6. 测试真实有效:新测试 executeKeysRowsBySqlAliasAndKeepsTypeConversion 断言了别名键、空标签回退列名、TIMESTAMP 走类型转换,并 assertFalse(row.containsKey("id")),去掉修复就会失败。
  7. 实测(我本地跑了):mvn -o -s /tmp/settings-offline.xml -pl connectors/mysql-connector test -Dtest=MysqlConnectorTest → Tests run: 8, Failures: 0, Errors: 0,新测试在列。未跑整个模块、未连真实 MySQL。

未采纳的低价值项(抑制,不进入 FINDINGS):call(存储过程)结果仍按列名建键,与命令查询的别名键语义不一致——属于范围外的风格一致性问题,无已声明需求,无实际影响;SELECT a.id, b.id 别名冲突与旧行为完全相同;每个 ResultSet 新建一个 Proxy 实例的开销可忽略。

需要做什么:无需修复,可以合并。唯一建议是留一次真实 MySQL + 自定义 SQL 别名的联调(含 executeCommand 路径),因为当前证据只来自单元测试。

FINAL_VERDICT: PASS

===FINDINGS===
===END===

标记:✅ 可通行

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