KaiwuDB 支援多種不同型別的 SQL 語句,如 create、insert 等。 本文介紹在 KaiwuDB SQL 解析器(以下簡稱解析器)中新增新語句的流程及其實現。 我們將了解如何使用 goyacc 工具更新解析器,以及執行器和查詢計畫器如何協同工作來執行此語句。
新增新的 SQL 語句首先要向 SQL 解析器新增必要的語法。 解析器由 goyacc 生成,goyacc 是流行的 yacc 編譯器的 go 版本。 語法定義位於 pkg sql parser sql 中y 檔案。 解析器的輸出是乙個抽象語法樹 (AST),其中節點型別在 pkg SQL SEM 樹目錄中的各種檔案中定義。
向 SQL 解析器新增新語句有三個主要元件:新增新關鍵字、向解析器新增語法以及新增新的語法節點型別。
在此示例中,我們將使用 KaiwuDB 中的乙個新語句:frobnicate。 此語句將隨機修改資料庫的設定。 它將有三個選項:frobnicate cluster,用於操作集群設定;frobnicate session,用於操作會話設定;frobnicate all,用於同時處理兩者。
讓我們首先檢查是否定義了所有關鍵字。 開啟 pkg sql 解析器 sqlY 檔案和搜尋"ordinary key words"。您將看到一系列按字母順序排列的標記定義。 由於其他語法已經定義了會話、集群和所有關鍵字,因此我們不需要新增它們,但我們確實需要為 frobnicate 建立乙個關鍵字。 它應如下所示:
%token frobnicate這告訴詞法分析器識別關鍵字,但我們仍然需要將其新增到其中乙個類別列表中。 如果關鍵字可以出現在識別符號位置,則必須保留該關鍵字(這要求必須將其引在引號中才能用於其他用途,例如作為列名)。 由於我們的新關鍵字用作 SQL 語句的開頭,因此它不會被誤認為是識別符號,因此我們可以安全地將其新增到非保留關鍵字列表中。 在 pkg sql 解析器 sql 中yfile,搜尋 unreserved 關鍵字: 並新增 |,如下所示 frobnicate:
unreserved_keyword:
frobnicate
現在詞法分析器知道了我們所有的關鍵字,我們需要教解析器如何處理我們的新語句。 我們需要在三個地方新增引用:語句型別列表、語句大小寫列表和解析子句。
在語法檔案 (pkg sql parser sqly),您將找到型別列表。新增一行關於我們的新語句型別,如下所示:
%type frobnicate_stmt因此,我們將建立乙個新的語句型別"frobnicatestmt"新增了型別宣告。 請注意"frobnicatestmt"只是乙個示例名稱,您可以根據自己的實際情況進行自定義。
接下來,我們需要將新的語句型別新增到語句大小寫的列表中。 繼續搜尋語法檔案並找到它"stmt"(例如 stmt select、stmt insert 等)。 將以下情況新增到這些規則中:
stmt:
frobnicate_stmt // extend with help: frobnicate
最後,我們需要在語句中新增乙個生成規則。 在 pkg sql 解析器 sql 中Y 檔案:
frobnicate_stmt:
frobnicate cluster
frobnicate session
frobnicate all
以下是我們允許的三個表示式的列表,用垂直字元分隔。 每個生成器還有乙個用大括號括起來的實現(它暫時報告錯誤並顯示“未實現”錯誤訊息)。
最後,將幫助文件新增到我們的宣告中。 在我們剛剛新增的生成規則上方,新增以下注釋:
// %help: frobnicate - twiddle the various settings
category: misc
text: frobnicate
現在,我們的解析器將能夠識別新的句子型別,並生成一些關於新語法的注釋,以幫助使用者。 重新編譯後,嘗試執行此語句,得到如下結果:
$ kwbase sql --insecure -e "frobnicate cluster"
error: at or near "cluster": syntax error: unimplemented: this syntax
sqlstate: 0a000
detail: source sql:
frobnicate cluster
這意味著我們的新語法已成功解析,但我們無法執行任何操作,因為它尚未實現。
現在新增了語法層,我們需要為新語句提供適當的語義。 我們需要乙個 ast 來將語句的結構從解析器傳遞到執行時。 如上所述,我們的語句是 %type,這意味著它需要實現 tree語句介面,可以在 PKG SQL SEM 樹 stmt 中找到去。
我們需要編寫四個函式:三個用於 Statement 介面本身(StatementReturnType、StatementType 和 StatementTag),乙個用於 NodeFormatter(Format) 和標準 FMTstringer。
請為我們的語句型別建立乙個新檔案:pkg sql sem tree frobnicatego。在其中,輸入我們 AST 節點的格式和定義。
package tree
type frobnicate struct
type frobnicatemode int
const (
frobnicatemodeall frobnicatemode = iota
frobnicatemodecluster
frobnicatemodesession
func (node *frobnicate) format(ctx *fmtctx)
要向 ast 樹新增語句和字串表示形式,請開啟 pkg sql sem tree stmt轉到檔案並搜尋 StatementReturnType 實現 Statement 介面。 現在,您可以看到不同型別 AST 的實現列表。 按字母順序插入以下內容:
func (node *frobnicate) statementreturntype() statementreturntype
statementtype implements the statement interface.
func (node *frobnicate) statementtype() statementtype
statementtag returns a short string identifying the type of statement.
func (node *frobnicate) statementtag() string
接下來,按字母順序新增以下內容:
func (n *frobnicate) string() string現在,我們需要更新解析器,以便在遇到語法時返回具有適當模式型別的 frobnicate 節點 (AST)。 返回 pkg sql 解析器 sqly 檔案,搜尋 %help: frobnicate,並將語句替換為以下內容:
frobnicate_stmt:
frobnicate cluster }
frobnicate session }
frobnicate all }
特殊符號 $$val 表示此規則生成的節點值。 還有一些其他的 $ 符號可以在 yacc 中使用。 一種更有用的形式是引用子生成器的節點值(例如,在這三個語句中,$1 將是令牌的 frobnicate)。
接下來,重新編譯 kaiwudb 並重新輸入新語法,得到如下結果:
$ kwbase sql --insecure -e "frobnicate cluster"
error: pq: unknown statement type: *tree.frobnicate
failed running "sql"
現在我們看到的錯誤與以前不同。 此錯誤來自 SQL Planner,當遇到新的語句型別時,它不知道該怎麼做。 我們需要教它新語句的含義。 儘管我們的語句在任何查詢計畫中都不起作用,但我們將通過向計畫器新增方法來實現。 這是集中式語句的分發位置,因此語義被新增到那裡。
找到我們當前看到的錯誤的來源**,你會看到它位於 pkg sql opaque 中在 go 檔案中一長串型別選擇語句的末尾。 讓我們新增乙個案例:
case *tree.frobnicate:
return p.frobnicate(ctx, n)
同樣,在同一檔案中 pkg sql 不透明Go 的 init() 函式:
&tree.frobnicate{},這將在規劃器本身(尚未實現)上呼叫乙個方法。 讓我們從 pkg sql frobnicate 開始GO 檔案。
package sql
import (
context"
github.com/kwbasedb/kwbase/pkg/sql/sem/tree"
github.com/kwbasedb/errors"
func (p *planner) frobnicate(ctx context.context, stmt *tree.frobnicate) (plannode, error) {
return nil, errors.assertionfailedf("we're not quite frobnicating yet...")
此時,重新編譯 kaiwudb 並再次執行語句:
$ kwbase sql --insecure -e "frobnicate cluster"
error: pq: we're not quite frobnicating yet...
failed running "sql"
此時,我們已經能夠將錯誤傳遞給 SQL 客戶端。 我們只需要新增上面的介面函式,就可以使語句生效。