lex 和 yacc 学习…

在编写dbscale的sql解析器的过程中,耗时最多的对select语法分支的冲突处理。

主要的问题来自:
1. select可能是个子查询
2. select支持 select:(select),即可以自由嵌套小括号
3. 对union语句的支持

问题1的关键在于如何区分第一个碰到的“SELECT”是一个select语句起始的“SELECT”,还是一个子查询的“SELECT”。

解决的办法是所有其他可能带有子查询语法分支在进入子查询分支之前必须先把语句类型标识出来。
例如:

stmt: delete_stmt;
delete_stmt: DELETE {pp->st->type = ST_DELETE;} delete_sql;
delete_sql:...

这样在碰到第一个SELECT的时候只需要去判别 变量pp->st->type是否被设置,如果没有设置那么将它设置为ST_SELECT并且按照select语句来处理,否则就是按照子查询来处理了。

问题2的关键在于在括号中的子查询如何处理,例如 expr: expr in ( sub_query);
bison无法区分这个括号是属于 in这个操作符的还是select语句自己带的。 为了解决这个问题,我参考了postgresql的解析器代码.
具体的解决办法是把select语句分为2种,不带扩号的select和带括号的select,并且定义select语句的优先级低于普通的括号。 
...
%right      USELECTMINUS
%left    '(' ')'
...
select_stmt: select_no_parens    %prec USELECTMINUS
    select_with_parens  %prec USELECTMINUS
   
...

在这个基础上postgresql将所有 ( sub_query) 看作 select_with_parens。
这么做主要是为了避免冲突,但由于我的语法树和postgresql的不一样,我只需要配置select语句的优先级低于普通括号的优先级就可以了。

问题3主要的问题在于语句 “select a from t1 union select b from t2 limit3 ”需要被解析成:
  “(select a from t1 union select b from t2) limit 3”
而不是 :
“(select a from t1) union (select b from t2 limit 3)”
这个问题目前我没有太完美的解决它,一个折中的方案是 union后面的那个select语句必须是带括号的select语句,即select_with_parens。


以下是具体的select语法定义:

...
%right      USELECTMINUS
%left      UNION
%left    '(' ')'
...

select_stmt: select_no_parens    %prec USELECTMINUS
    select_with_parens  %prec USELECTMINUS
    select_union
    ;

select_union: select_stmt UNION opt_all select_with_parens opt_groupby opt_having opt_orderby opt_limit %prec UNION;

select_with_parens: '(' select_no_parens ')'
    '(' select_with_parens ')'
    ;

subquery_stmt_no_parens: select_no_parens;

subquery_stmt: select_stmt;

select_no_parens: select_query
        ;

select_query: SELECT
{
 
} query_part
    ;

query_part: select_opts select_expr_list opt_limit
                                      |
                                      select_opts select_expr_list
    FROM table_references
    opt_where opt_groupby opt_having opt_orderby opt_limit
    opt_into_list
                                      |
                                      select_opts select_expr_list INTO column_list
    FROM table_references
    opt_where opt_groupby opt_having opt_orderby opt_limit
                                      ;
....

expr: expr IN '(' subquery_stmt ')';

....

转载请注明出自高孝鑫的博客。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值