You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修改ANTLR SQL语法以支持对象访问时忽略保留关键字?

修改ANTLR语法以支持带空格的限定标识符(含保留关键字)

背景说明

在SQL里,保留关键字一般不能直接当列名用,比如写SELECT select FROM tbl会触发语法错误。要想用关键字当列名,通常得给它加引号,比如SELECT select FROM tbl(具体引号语法依方言而定)。

但有个例外:当标识符是限定对象(比如带表名/函数前缀)时,不用加引号就能直接用关键字,比如:

SELECT tbl.select FROM tbl
SELECT function().select

现在你的ANTLR语法能正常解析普通的SELECT语句(比如SELECT col1, xxx, xxx;),但没法处理SELECT tbl.select, tbl . select;这种带空格的限定标识符,下面是具体的修改方案。

方言适配说明

不同SQL方言对.前后空格的要求不一样:

  • Postgres、BigQuery:允许.前后有空格
  • MySQL:不允许.前后有空格
  • SQLite、SQLServer:不支持“限定后直接用关键字”的特性,末尾标识符仍需加引号

修改步骤

1. 更新词法分析器(DBLexer.g4)

首先要把.单独定义为TOKEN,这样才能支持前后带空格的场景:

lexer grammar DBLexer;
options { caseInsensitive=true; }

COMMA               : ',';                        // 参数列表、选择列表分隔符
SEMI                : ';';                        // 语句终止符
SELECT              : 'SELECT';                   // SELECT关键字
DOT                 : '.';                        // 限定标识符的分隔点

IDENTIFIER
    : [A-Z_] [A-Z_0-9]*
    ;

WHITESPACE
    : [ \t\r\n] -> skip
    ;

2. 更新解析器(DBParser.g4)

核心是修改expr规则,支持嵌套的限定结构,并且允许限定部分的末尾是保留关键字。这里有两种简洁的实现方式:

方式一:直接允许关键字作为限定后的标识符

把关键字加入到可解析的表达式单元中,这样select这类关键字在限定结构里会被正常识别:

parser grammar DBParser;
options { tokenVocab = DBLexer;}

root
    : selectStatement? (SEMI selectStatement)* SEMI EOF?
    ;

selectStatement
    : SELECT selectItem (COMMA selectItem)* COMMA?
    ;

selectItem
    : expr (AS? IDENTIFIER)?
    ;

// 支持嵌套限定,比如 tbl.select、schema.tbl.select、tbl . select 等
expr
    : primaryExpr (DOT primaryExpr)*
    ;

// 允许标识符或关键字作为表达式单元
primaryExpr
    : IDENTIFIER
    | SELECT // 这里可以继续添加其他需要支持的关键字,比如 FROM、WHERE 等
    ;

方式二:用模式让关键字仅在特定语境生效

如果不想逐个列关键字,可以修改词法分析器,让SELECT这类字符串只有在语句开头(比如作为SELECT语句的起始关键字)才被识别为关键字,其他场景下都作为普通标识符:

lexer grammar DBLexer;
options { caseInsensitive=true; }

// 默认模式
COMMA               : ',';
SEMI                : ';';
DOT                 : '.';

// 只有当SELECT出现在语句起始位置时,才识别为关键字,否则作为IDENTIFIER
SELECT              : 'SELECT' -> pushMode(DEFAULT_MODE);

IDENTIFIER
    : [A-Z_] [A-Z_0-9]*
    ;

WHITESPACE
    : [ \t\r\n] -> skip
    ;

对应的解析器expr规则可以简化为:

expr
    : IDENTIFIER (DOT IDENTIFIER)*
    ;

3. 方言差异化处理

  • 对于允许.前后空格的方言(Postgres、BigQuery):因为词法分析器已经自动跳过空格,修改后的语法天然支持这种场景。
  • 对于不允许空格的方言(MySQL):可以在语义分析阶段添加检查,当DOT前后存在空格时抛出错误。
  • 对于不支持该特性的方言(SQLite、SQLServer):在语义分析阶段,若限定结构的最后一个标识符是关键字,要求用户添加引号。

测试验证

修改后的语法可以正常解析以下语句:

SELECT tbl.select, tbl . select;
SELECT schema.tbl.select, func().select;

而SELECT col1, select;这类非限定的关键字列名依然会报错,符合SQL的原生规则。

内容的提问来源于stack exchange,提问作者samuelbrody1249

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 00:45:36