再讀simpledb 之 SQL語句解析(1)

來源:互聯網
上載者:User

前面的幾個部分,基本實現了資料的讀寫。對於資料庫使用者來說,SQL(Structured Query Language)是訪問資料庫的視窗,這一節就來看下simpledb對SQL語句的解析。

首先要說的是,simpledb實現了一個SQL-92的子集,具體支援的文法如下所示:

   1:  

   2: <Query>      := SELECT <SelectList> FROM <TableList> [ WHERE <Predicate> ]

   3: <SelectList> := <Field> [ , <SelectList> ]

   4: <TableList>  := TableName [ , <TableList> ]

   5: <Predicate>  := <Term> [ AND <Predicate> ]

   6: <Term>       := <Expression> = <Expression>

   7: <Expression> := <Field> | <Constant>

   8: <Field>      := FieldName

   9: <Constant>   := String | Integer

  10:  

  11: <Modify>     := <Insert> | <Delete> | <Update> 

  12: <Insert>     := INSERT INTO TableName ( <FieldList> ) VALUES ( <ConstList> )

  13: <FieldList>  := <Field> [ , <FieldList> ]

  14: <ConstList>  := <Constant> [ , <Constant> ]

  15: <Delete>     := DELETE FROM TableName [ WHERE <Predicate> ]

  16: <Update>     := UPDATE TableName SET <Field> = <Expression> [ WHERE <Predicate> ]

  17:  

  18: <Create>     := <CreateTable> | <CreateView> | <CreateIndex>

  19: <CreateTable>:= CREATE TABLE TableName ( <FieldDefs> )

  20: <FieldDefs>  := <FieldDef> [ , <FieldDefs> ]

  21: <FieldDef>   := FieldName <TypeDef>

  22: <TypeDef>    := INT | VARCHAR ( Integer )

  23: <CreateView> := CREATE VIEW ViewName AS <Query>

  24: <CreateIndex>:= CREATE INDEX IndexName ON TableName ( <Field> )

simpledb中的parse模組完成瞭解析的功能,類圖如下:

圖1 parse類圖

在開始之間,先想一下SQL語句的解析,主要的工作是:

通過對輸入SQL語句字串的分割等工作,

首先,對輸入SQL語句字串的分割等工作;

然後,識別出語句執行的是CRUD中的哪個動作,識別出資料庫操作關聯的表和相關的資料;

最後,把識別出的表和資料傳遞給系統的相關介面,完成查詢。

結合上面的類圖,可以分三類:lexer、parser工具類,完成了SQL的解析;*Data,SQL解析成果的載體;BadSyntaxException,語法錯誤異常類。

下面,先從工具類說起:

> lexer

用編譯原理的知識說來,這是個詞法分析器,主要負責把輸入的SQL字串切割開,

第一步,將SQL字串使用指定的分割符進行分割,將結果儲存在一個叫tokens的string數組中

圖2 lexer分割SQL

分割過程2所示,利用Regex,將SQL字串分割。

\s{1}|(,){1}|(=){1}|(\(){1}|(\)){1}|('[^']*'){1}

圖3 SQL to tokens分割過程用到的RE

圖4 實際運行時tokens結果

 

圖5 惡意輸入的結果

( 在面試的時候,問過我一個問題,如果有使用者而已輸入,輸入了N多個空格,隔斷了select語句的field-list,該怎麼辦?

select sid,            sname from     students where sid='10001'

實際上,在上面這個步驟,把所有的單元都獨立分出來,5所示,每個空格都佔一個tokens的位置。但是,lexer有一個nextToken方法,能有效地過濾掉這些幹擾:

private void nextToken()

{

    position++;

    while (position < tokens.Length && tokens[position].Length == 0)

        position++;

}

 

之後,lexer通過以下的演算法,實現對各種字串片段的處理

(注意:lexer下有tokens數組的指標position,指向了lexer當前處理的tokens數組中的元素)

1、定位到下一個處理元素token,使用nextToken()方法
2、匹配token,使用match*()方法

3、處理token,使用eat*()方法

在match階段,用到了如下的RE來對字串片段進行匹配:

private const string intPattern = @"^[-+]?(0|[1-9]\d*)$";

private const string stringPattern = @"^'[^']*'$";

private const string idPattern = @"^[a-zA-Z_]\w*$"

private const string keywordPattern = @"^[a-zA-Z]*$";

simpledb支援的SQL關鍵字如下:

string[] keywords = {"select","from","where","and","insert","into","values",

"delete","update","set","create","table","varchar","view","as","index","on"};

在eat階段,

總共有5個eat方法:eatDelim(char) eatId() eatIntConstant() eatKeyword(string) eatStringConstant,其中eatDelim和eatKeyword,有參數輸入,根據參數的不懂,吃掉相應的分隔字元或關鍵字,其他的,只是利用position,將position指向的token解析對指定的int或string。

可以說,lexer為SQL的解析完成了第一步的工作。

 

明天得早起,先到這裡,待續。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.