Druid SQL 解析器概覽


概覽

Druid 的官方 wiki 對 SQL 解析器部分的講解內容並不多,但雖然不多,也有利於完全沒接觸過 Druid 的人對 SQL 解析器有個初步的印象。

說到解析器,腦海里便很容易浮現 parser 這個單詞,然后便很容易聯想到計算機科學中理論性比較強的學科------編譯原理。想必很多人都知道(即使不知道,應該也耳濡目染)能夠手寫編譯器的人並不多,並且這類人呢,理論知識和工程能力都比較強。在缺乏人力的條件下,大多數時候實現一個編譯器,往往是選擇采用一些工具,比如說 ANTLR,只需要描述好語法規則,這個工具就能生成對應的編譯器。

不過,Druid 的 SQL 解析器是手寫的,官方宣稱性能是 ANTLR 這類工具的10倍以上。

解析器組成部分

在 Druid 的 SQL 解析器中,有三個重要的組成部分,它們分別是:

  • Parser

    • 詞法分析

    • 語法分析

  • AST(Abstract Syntax Tree,抽象語法樹)

  • Visitor

這三者的關系如下圖所示:

Parser 由兩部分組成,詞法分析和語法分析。
當拿到一條形如 select id, name from user 的 SQL 語句后,首先需要解析出每個獨立的單詞,select,id,name,from,user。這一部分,稱為詞法分析,也叫作 Lexer。
通過詞法分析后,便要進行語法分析了。
經常能聽到很多人在調侃自己英文水平很一般時會說:26個字母我都知道,但是一組合在一起我就不知道是什么意思了。這說明他掌握了詞法分析的技能,卻沒有掌握語法分析的技能。
那么對於 SQL 解析器來說呢,它不僅需要知道每個單詞,而且要知道這些單詞組合在一起后,表達了什么含義。語法分析的職責就是明確一個語句的語義,表達的是什意思。
自然語言和形式語言的一個重要區別是,自然語言的一個語句,可能有多重含義,而形式語言的一個語句,只能有一個語義;形式語言的語法是人為規定的,有了一定的語法規則,語法解析器就能根據語法規則,解析出一個語句的一個唯一含義。

AST 是 Parser 的產物,語句經過詞法分析,語法分析后,它的結構需要以一種計算機能讀懂的方式表達出來,最常用的就是抽象語法樹。
樹的概念很接近於一個語句結構的表示,一個語句,我們經常會對它這樣看待:它由哪些部分組成?其中一個組成部分又有哪些部分組成?例如一條 select 語句,它由 select 列表、where 子句、排序字段、分組字段等組成,而 select 列表則由一個或多個 select 項組成,where 子句又由一個或者多個 where條件組成。
在我們人類的思維中,這種組成結構就是一個總分的邏輯結構,用樹來表達,最合適不過。並且對於計算機來說,它顯然比人類更擅長處理“樹”。

AST 僅僅是語義的表示,但如何對這個語義進行表達,便需要去訪問這棵 AST,看它到底表達什么含義。通常遍歷語法樹,使用 VISITOR 模式去遍歷,從根節點開始遍歷,一直到最后一個葉子節點,在遍歷的過程中,便不斷地收集信息到一個上下文中,整個遍歷過程完成后,對這棵樹所表達的語法含義,已經被保存到上下文了。有時候一次遍歷還不夠,需要二次遍歷。遍歷的方式,廣度優先的遍歷方式是最常見的。

快速上手

使用 Druid SQL Parser 來解析 SQL 語句,一般需要進行以下幾個步驟:

  1. 新建一個 Parser

  2. 使用 Parser 解析 SQL,生成 AST

  3. 使用 Visitor 訪問 AST

如下代碼所示:

package io.beansoft.demo;

import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlSchemaStatVisitor;
import com.alibaba.druid.sql.parser.SQLStatementParser;

/**
 *
 *
 * @author beanlam
 * @date 2017年1月10日 下午11:06:26
 * @version 1.0
 *
 */
public class ParserMain {

    public static void main(String[] args) {
        String sql = "select id,name from user";

        // 新建 MySQL Parser
        SQLStatementParser parser = new MySqlStatementParser(sql);

        // 使用Parser解析生成AST,這里SQLStatement就是AST
        SQLStatement statement = parser.parseStatement();

        // 使用visitor來訪問AST
        MySqlSchemaStatVisitor visitor = new MySqlSchemaStatVisitor();
        statement.accept(visitor);
                
        // 從visitor中拿出你所關注的信息        
        System.out.println(visitor.getColumns());
    }
}

以上代碼運行后控制台的輸出為

[user.id, user.name]

當然,不使用 Visitor,直接操作 AST 也可以得到 SQL 語句的信息,在 Druid 現有內置的 Visitor 不能滿足需求時,可以自己去實現 Visitor,對於用 Visitor 無法解析到的信息,可以直接訪問 AST 去獲取。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM