Skip to content

fix(spark): #501 fix syntax error for subtraction between column and function call - #502

Open
iGarym wants to merge 1 commit into
DTStack:mainfrom
iGarym:fix/spark-subtraction-func-501
Open

iGarym wants to merge 1 commit into
DTStack:mainfrom
iGarym:fix/spark-subtraction-func-501

Conversation

@iGarym

@iGarym iGarym commented Nov 5, 2026

Copy link
Copy Markdown

Fixes #501

根因分析

  1. 无效的错误捕获规则残留:
    SparkSqlParser.g4 沿用了 Apache Spark 官方语法的 errorCapturingIdentifier(含 errorCapturingIdentifierExtra : (MINUS identifier)+)。在 Apache Spark 中,该规则配合 Scala PostProcessor 用于捕获未加反引号的连字符标识符(如 test-table)并抛出专用异常;但本仓库在 #163 导入并精简语法标签时移除了 #errorIdent,且从未实现对应的后置报错逻辑。
  2. 表达式规则引入连字符标识符歧义:
    后续在 #179、#218、#358 中,lateralView(viewName)、namedExpression(columnName)和 primaryExpression(columnNamePath)先后改为引用 multipartIdentifier -> errorCapturingIdentifier,打破了原语法“不要在紧跟表达式的位置使用 errorCapturingIdentifier”的约束。
  3. SLL 预测冲突误选分支:
    在 PredictionMode.SLL(#269)下解析 SELECT (price - if(...)) * quantity FROM t; 时,由于 SLL 不保留外层调用栈,errorCapturingIdentifierExtra 的 Alt 1(将 price - if 吞作单个标识符)借由 lateralView 规则消化了后续的 (...),并在外层右括号 ) 处与 Alt 2(正常算术减法)产生 SLL 完备冲突。ANTLR 默认选择编号更小的 Alt 1,导致 price - if 被误判为列名,进而对随后的 ( 报错 missing ')' at '('。

改动内容

  1. 移除 src/grammar/spark/SparkSqlParser.g4 中 errorCapturingIdentifierExtra 的 (MINUS identifier)+ 错误捕获分支,将 errorCapturingIdentifier 简化为直接匹配 identifier(与 #432 移除 PostgreSQL 错误捕获规则一致),并重新生成 src/lib/spark 下的解析器代码。
  2. 补充 test/parser/spark 下关于列与函数相减表达式语法校验、减法表达式实体收集(getAllEntities)、SET / RESET 带中划线配置项以及非法连字符标识符校验的测试用例。

影响范围与风险评估

  • 方言与变更范围:仅限 Spark SQL,不涉及其他方言或公共基类;改动收敛在 SparkSqlParser.g4 的 errorCapturingIdentifier 规则,可随时通过单次提交回滚。
  • 修复的问题:
    • 语法校验(validate):修复括号内列与函数调用相减(如 SELECT (price - if(...)) * quantity FROM t;)、无 FROM 子句的列与函数调用相减(如 SELECT price - if(...);)以及无参函数减法(如 SELECT a - f();)的语法校验误报。
    • 实体收集(getAllEntities):修复 SELECT a - b FROM t;、SELECT a - f(x) FROM t; 等减法表达式被静默归类为字面量列(ColumnDeclareType.LITERAL)而非表达式列(ColumnDeclareType.EXPRESSION)的问题。
  • 对其他含 - 语法的兼容性:
    • SET / RESET 配置语句(如 SET tez.grouping.max-size = 1;、SET -v;、RESET tez.grouping.max-size;):走 #setAny(KW_SET .*?)和 #resetAny(KW_RESET .*?),不经过 errorCapturingIdentifier,不受影响。
    • 表/库属性(如 TBLPROPERTIES ('max-age' = '1'))、负数常量、时间间隔 INTERVAL -1 DAY、反引号包裹的带中划线标识符(如 `test-table`、`col-a`):不受影响。
    • 未加反引号的非法连字符标识符(如 CREATE DATABASE test-db;、CREATE TABLE test-tbl (id-col INT);):将按 Spark SQL 规范正常拦截并报语法错误。

…mn and function call

Remove errorCapturingIdentifierExtra (MINUS identifier)+ rule from
SparkSqlParser.g4 so SLL prediction does not misparse
column-minus-function expressions as hyphenated identifiers.

Co-authored-by: Cursor <cursoragent@cursor.com>
@Cythia828

Copy link
Copy Markdown
Collaborator

好的,PR已收到,review没问题后会随着下个版本一起发布,感谢你的关注

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.

[Bug]: Syntax error reported for parenthesized subtraction between a column and a function call

2 participants