日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當前位置:首頁 > 科技  > 軟件

自己動手寫數據庫:解析 Select 語句并生成查詢樹

來源: 責編: 時間:2023-12-15 17:17:38 329觀看
導讀首先,我們需要給原來代碼打個補丁,在SelectScan 結構體初始化時需要傳入 UpdateScan 接口對象,但很多時候我們需要傳入的是 Scan 對象,因此我們需要做一個轉換,也就是當初始化 SelectScan 時,如果傳入的是 Scan 對象,那么我

首先,我們需要給原來代碼打個補丁,在SelectScan 結構體初始化時需要傳入 UpdateScan 接口對象,但很多時候我們需要傳入的是 Scan 對象,因此我們需要做一個轉換,也就是當初始化 SelectScan 時,如果傳入的是 Scan 對象,那么我們就將其封裝成 UpdateScan 接口對象,因此在 query 目錄下增加一個名為 updatescan_wrapper.go 的文件,在其中輸入內容如下:5Rx28資訊網——每日最新資訊28at.com

package queryimport (    "record_manager")type UpdateScanWrapper struct {    scan Scan}func NewUpdateScanWrapper(s Scan) *UpdateScanWrapper {    return &UpdateScanWrapper{        scan: s,    }}func (u *UpdateScanWrapper) GetScan() Scan {    return u.scan}func (u *UpdateScanWrapper) SetInt(fldName string, val int) {    //DO NOTHING}func (u *UpdateScanWrapper) SetString(fldName string, val string) {    //DO NOTHING}func (u *UpdateScanWrapper) SetVal(fldName string, val *Constant) {    //DO NOTHING}func (u *UpdateScanWrapper) Insert() {    //DO NOTHING}func (u *UpdateScanWrapper) Delete() {    //DO NOTHING}func (u *UpdateScanWrapper) GetRid() *record_manager.RID {    return nil}func (u *UpdateScanWrapper) MoveToRid(rid *record_manager.RID) {    // DO NOTHING}

上面代碼邏輯簡單,如果調用 Scan 對象接口時,他直接調用其 Scan 內部對象的接口,如果調用到 UpdateScan 的接口,那么它什么都不做。完成上面代碼后,我們在select_plan.go 中進行一些修改:5Rx28資訊網——每日最新資訊28at.com

func (s *SelectPlan) Open() interface{} {    scan := s.p.Open()    updateScan, ok := scan.(query.UpdateScan)    if !ok {        updateScanWrapper := query.NewUpdateScanWrapper(scan.(query.Scan))        return query.NewSelectionScan(updateScanWrapper, s.pred)    }    return query.NewSelectionScan(updateScan, s.pred)}

上面代碼在創建 SelectScan 對象時,先判斷傳進來的對象是否能類型轉換為 UpdateScan,如果不能,那意味著s.p.Open 獲取的是 Scan 對象,因此我們使用前面的代碼封裝一下再用來創建 SelectScan 對象。完成這里的修改后,我們進入正題。5Rx28資訊網——每日最新資訊28at.com

前面我們在實現 sql 解析器后,在解析完一條查詢語句后會創建一個 QueryData 對象,本節我們看看如何根據這個對象構建出合適的查詢規劃器(Plan)。我們將采取由簡單到負責的原則,首先我們直接構建 QueryData 的信息去構建查詢規劃對象,此時我們不考慮它所構造的查詢樹是否足夠優化,后面我們再慢慢改進構造算法,直到算法能構建出足夠優化的查詢樹。5Rx28資訊網——每日最新資訊28at.com

我們先看一個具體例子,假設我們現在有兩個表 STUDENT, EXAM,第一個表包含兩個字段分別是學生 id 和姓名:
id | name
———— | ——-
1 | Tom
2 | Jim
3 | John
5Rx28資訊網——每日最新資訊28at.com

第二個表包含的是學生 id,科目名稱,考試乘機:
stuid | exam|grad
———— | ——-|——-|
1 | math| A|
1 | algorithm| B
2 | writing| C |
2| physics| C|
3|chemical|B|
3|english| C|
5Rx28資訊網——每日最新資訊28at.com

現在我們使用 sql 語句查詢所有考試成績得過 A 的學生:5Rx28資訊網——每日最新資訊28at.com

select name from STUDENT, EXAM where id = student_id and grad='A'

當 sql 解釋器讀取上面語句后,他就會創建一個 QueryData 結構,里面 Tables 對了就包含兩個表的名字,也就是 STUDENT, EXAM。由于這兩個表不是視圖,因此上面代碼中判斷 if viewDef != nil 不成立,于是進入 else 部分,也就是代碼會為這兩個表創建對應的 TablePlan 對象,接下來直接對這兩個表執行 Product 操作,也就是將左邊表的一行跟右邊表的每一行合起來形成新表的一行,Product 操作在 STUDENT 和 EXAM 表后所得結果如下:
id|name|student_id | exam|grad
————|——-|———— | ——-|——-|
1|Tom|1|math|A|
1|Tom|1|algorithm|B|
1|Tom|2|writing|A|
1|Tom|2|physics|C|
1|Tom|3|chemical|B|
1|Tom|3|english|A|
…..|….|…..|…|…|
5Rx28資訊網——每日最新資訊28at.com

接下來代碼創建 ScanSelect 對象在上面的表上,接著獲取該表的每一行,然后檢測該行的 id 字段是否跟 student_id 字段一樣,如果相同,那么查看其 grad 字段,如果該字段是’A’,就將該行的 name 字段顯示出來。5Rx28資訊網——每日最新資訊28at.com

下面我們看看如何使用代碼把上面描述的流程實現出來。首先我們先對接口進行定義,在 Planner 目錄下的 interface.go 文件中增加如下內容:5Rx28資訊網——每日最新資訊28at.com

type QueryPlanner interface {    CreatePlan(data *query.QueryData, tx tx.Transaction) Plan}

接著在 Planner 目錄下創建文件 query_planner.go,同時輸入以下代碼,代碼的實現邏輯將接下來的文章中進行說明:5Rx28資訊網——每日最新資訊28at.com

package plannerimport (    "metadata_management"    "parser"    "tx")type BasicQueryPlanner struct {    mdm *metadata_management.MetaDataManager}func CreateBasicQueryPlanner(mdm *metadata_management.MetaDataManager) QueryPlanner {    return &BasicQueryPlanner{        mdm: mdm,    }}func (b *BasicQueryPlanner) CreatePlan(data *parser.QueryData, tx *tx.Transaction) Plan {    //1,直接創建 QueryData 對象中的表    plans := make([]Plan, 0)    tables := data.Tables()    for _, tblname := range tables {        //獲取該表對應視圖的 sql 代碼        viewDef := b.mdm.GetViewDef(tblname, tx)        if viewDef != nil {            //直接創建表對應的視圖            parser := parser.NewSQLParser(viewDef)            viewData := parser.Query()            //遞歸的創建對應表的規劃器            plans = append(plans, b.CreatePlan(viewData, tx))        } else {            plans = append(plans, NewTablePlan(tx, tblname, b.mdm))        }    }    //將所有表執行 Product 操作,注意表的次序會對后續查詢效率有重大影響,但這里我們不考慮表的次序,只是按照    //給定表依次執行 Product 操作,后續我們會在這里進行優化    p := plans[0]    plans = plans[1:]    for _, nextPlan := range plans {        p = NewProductPlan(p, nextPlan)    }    p = NewSelectPlan(p, data.Pred())    return NewProjectPlan(p, data.Fields())}

上面代碼中 QueryData就是解析器在解析 select 語句后生成的對象,它的 Tables 數組包含了 select 語句要查詢的表,所以上面代碼的 CreatePlan 函數先從 QueryData 對象獲得 select 語句要查詢的表,然后使用遍歷這些表,使用 NewProductPlan 創建這些表對應的 Product 操作,最后在 Product 的基礎上我們再創建 SelectPlan,這里我們就相當于使用 where 語句中的條件,在 Product 操作基礎上將滿足條件的行選出來,最后再創建 ProjectPlan,將在選出的行基礎上,將需要的字段選擇出來。5Rx28資訊網——每日最新資訊28at.com

下面我們測試一下上面代碼的效果,首先在 main.go 中,我們先把 student, exam 兩個表構造出來,代碼如下:5Rx28資訊網——每日最新資訊28at.com

func createStudentTable() (*tx.Transation, *metadata_manager.MetaDataManager) {    file_manager, _ := fm.NewFileManager("student", 2048)    log_manager, _ := lm.NewLogManager(file_manager, "logfile.log")    buffer_manager := bmg.NewBufferManager(file_manager, log_manager, 3)    tx := tx.NewTransation(file_manager, log_manager, buffer_manager)    sch := record_manager.NewSchema()    mdm := metadata_manager.NewMetaDataManager(false, tx)    sch.AddStringField("name", 16)    sch.AddIntField("id")    layout := record_manager.NewLayoutWithSchema(sch)    ts := query.NewTableScan(tx, "student", layout)    ts.BeforeFirst()    for i := 1; i <= 3; i++ {        ts.Insert() //指向一個可用插槽        ts.SetInt("id", i)        if i == 1 {            ts.SetString("name", "Tom")        }        if i == 2 {            ts.SetString("name", "Jim")        }        if i == 3 {            ts.SetString("name", "John")        }    }    mdm.CreateTable("student", sch, tx)    exam_sch := record_manager.NewSchema()    exam_sch.AddIntField("stuid")    exam_sch.AddStringField("exam", 16)    exam_sch.AddStringField("grad", 16)    exam_layout := record_manager.NewLayoutWithSchema(exam_sch)    ts = query.NewTableScan(tx, "exam", exam_layout)    ts.BeforeFirst()    ts.Insert() //指向一個可用插槽    ts.SetInt("stuid", 1)    ts.SetString("exam", "math")    ts.SetString("grad", "A")    ts.Insert() //指向一個可用插槽    ts.SetInt("stuid", 1)    ts.SetString("exam", "algorithm")    ts.SetString("grad", "B")    ts.Insert() //指向一個可用插槽    ts.SetInt("stuid", 2)    ts.SetString("exam", "writing")    ts.SetString("grad", "C")    ts.Insert() //指向一個可用插槽    ts.SetInt("stuid", 2)    ts.SetString("exam", "physics")    ts.SetString("grad", "C")    ts.Insert() //指向一個可用插槽    ts.SetInt("stuid", 3)    ts.SetString("exam", "chemical")    ts.SetString("grad", "B")    ts.Insert() //指向一個可用插槽    ts.SetInt("stuid", 3)    ts.SetString("exam", "english")    ts.SetString("grad", "C")    mdm.CreateTable("exam", exam_sch, tx)    return tx, mdm}

然后我們用解析器解析select查詢語句生成 QueryData 對象,最后使用BasicQueryPlanner創建好執行樹和對應的 Scan 接口對象,最后我們調用 Scan 對象的 Next 接口來獲取給定字段,代碼如下:5Rx28資訊網——每日最新資訊28at.com

func main() {    //構造 student 表    tx, mdm := createStudentTable()    queryStr := "select name from student, exam where id = stuid and grad=/"A/""    p := parser.NewSQLParser(queryStr)    queryData := p.Query()    test_planner := planner.CreateBasicQueryPlanner(mdm)    test_plan := test_planner.CreatePlan(queryData, tx)    test_interface := (test_plan.Open())    test_scan, _ := test_interface.(query.Scan)    for test_scan.Next() {        fmt.Printf("name: %s/n", test_scan.GetString("name"))    }}

上面代碼運行后所得結果如下:5Rx28資訊網——每日最新資訊28at.com

5Rx28資訊網——每日最新資訊28at.com

本文鏈接:http://www.www897cc.com/showinfo-26-46475-0.html自己動手寫數據庫:解析 Select 語句并生成查詢樹

聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: 在Linux系統中實現容器化的大規模數據分析平臺:Hadoop和Spark

下一篇: 玩轉C++方法模板,編程技能秒提升

標簽:
  • 熱門焦點
  • Find N3入網:最高支持16+1TB

    OPPO將于近期登場的Find N3折疊屏目前已經正式入網,型號為PHN110。本次Find N3在外觀方面相比前兩代有很大的變化,不再是小號的橫向折疊屏,而是跟別的廠商一樣采用了較為常見的
  • K60 Pro官方停產 第三方瞬間漲價

    雖然沒有官方宣布,但Redmi的一些高管也已經透露了,Redmi K60 Pro已經停產且不會補貨,這一切都是為了即將到來的K60 Ultra鋪路,屬于廠家的正常操作。但有意思的是該機在停產之后
  • 帥氣純真少年!日本最帥初中生選美冠軍出爐

    日本第一帥哥初一生選美大賽冠軍現已正式出爐,冠軍是來自千葉縣的宗田悠良。日本一直熱衷于各種選美大賽,從&ldquo;最美JK&rdquo;起到&ldquo;最美女星&r
  • 《英雄聯盟》夏季賽總決賽今日開打!JDG對陣LNG首發名單來了 Knight:準備三連冠

    8月5日消息,今日17:00,《英雄聯盟》2023LPL夏季賽總決賽將正式開打,由JDG對陣LNG。對兩支隊伍來說,這場比賽不僅要爭奪夏季賽冠軍,更要決定誰才是LPL賽區一
  • 量化指標是與非:挽救被量化指標扼殺的技術團隊

    作者 | 劉新翠整理 | 徐杰承本文整理自快狗打車技術總監劉新翠在WOT2023大會上的主題分享,更多精彩內容及現場PPT,請關注51CTO技術棧公眾號,發消息【WOT2023PPT】即可直接領取
  • 三分鐘白話RocketMQ系列—— 如何發送消息

    我們知道RocketMQ主要分為消息 生產、存儲(消息堆積)、消費 三大塊領域。那接下來,我們白話一下,RocketMQ是如何發送消息的,揭秘消息生產全過程。注意,如果白話中不小心提到相關代
  • 得物寵物生意「狂飆」,發力“它經濟”

    作者|花花小萌主近日,得物宣布正式上線寵物鑒別,通過得物App內的&ldquo;在線鑒別&rdquo;,可找到鑒別寵物的選項。通過上傳自家寵物的部位細節,就能收獲擁有專業資質認證的得物鑒
  • 2納米決戰2025

    集微網報道 從三強爭霸到四雄逐鹿,2nm的廝殺聲已然隱約傳來。無論是老牌勁旅臺積電、三星,還是誓言重回先進制程領先地位的英特爾,甚至初成立不久的新
  • 由于成本持續增加,筆記本產品價格預計將明顯上漲

    根據知情人士透露,由于材料、物流等成本持續增加,筆記本產品價格預計將在2021年下半年有明顯上漲。進入6月下旬以來,全球半導體芯片缺貨情況加劇,顯卡、處理器
Top 主站蜘蛛池模板: 乌兰县| 当涂县| 洛川县| 靖安县| 汝南县| 康平县| 缙云县| 札达县| 临澧县| 都江堰市| 商洛市| 白玉县| 八宿县| 日喀则市| 丹棱县| 沛县| 囊谦县| 定襄县| 元谋县| 乳源| 玉林市| 泰来县| 大邑县| 保亭| 和静县| 万年县| 华蓥市| 海晏县| 城步| 大化| 广西| 武鸣县| 从江县| 韶山市| 万宁市| 兴宁市| 徐州市| 青海省| 阿图什市| 岑溪市| 浦东新区|