antlr parser sql如何区分字段和表?

5us2dqdw  于 2021-07-24  发布在  Java
关注(0)|答案(1)|浏览(394)

我编写了一些antlr4规则来解析sql,只是想区分字段和表。但是它们做了一些意想不到的事情。我的规则:

grammar Col;
stat : SELECT select_list FROM table_ref_list;
select_list : select_ele (',' select_ele)* ;
select_ele : Subquery_in_field_nor    //subquery select column
            | ID '(' .*? ')'  //function calls
            | NoDotId '(' .*? ')' NoDotId '(' .*? ')'  //window function call
            | ID             //like column of tab
            | DIGIT          //number
            | STRING         //like this 'dad'
            ;

table_ref_list
    : table_ref (',' table_ref)*
    ;

table_ref:table_block (NoDotId)?;

table_block : ID                   //So much like select_ele
          | Subquery_in_field_nor
          ;

Subquery_in_field_nor : '(' (Subquery_in_field | ~[()])* ')';  //Resolving function nesting
Subquery_in_field : '(' .*? ')' ;
SELECT : [Ss][Ee][Ll][Ee][Cc][Tt];
FROM :[Ff][Rr][Oo][Mm];
NL : [ \r\n]+ ->skip;
ID : [A-Za-z] [A-Za-z0-9.]*;
NoDotId : [A-Za-z] [A-Za-z0-9]*;  
DIGIT : ('-')? [0-9]+('.' [0-9]+)?;
STRING : '\'' .*? '\'';

我的sql文件是这样的

SELECT substr(A.EMPNO,1,2),
       A.ENAME,
       '1',
       'wwet',
       18,
       A.DEPTNO FROM EMP A

显示消息

line 1:13 missing FROM at '(A.EMPNO,1,2)'
line 3:7 mismatched input ''1'' expecting {Subquery_in_field_nor, ID}
line 4:7 mismatched input ''wwet'' expecting {Subquery_in_field_nor, ID}
line 5:7 mismatched input '18' expecting {Subquery_in_field_nor, ID}
(stat SELECT (select_list (select_ele substr)) <missing FROM> (table_ref_list (table_ref (table_block (A.EMPNO,1,2))) , (table_ref (table_block A.ENAME)) , (table_ref (table_block '1')) , (table_ref (table_block 'wwet')) , (table_ref (table_block 18)) , (table_ref (table_block A.DEPTNO))))

我不知道为什么?为什么 select_list : select_ele (',' select_ele)* ,但仍然匹配表\u ref?

zphenhs4

zphenhs41#

substr(A.EMPNO,1,2) 不匹配为 select_ele 因为它产生代币: ID :
substr Subquery_in_field_nor : (A.EMPNO,1,2) 而不是两种选择中的任何一种:
| ID '(' .? ')' //function calls | NoDotId '(' .*? ')' NoDotId '(' .*? ')' //window function call 零件“('.?')”解释为:匹配 ( 标记,不情愿地后跟零个或多个其他标记,以 ) 代币。但是由于antlr的lexer在标记输入时试图获取尽可能多的字符, (A.EMPNO,1,2) 总会有一个 Subquery_in_field_nor 代币。
除了lexer中贪婪的标记化之外,您还必须注意,当2个或更多lexer规则可以匹配相同的字符时,首先定义的规则“获胜”。所以输入 select 可以匹配 SELECT , ID 以及 NoDotId . 但是自从 SELECT 首先定义,输入将始终成为 SELECT 代币。然而,输入 foo 可以匹配 ID 以及 NoDotId 从那以后呢 ID 先定义,它就会赢。你会注意到永远不会有 NoDotId 因为它匹配的任何东西也会被匹配 ID .
下面是一个稍加修改的语法,适用于您的输入:

grammar Col;

stat
  : SELECT select_list FROM table_ref_list
  ;

select_list
 : select_ele (',' select_ele)*
 ;

select_ele
 : id Subquery_in_field_nor (id Subquery_in_field_nor)?
 | id
 | DIGIT
 | STRING
 ;

table_ref_list
 : table_ref (',' table_ref)*
 ;

table_ref
 : table_block id?
 ;

table_block
 : id
 | Subquery_in_field_nor
 ;

id
 : ID ('.' ID)*
 ;

Subquery_in_field_nor : '(' (Subquery_in_field | ~[()])* ')';  //Resolving function nesting
Subquery_in_field     : '(' .*? ')' ;
SELECT                : [Ss][Ee][Ll][Ee][Cc][Tt];
FROM                  : [Ff][Rr][Oo][Mm];
NL                    : [ \r\n]+ ->skip;
ID                    : [A-Za-z] [A-Za-z0-9]*;
DIGIT                 : ('-')? [0-9]+('.' [0-9]+)?;
STRING                : '\'' .*? '\'';

或者更好,从antlr4 github repo获取现有的sql语法:https://github.com/antlr/grammars-v4 请注意,所有这些语法都是来自社区的开源贡献:正确地测试它们,因为它们中的许多都有局限性(准确性和性能)。

相关问题