zhangshenghang commented on PR #10488:
URL: https://github.com/apache/seatunnel/pull/10488#issuecomment-3894509898
<!-- code-pr-reviewer -->
<!-- cpr:pr_reply_v2_parts {"group": "apache/seatunnel#10488", "part": 1,
"total": 1} -->
## 1) PR 基本信息(事实)
- **PR 标题**:`[Fix][Connector-v2][JDBC] Enhance WHERE condition handling in
SQL queries`(置信度:高)
- **模块**:`Connector-V2 / JDBC Source`(置信度:高)
- **类型**:Bug Fix(围绕 `where_condition` SQL 组装逻辑)(置信度:高)
- **变更文件**:5
个(`ChunkSplitter`、`DynamicChunkSplitter`、`FixedChunkSplitter`、新增
`SqlWhereConditionHelper`、新增其测试)(置信度:高)
- **Issue 链接**:PR 描述中未提供(置信度:高)
- **测试执行情况**:未执行构建/测试(按你的只读约束)(置信度:高)
---
## 2) 问题定义(通俗解释)
### 原始问题(推断+代码佐证)
- 旧实现在 `ChunkSplitter.createPreparedStatement` 里统一外包一层 `SELECT * FROM (...)
tmp where_condition`。
- 当用户自定义 `query` 只选了部分列,而 `where_condition` 使用了未投影列时,外层 `WHERE` 会引用不到列,导致
SQL 失败。
(置信度:高,旧代码在 `dev` 分支可见)
### 场景示例
- 用户配置:
- `query = "SELECT id, name FROM orders"`
- `where_condition = "where partition_date = '2026-02-01'"`
- 旧逻辑会生成外层过滤,`partition_date` 不在内层输出列里,数据库会报列不存在。
(置信度:高)
### 影响范围
- 主要影响 JDBC Source 中使用 `where_condition + 自定义 query` 的用户。
(置信度:高)
---
## 3) 调用链(含修改点)
```mermaid
graph TD
A[SeaTunnel Job] --> B[JdbcSourceSplitEnumerator.run]
B --> C[ChunkSplitter.generateSplits]
C --> D[DynamicChunkSplitter / FixedChunkSplitter]
A --> E[JdbcSourceReader -> JdbcInputFormat.open]
E --> F[ChunkSplitter.generateSplitStatement]
F --> G[ChunkSplitter.applyUserWhereCondition]
G --> H[SqlWhereConditionHelper.applyWhereConditionWithWrap]
H --> I[ChunkSplitter.createPreparedStatement]
I --> J[JDBC executeQuery]
style H fill:#f9f,stroke:#333,stroke-width:3px
```
---
## 4) 核心审查结论
### 已确认的正向点(事实)
1. `where_condition` 的拼接不再在 `createPreparedStatement` 全局硬拼,而是前移到 split SQL
生成阶段,调用链更可控(置信度:高)。
2. 新增 `SqlWhereConditionHelperTest`,覆盖了很多字符串场景(置信度:高)。
3. 无新增第三方依赖;配置项和 SPI 接口未改(置信度:高)。
---
## 问题 1:缺列检测扫描了**整条 SQL**,会漏判“SELECT 未投影但在 WHERE/ON/字符串里出现”的列(阻塞)
**位置**:`SqlWhereConditionHelper.java:154`、`106-123`
```java
List<String> missingFields = findMissingFields(sql, requiredFields);
...
Matcher matcher = pattern.matcher(sql);
```
相关上下文:
- 调用入口:`ChunkSplitter.java:150-154`
- 调用方1:`DynamicChunkSplitter.java:674,682`
- 调用方2:`FixedChunkSplitter.java:222,236,309,321`
**问题描述(事实+推断)**:
- 方法目标是“确保字段在 SELECT 子句里”,但实际用整条 SQL 做存在性判断。
- 如果列仅出现在内层 `WHERE/JOIN/ORDER BY`,会被误判为“已存在”,从而不补到 SELECT 列表。
- 外层再套 `WHERE` 时仍可能找不到该列,原 bug 在这类场景仍可复现。
(置信度:高)
**潜在风险**:
- 风险1:`where_condition` 仍可能触发运行时 SQL 列不存在异常。
- 风险2:字符串字面量命中字段名时也会误判“已存在”。
(置信度:高)
**影响范围**:
- 直接影响:`SqlWhereConditionHelper.applyWhereConditionWithWrap`
- 间接影响:Dynamic/Fixed/Single split 的 SQL 生成链路
- 影响面:JDBC Connector(单 Connector)
(置信度:高)
**严重程度**:高
**改进建议**:
```java
// ensureFieldsInSelect 内
String selectClause = (fromIndex != -1) ? sql.substring(0, fromIndex) : sql;
List<String> missingFields = findMissingFields(selectClause, requiredFields);
```
并在 `findMissingFields` 前去除字符串字面量/注释后再匹配。
理由:目标是判断“是否在投影列中”,不是“是否在 SQL 任意位置出现”。
(置信度:高)
---
## 问题 2:去引号后直接回填列名,遇到保留字/特殊字符列会生成非法 SQL(阻塞)
**位置**:`SqlWhereConditionHelper.java:87-90, 163-166`
```java
field = field.replaceAll("^[`\"\\[]|[`\"\\]]$", "");
...
insertion.append(", ").append(field);
```
相关上下文:
- 调用入口:`ChunkSplitter.applyUserWhereCondition`
- 下游执行:`ChunkSplitter.createPreparedStatement`
**问题描述(事实+推断)**:
- 代码先去掉反引号/双引号/方括号,再把字段原样拼回 SQL。
- 若字段本来需要引用(如保留字 `order`、特殊字符 `order-id`),回填后 SQL 可能非法或语义错误。
(置信度:高)
**潜在风险**:
- 风险1:SQL 语法错误(生产直接失败)。
- 风险2:跨方言兼容性下降(不同数据库标识符规则不同)。
(置信度:高)
**影响范围**:
- 直接影响:`extractFieldNamesFromWhere` + `ensureFieldsInSelect`
- 间接影响:所有启用 `where_condition` 的 JDBC Source 读链路
- 影响面:JDBC Connector
(置信度:高)
**严重程度**:高
**改进建议**:
- 保留“原始带引号 token”用于回填;
- 或在 helper 接收 dialect/quote 策略,统一 `quoteIdentifier` 后插入;
- 同时新增包含保留字、`-`、空格列名的单元测试。
理由:当前实现破坏了用户显式给出的标识符引用语义。
(置信度:高)
---
## 问题 3:测试主要是字符串 contains,缺少关键集成场景断言(非阻塞但建议补)
**位置**:`SqlWhereConditionHelperTest.java`(整体)
**问题描述(事实)**:
- 现有测试大量使用 `contains("SELECT * FROM (")` 这类弱断言。
- 未覆盖“字段出现在原 SQL 的 WHERE/ON,但不在 SELECT 投影”这一关键失败场景。
- 也未覆盖“保留字/特殊字符列名回填后 SQL 合法性”场景。
(置信度:高)
**严重程度**:中
**建议补充**:
1. `SELECT id FROM t WHERE partition_date > ...` + `where_condition` 引用
`partition_date`
2. `where_condition` 使用 `` `order-id` `` / `"order"` / `[order]`
3. Dynamic/Fixed splitter 端到端 SQL 断言(不仅 helper)
(置信度:高)
---
## 5) 兼容性与架构评估(简要)
- **API/SPI**:未破坏公开接口;`Option` 未变更(置信度:高)
- **调用方完整性**:`createPreparedStatement` 的 4 个现有调用点已迁移到前置拼接(置信度:高)
- **性能**:新增正则解析与 SQL 字符串处理,单次开销小;但 `log.warn` 可能在多 split 下刷屏(置信度:中)
- **Checkpoint/Exactly-once/Schema 机制**:未见直接改动(置信度:中高)
---
## 最终结论
**当前不建议直接 merge。**
原因:存在 2 个高严重度逻辑缺陷(问题 1、2),会导致部分真实场景下 SQL 仍失败或新失败。建议先修复并补充针对性测试后再合并。
(结论置信度:高)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]