Skip to content

Commit 1ac4c0b

Browse files
committed
add ontology for TIS
1 parent fce272f commit 1ac4c0b

44 files changed

Lines changed: 6166 additions & 6 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# AstValidator WITH 语句支持修复
2+
3+
## 问题描述
4+
5+
测试 `TestAstValidator.testValidSelectForWithStatement()` 失败,因为 `AstValidator` 没有正确处理 SQL 中的 WITH 语句(CTE - Common Table Expression)。
6+
7+
## 根本原因
8+
9+
1. **CTE 表名被当作普通表校验**:WITH 语句中定义的临时表(如 `category_sales``total_sales`)被当作需要在白名单中的普通表
10+
2. **分号解析错误**:Presto SQL Parser 不接受 SQL 末尾的分号
11+
3. **CTE 之间的 JOIN 被校验**:CTE 定义的临时表之间的 JOIN 也被当作需要 linker 的 JOIN
12+
4. **CROSS JOIN 误报**:没有 ON 条件的 CROSS JOIN(包括逗号分隔的多表查询)被当作需要 linker 的 JOIN
13+
14+
## 解决方案
15+
16+
### 1. 支持 WITH 语句中的 CTE(核心修复)
17+
18+
**修改文件**`AstValidator.java`
19+
20+
`AstCollector` 类中添加:
21+
- 新增 `cteNames` 集合,用于存储 CTE 定义的表名
22+
- 重写 `visitWith()` 方法,收集所有 CTE 名称
23+
- 修改 `visitTable()` 方法,排除 CTE 表名的收集
24+
- 修改 `visitJoin()` 方法,排除涉及 CTE 的 JOIN
25+
26+
```java
27+
final Set<String> cteNames = new HashSet<>();
28+
29+
@Override
30+
protected Void visitWith(With node, Void context) {
31+
for (WithQuery query : node.getQueries()) {
32+
cteNames.add(query.getName().toString());
33+
}
34+
return super.visitWith(node, context);
35+
}
36+
37+
@Override
38+
protected Void visitTable(Table node, Void context) {
39+
String tableName = node.getName().toString();
40+
if (!cteNames.contains(tableName)) {
41+
tables.add(tableName);
42+
}
43+
return super.visitTable(node, context);
44+
}
45+
```
46+
47+
### 2. 自动去除末尾分号
48+
49+
`validate()` 方法开头添加:
50+
51+
```java
52+
// 去除末尾的分号(Presto Parser 不接受分号)
53+
sql = sql.trim();
54+
if (sql.endsWith(";")) {
55+
sql = sql.substring(0, sql.length() - 1).trim();
56+
}
57+
```
58+
59+
### 3. 跳过 CROSS JOIN 的 linker 校验
60+
61+
修改 `visitJoin()` 方法,只对有 ON 条件的 JOIN 进行 linker 校验:
62+
63+
```java
64+
if (left != null && right != null && !cteNames.contains(left) && !cteNames.contains(right)) {
65+
// 如果有 JOIN 条件(不是 CROSS JOIN),才需要校验 linker
66+
if (node.getCriteria().isPresent()) {
67+
joins.add(new JoinPair(left, right));
68+
}
69+
}
70+
```
71+
72+
### 4. 修复测试断言
73+
74+
**修改文件**`TestAstValidator.java`
75+
76+
- `testValidSelectForWithStatement`:添加必要的 linker(`toy_sales <-> toy_products`
77+
- `testInvalidTableNotInWhitelist`:修改断言检查 `issues` 而不是 `reason`
78+
79+
```java
80+
// 修改前
81+
assertTrue("Error should mention invalid table", result.reason().contains("Invalid tables"));
82+
83+
// 修改后
84+
assertTrue("Error should mention invalid table",
85+
result.issues().stream().anyMatch(issue -> issue.contains("Invalid tables")));
86+
```
87+
88+
## 测试结果
89+
90+
所有 12 个测试全部通过:
91+
92+
```
93+
[INFO] Tests run: 12, Failures: 0, Errors: 0, Skipped: 0
94+
```
95+
96+
## 支持的 SQL 特性
97+
98+
修复后,`AstValidator` 现在支持:
99+
100+
1.**WITH 语句(CTE)**:可以定义和使用多个 CTE
101+
2.**嵌套 CTE**:CTE 可以引用其他 CTE
102+
3.**CTE 与真实表的 JOIN**:CTE 中可以 JOIN 真实表
103+
4.**CROSS JOIN**:不需要 linker 的笛卡尔积 JOIN
104+
5.**逗号分隔的多表查询**:隐式 CROSS JOIN
105+
6.**带分号的 SQL**:自动去除末尾分号
106+
107+
## 示例
108+
109+
### 成功案例:复杂 WITH 语句
110+
111+
```sql
112+
WITH category_sales AS (
113+
SELECT
114+
p.Product_Category,
115+
SUM(CAST(p.Product_Price AS DECIMAL) * s.Units) AS category_total_sales
116+
FROM toy_sales s
117+
JOIN toy_products p ON s.Product_ID = p.Product_ID
118+
GROUP BY p.Product_Category
119+
HAVING SUM(CAST(p.Product_Price AS DECIMAL) * s.Units) > 50
120+
),
121+
total_sales AS (
122+
SELECT SUM(category_total_sales) AS grand_total
123+
FROM category_sales
124+
)
125+
SELECT
126+
cs.Product_Category,
127+
cs.category_total_sales,
128+
ROUND(cs.category_total_sales / ts.grand_total * 100, 2) AS percentage_of_total
129+
FROM category_sales cs
130+
CROSS JOIN total_sales ts;
131+
```
132+
133+
**校验结果**:✅ 通过
134+
- CTE `category_sales``total_sales` 不在白名单校验范围内
135+
- 真实表 `toy_sales``toy_products` 的 JOIN 通过 linker 校验
136+
- CROSS JOIN 不需要 linker 校验
137+
138+
## 相关文件
139+
140+
- `AstValidator.java` - 核心校验逻辑
141+
- `TestAstValidator.java` - 单元测试
142+
- `ValidationResult.java` - 校验结果数据结构
143+
144+
## 日期
145+
146+
2026-06-02

0 commit comments

Comments
 (0)