Skip to content

fix(spark): use functionName instead of viewName in lateralView rule - #503

Open
iGarym wants to merge 1 commit into
DTStack:mainfrom
iGarym:fix/spark-lateral-view-function
Open

iGarym wants to merge 1 commit into
DTStack:mainfrom
iGarym:fix/spark-lateral-view-function

Conversation

@iGarym

@iGarym iGarym commented Nov 5, 2026 •

Copy link
Copy Markdown

问题分析

在 Spark SQL 语法规范中,LATERAL VIEW [OUTER] generator_function(expression, ...) 后接的是表生成函数(UDTF,如 EXPLODE、POSEXPLODE 等),而非视图(View)。

  • 历史根因:初始导入 Apache Spark 官方语法(623a004cd)时,该位置定义为 qualifiedName。在 PR #179(4d1dfa676)支持 Spark SQL 自动补全时将其改为了 viewName。
  • 异常表现:
    1. 实体收集误报(getAllEntities):SparkEntityCollector.exitViewName 会将所有 viewName 收集为 EntityContextType.VIEW,导致 LATERAL VIEW EXPLODE(...) 中的函数名 EXPLODE 被误收集为视图实体。
    2. 代码补全与报错提示偏差(getSuggestionAtCaretPosition / validate):SparkSQL 与 SparkErrorListener 将 RULE_viewName 映射为视图,导致在 LATERAL VIEW | 处触发补全时返回 EntityContextType.VIEW(应为 EntityContextType.FUNCTION),未完成语句报错提示 expecting an existing view(应为 expecting an existing function)。
    3. 语法覆盖受限:viewName(viewIdentifier)最多仅允许两段式名称(db.view),导致 LATERAL VIEW 无法支持三段式函数名(catalog.schema.func)及 IDENTIFIER('func') 动态函数调用。

改动方案

1. 语法规则修改

将 src/grammar/spark/SparkSqlParser.g4 中 lateralView 规则里的 viewName 替换为 functionName,并重新生成 src/lib/spark 下的 Parser 代码。

2. 为什么采用此方案

全仓支持 LATERAL VIEW 语法的方言仅有 Spark 与 Hive。在 HiveSqlParser.g4 中,lateralView 规则使用的是 function_(内部对应 functionNameForInvoke)。在评估 Spark 的修复方案时对比了以下三种路径,最终选择替换为 functionName:

  1. 对比方案 A:还原为 Apache Spark 官方原始的 qualifiedName(不采用)
    • 虽然能消除 getAllEntities 将生成函数误收集为 view 的问题,但 RULE_qualifiedName 在本仓库中属于底层通用标识符规则,不能直接加入 SparkSQL.preferredRules(否则会污染列、表、分区等其他引用 qualifiedName 的位置)。若使用 qualifiedName,会导致 LATERAL VIEW | 处丢失 EntityContextType.FUNCTION 语法补全,且语法报错退化为仅提示 expecting a keyword,无法与 Hive 方言行为对齐。
  2. 对比方案 B:保持语法不变,在 SparkEntityCollector.exitViewName 中排除 lateralView 父节点(不采用)
    • 仅能解决 getAllEntities 的误报,无法修复代码补全仍提示 VIEW、语法报错仍提示 expecting an existing view 以及 viewName 不支持三段式函数名和 IDENTIFIER(...) 的问题,属于治标不治本。
  3. 当前方案:替换为 functionName(采用)
    • 语义与语法一致:在 SparkSqlParser.g4 中,同为表值函数调用的 atomFunctionTable(第 787 行)和普通标量函数调用(第 971 行)均使用 functionName。将其统一为 functionName 既符合 UDTF 的真实语义,又能天然支持三段式限定名(qualifiedName)和 IDENTIFIER(...) 语法。
    • 零侵入复用现有机制:SparkSQL.preferredRules、SparkSQL.processCandidates 和 SparkErrorListener 已完整配置了 RULE_functionName -> EntityContextType.FUNCTION / 'function' 的映射;且 SparkEntityCollector 不监听普通调用态的 functionName。
    • 与 Hive 方言行为完全对齐:修改后,SparkSQL 与 HiveSQL 在处理 LATERAL VIEW 时的表现完全一致:
      • 实体收集(getAllEntities):均不将 LATERAL VIEW 后的 UDTF 收集为 view 或其他额外实体,仅收集主查询的表与 queryResult 实体。
      • 代码补全(getSuggestionAtCaretPosition):在 LATERAL VIEW | 及 LATERAL VIEW OUTER | 后均返回 syntaxContextType: EntityContextType.FUNCTION。
      • 语法报错(validate):未完成语句均提示 Statement is incomplete, expecting an existing function or a keyword。

影响范围及风险评估

  • 影响范围:
    • 仅限于 Spark SQL 方言(src/grammar/spark、src/lib/spark)中的 lateralView 语法规则及其关联的实体收集、代码补全与语法报错提示。
    • 其他 SQL 方言不受影响(已核查全仓其余 7 个方言:Hive 的 lateralView 已使用 function_,其余方言无 lateralView 规则)。
  • 风险评估:可逆变更**
    • 改动仅涉及 SparkSqlParser.g4 中的 1 行规则替换及对应的 ANTLR 生成产物,不涉及 src/parser/common 公共逻辑。
    • 修复后 Spark 对 LATERAL VIEW 的实体收集、补全与报错行为与 Hive 方言完全一致;同时 functionName 完全超集兼容原有的单段与两段式标识符语法,不会破坏已有合法 SQL 的解析。

Replace viewName with functionName in SparkSqlParser.g4 lateralView rule
so generator functions in LATERAL VIEW clauses are no longer collected as
view entities by getAllEntities, and code completion and syntax error
messages expect a function rather than a view.

Co-authored-by: Cursor <cursoragent@cursor.com>
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