Databend Parser 快速入門(mén)
作者:謝其駿
北京航空航天大學(xué)在讀碩士,?Databend 研發(fā)工程師實(shí)習(xí)生
https://github.com/jun0315
基本介紹
Parser 模塊主要負(fù)責(zé)將 SQL 字符串經(jīng)過(guò)詞法分析得到的 Token 列表轉(zhuǎn)換為 AST(抽象語(yǔ)法樹(shù))的過(guò)程。
下面是函數(shù)定義:
parse_sql
接受兩個(gè)參數(shù):sql_tokens
和 dialect
,返回一個(gè) Result
,其中包含一個(gè) Statement
和一個(gè)可選的輸出格式String
(如 CSV 格式等)。
sql_tokens
參數(shù)是一個(gè)對(duì) SQL 語(yǔ)句進(jìn)行詞法分析之后得到的Token
數(shù)組,令牌包含關(guān)鍵字、標(biāo)識(shí)符、運(yùn)算符等信息。
dialect
參數(shù)表示 SQL 方言,Rust 提供了幾種常見(jiàn)的方言,比如 SQLite、MySQL 等。
parse_sql
函數(shù)的主要作用是將 SQL 的 Token 解析為 AST( Abstract Syntax Tree 抽象語(yǔ)法樹(shù))。AST 是一個(gè)用于表示程序語(yǔ)言語(yǔ)法結(jié)構(gòu)的樹(shù)形數(shù)據(jù)結(jié)構(gòu),它的節(jié)點(diǎn)代表程序語(yǔ)法的不同部分,通過(guò)這個(gè)數(shù)據(jù)結(jié)構(gòu)可以更方便地對(duì)程序語(yǔ)言進(jìn)行分析和處理。
Nom 庫(kù)
Databend 的 Parser 模塊主要使用了nom 庫(kù)和 nom-rule 庫(kù)。
nom
是一個(gè)基于parser
組合器的庫(kù),它允許開(kāi)發(fā)者定義小型的 parser,然后將它們組合成更復(fù)雜的 parser。
nom-rule
是基于 nom
庫(kù)的一個(gè)規(guī)則引擎庫(kù),可以用于語(yǔ)法分析、解析和轉(zhuǎn)換。它提供了一種聲明式的方式來(lái)定義語(yǔ)法規(guī)則,同時(shí)支持錯(cuò)誤處理和自定義語(yǔ)法擴(kuò)展。
2.1 parser
在 nom 中,parser
是一個(gè) trait,定義了一個(gè)通用的解析器接口,任何實(shí)現(xiàn)了該 trait 的解析器都可以用于解析。這個(gè) trait 定義了一個(gè)名為parse
的方法,該方法接受一個(gè)輸入數(shù)據(jù),進(jìn)行解析,返回一個(gè)IResult
類(lèi)型的結(jié)果,I、O 和 E 分別表示剩余未解析的數(shù)據(jù)、解析結(jié)果和錯(cuò)誤類(lèi)型。
接下來(lái),我們將介紹一些 Databend 中用到的重要的 parser 組件。
2.2 map
map
組件是一個(gè)函數(shù)式編程工具,用于將解析器解析出的數(shù)據(jù)轉(zhuǎn)換為其他類(lèi)型或格式。map
組件接受兩個(gè)參數(shù):一個(gè)解析器和一個(gè)函數(shù),用于將解析器的結(jié)果轉(zhuǎn)換為另一種格式。
map
組件的函數(shù)參數(shù)是一個(gè)閉包,它接受解析器解析出的數(shù)據(jù),并將其轉(zhuǎn)換為其他類(lèi)型或格式。通常,閉包的返回值將成為解析器的最終結(jié)果。下面是一個(gè)簡(jiǎn)單的示例:
在這個(gè)例子中,首先使用了 nom 中的digit1
parser 組件來(lái)解析連續(xù)的數(shù)字字符,然后使用map
組件對(duì)解析結(jié)果進(jìn)行轉(zhuǎn)換,將數(shù)字字符串的長(zhǎng)度作為解析結(jié)果返回。
2.3 alt
alt
是一個(gè)組合子,它用于在多個(gè)解析器之間進(jìn)行選擇。它接受兩個(gè)或多個(gè)解析器作為參數(shù),并依次嘗試將輸入數(shù)據(jù)解析為這些解析器中的一個(gè),返回第一個(gè)成功解析的結(jié)果。下面是一個(gè)簡(jiǎn)單的示例:
在這個(gè)例子中,我們使用alt
組件將兩個(gè) parser 拼接在一起:alpha1
和digit1
。這兩個(gè) parser 都是 nom 中的字符解析器,alpha1
解析一個(gè)或多個(gè)字母,digit1
解析一個(gè)或多個(gè)數(shù)字。因此,alt
嘗試首先使用alpha1
解析輸入,如果解析成功,則返回其結(jié)果(即解析的字母字符串)。否則,alt
將使用digit1
解析輸入,如果解析成功,則返回其結(jié)果(即解析的數(shù)字字符串)。如果兩個(gè) parser 都解析失敗,則返回一個(gè)錯(cuò)誤。
2.4 tuple
tuple
是一個(gè)組合子,用于將多個(gè)解析器按順序組合起來(lái),形成一個(gè)元組。
除了可以嵌套多個(gè)解析器之外,tuple
還支持使用 map
函數(shù)對(duì)解析結(jié)果進(jìn)行轉(zhuǎn)換。
這段代碼演示了如何使用tuple
組合子將多個(gè)解析器按順序組合起來(lái)。tuple
會(huì)將多個(gè)解析器打包成一個(gè)元組返回,元組中包含了每個(gè)解析器的結(jié)果。
在上面的例子中,tuple
包含了三個(gè)解析器:alpha1
,digit1
和另一個(gè)alpha1
。它們按順序解析輸入字符串中的字符,并將結(jié)果打包成一個(gè)三元組。
2.5 rule!
rule! 首先給定了 match_text(匹配文本)和 match_token(匹配 TokenKind )的方法,接著再調(diào)用nom_rule
中的 rule 宏定義,這樣可以方便的拼裝成上文提到的tuple
組合子。
舉例如下
最終會(huì)被展開(kāi)為?
摘自https://github.com/andylokandy/nom-rule#example
源碼分析
在了解了 parser 組件之后,我們繼續(xù)探究實(shí)際的源碼。
在parser_sql
函數(shù)中,調(diào)用了statement(Input(sql_tokens, dialect, &backtrace))
。
statement
函數(shù)實(shí)際上解析 token 的地方:
通過(guò)調(diào)用 rule 宏定義,解析statement_body
,而statement
也是用 alt 組件拼成的多個(gè) parser 。
每一個(gè) parser,如第六行的delete
都是 map 組件,會(huì)轉(zhuǎn)換成Statement
。delete
會(huì)最終轉(zhuǎn)換成Statement::Delete
。
最終通過(guò)拼裝出來(lái)的 parser 來(lái)轉(zhuǎn)換成Statement
。至此,整個(gè) Parser 解析的過(guò)程就完成了。
關(guān)于?Databend
Databend 是一款開(kāi)源、彈性、低成本,基于對(duì)象存儲(chǔ)也可以做實(shí)時(shí)分析的新式數(shù)倉(cāng)。期待您的關(guān)注,一起探索云原生數(shù)倉(cāng)解決方案,打造新一代開(kāi)源 Data Cloud。
???????Databend Cloud:https://databend.cn
???Databend 文檔:https://databend.rs/
???Wechat:Databend
??GitHub:https://github.com/datafuselabs/databend