现在的位置: 首页 > 综合 > 正文

CUBRID的语法分析和检测

2013年12月09日 ⁄ 综合 ⁄ 共 2861字 ⁄ 字号 评论关闭

作者:王东

 

就像是我们使用编译器编译c, cpp文件一样, 对查询语句的编译过程也分为了如下几部分:

l  词法分析;

l  语法分析;

l  语义分析和检测;

l  查询重写;

l  生成查询计划;

l  挑选和优化查询计划;

 

这里主要是针对 前三步 进行说明。

 

当我们输入一个SQL语句时, CUBRID的查询编译器会按照类似代码编译器的方式进行工作。

1.         首先进行词法分析,词法分析的目标是将SQL语句进行扫描并分割成为一系列记号(Token),在CUBRID,是使用Flex生成的文件进行词法分析的。Flex(fast lexical analyser generator)是一个自动的词法分析器生成器(参考附1)。在CUBRID中,有一个描述SQL词法的.l 文件,该文件描述了SQL语句中用的词汇。通过使用Flex,并输入.l 文件,将生成对应的可以用的编译的.c文件。词法分析的结果产生了各种记号(Token), 例如:关键字,标识符,字符串等等;

2.         接下来进行语法分析。语法分析是将词法分析产生的记号(Token)按照语法要求生成语法树(Syntax Tree)CUBRID 中采用bison来进行语法分析(参考附录2)。类似于编译器中的表达式一样,不同的SQL语句,将被看作为不同表达式(Expression)CUBRID中有一个描述语法的.y文件,该文件中包含表达式树是如何组织起来的代码。通过bison,并输入.y文件,生成对应可以用于编译的.c.h文件。这样SQL就被组织成语法树的结构了。

3.         接下来就是对语法树进行语义检测(Semantic analysis and check)。因为语法分析中只是完成了对表达式语法层面的分析,并没有对真正这条语句的内容是否合法进行检测。 CUBRID 里面的Semantic check, 是对生成的语法树进行遍历和检查。由于树的节点不同,对每个节点的遍历算法也是不同的。语义检测的结果是对不满足输入的SQL语句进行过滤(提示报错),对语法树进行适当的扩充和删减,便与接下来的生成查询计划等工作。

 

接下来就进行查询重写,生成查询计划其他了操作。这里暂且不提。

下面就这三部分给出CUBRID中实现的三个例子。

 

例子1  CUBRID词法分析

.l 文件是由正则表达式和c语法组成的。

//定义段代码

%{

//定义include文件,宏,辅助函数,flex会跳过对这些的处理。

#include "csql_grammar.h"

#include "parse_tree.h"

#define CSQL_MAXNAME 256

static int parser_yyinput_single_line(char* buff, int max_size);

 

extern int yyline;

//……

%}

// 词法规则段代码

%%

[sS][eE][lL][eE][cC][tT]    { begin_token(yytext);   return SELECT; }

([a-zA-Z_#]|(/xa1[/xa2-/xee/xf3-/xfe])|([/xa2-/xfe][/xa1-/xfe])|(/x8e[/xa1-/xfe]))([a-zA-Z_#0-9]|(/xa1[/xa2-/xfe])|([/xa2-/xfe][/xa1-/xfe])|(/x8e[/xa1-/xfe]))*

{ begin_token(yytext);

                     if (strlen(yytext) >= 254)

                         yytext[254] = 0;

                     csql_yylval.cptr = pt_makename(yytext);

                     return IdName;

                  }

%%

通过编辑.l文件,我们可以定义我们感兴趣的token

生成的c代码,如下:

case 338:

YY_RULE_SETUP

#line 537 "../../src/parser/csql_lexer.l"

{ begin_token(yytext);   return SELECT; }

    YY_BREAK

 

 

例子2 CUBRID语法分析

.y 文件定义语法树表达方式, 其中包含了Token, rule type, rule的组织方式. 例子中,select 语句的节点中就包含很多内容。

 

/* Token define */

/*{{{*/

%token SELECT

%token IdName

/* define rule type (node) */

/*{{{*/

%type <node> stmt_

%type <node> create_stmt

%type <node> select_stmt

 

stmt_

    : create_stmt

       { $$ = $1; }

    | select_stmt

       { $$ = $1; }

    ;

 

select_stmt

    : SELECT                     /* $1 */

       {{                       /* $2 发现是select语句,就创建select节点*/

           PT_NODE *node = parser_new_node (this_parser, PT_SELECT);

           

       DBG_PRINT}}

   

    select_list                  /* $5 */

       {{                       /* $6 创建select 选项的列表节点*/

           PT_NODE *node = parser_top_select_stmt_node ();

           if (node)

             {

               node->info.query.q.select.list = $5;

             }

       DBG_PRINT}}

    opt_select_param_list       /* $7 */

    FROM                         /* $8 */

   

    opt_where_clause             /* $11 where语句对应的节点*/

   

    opt_groupby_clause           /* $14 group语句对应的节点*/

    opt_having_clause            /* $16 having语句对应的节点*/

   

       {{

           if (node)

             {

               node->info.query.into_list = $7;    /* param_list */

               node->info.query.q.select.where = $11;

抱歉!评论已关闭.