• 再读simpledb 之 SQL语句解析(2)


    (1)里面提到,lexer作为一个工具,完成了对SQL字符串的切割,将语句转化成一个tokens数组。

    Parser完成了SQL解析的后序部分:使用一个lexer对象作为工具,切出tokens,然后解析语义,绑定相关的系统接口。

    在这里先要回顾下simpledb的支持的SQL的语法,这个影响了它在解析字符串时使用的方法。

    <Query>      := SELECT <SelectList> FROM <TableList> [ WHERE <Predicate> ]
    <SelectList> := <Field> [ , <SelectList> ]
    <TableList>  := TableName [ , <TableList> ]
    <Predicate>  := <Term> [ AND <Predicate> ]
    <Term>       := <Expression> = <Expression>
    <Expression> := <Field> | <Constant>
    <Field>      := FieldName
    <Constant>   := String | Integer
     
    <Modify>     := <Insert> | <Delete> | <Update> 
    <Insert>     := INSERT INTO TableName ( <FieldList> ) VALUES ( <ConstList> )
    <FieldList>  := <Field> [ , <FieldList> ]
    <ConstList>  := <Constant> [ , <Constant> ]
    <Delete>     := DELETE FROM TableName [ WHERE <Predicate> ]
    <Update>     := UPDATE TableName SET <Field> = <Expression> [ WHERE <Predicate> ]
     
    <Create>     := <CreateTable> | <CreateView> | <CreateIndex>
    <CreateTable>:= CREATE TABLE TableName ( <FieldDefs> )
    <FieldDefs>  := <FieldDef> [ , <FieldDefs> ]
    <FieldDef>   := FieldName <TypeDef>
    <TypeDef>    := INT | VARCHAR ( Integer )
    <CreateView> := CREATE VIEW ViewName AS <Query>
    <CreateIndex>:= CREATE INDEX IndexName ON TableName ( <Field> )

    Parser这里实现的编译技术中的“一趟编译”,即通过lex顺序扫描tokens数组,在扫描过程中完成对各个token元素的识别,按照

    constant/field –> Expression –> Term –> Predicate

    的层递关系,完成参数包装,输出一个查询关联的数据类,如(1)中的类图1所示。

    首先,以(1)图2的例子“select sid,sname from students where sid='10001' ”,给出一个parser解析过程中构建的语法树:

    图1 示例语法树

    以下是Query方法的代码:

    public QueryData query()
    {
        lex.eatKeyword("select");
        List<string> fields = selectList();
        lex.eatKeyword("from");
        List<string> tables = tableList();
        Predicate pred = new Predicate();
        if (lex.matchKeyword("where"))
        {
            lex.eatKeyword("where");
            pred = predicate();
        }
        return new QueryData(fields, tables, pred);
    }

    由代码和上面的语法树看出来,simpledb在解析SQL语句的时候,严格按照语法中支持的类型,“卡住”关键字,从中解析出字段列表fieldlist,表名列表tablelist,以及谓词列表predicates,然后将这些查询中实际用到的数据,包装成相应的对象,SQL语句的解析就初步完成。以上面的例子为例,QueryData对象包装完之后,会传递给查询处理模块,通过query下的一些方法,根据fieldlist,tablelist,和predicates来完成查询数据的读取。

    parser中create(), delete(), insert(),query(), modify()方法,对应了上面的几类语法

    作为SQL语句解析的入口,有如下的updateCMD方法,根据SQL语句首个token的不同,进行了分支:

    public object updateCmd()
    {
        if (lex.matchKeyword("insert")) 
            return insert();
        else if (lex.matchKeyword("delete"))
            return delete();
        else if (lex.matchKeyword("update"))
            return modify();
        else
            return create();
    }

    补充一点,注意下上面的query()的代码,lex用match*()来检测下一个token是否满足匹配条件,用eat*()来讲满足条件的token处理掉:

    public void eatDelim(char d);
    public string eatId();
    public int eatIntConstant()
    public void eatKeyword(string w)
    public string eatStringConstant()

     数据相关的,均有返回值,返回处理后的结果;数据无关的,没有返回值,实际只是利用nextToken移动position指针。

    关于tablelist、fieldlist的构建,使用了递归的方式实现:

    private List<string> fieldList()
    {
        List<string> l = new List<string>();
        l.Add(field());
        if (lex.matchDelim(','))
        {
            lex.eatDelim(',');
            l.AddRange(fieldList());
        }
        return l;
    }

    谓词 predicates也是用了递归的形式:

    private Predicate predicate()
    {
        Predicate pred = new Predicate(term());
        if (lex.matchKeyword("and"))
        {
            lex.eatKeyword("and");
            pred.conjoinWith(predicate());
        }
        return pred;
    }

     略有不同的是,在谓词连接的时候,使用了Predicate类的conjoinwith方法,实际上,predicate对象下,维护了一个条件列表terms,这个方法就是把谓词中的各个term转存到一起。

    本文和前一节只是扼要地描述了SQL语句解析的思路和过程,可以看到解析的结果就是生成了各种查询data,这些data会传递给query模块,由query模块利用这些得到的data,完成数据的查询。

  • 相关阅读:
    [转]用异或交换两个整数的陷阱
    线索化二叉树
    [转]Socket编程中,阻塞与非阻塞的区别
    两个链表的归并
    [转] std::string and stl 算法
    类图
    leetcode 答案
    about raw socket
    54. Spiral Matrix【数组】
    矩阵乘法问题的实现
  • 原文地址:https://www.cnblogs.com/YFYkuner/p/2682656.html
Copyright © 2020-2023  润新知