??? 摘 要: 在數(shù)據(jù)庫管理系統(tǒng)" title="管理系統(tǒng)">管理系統(tǒng)GKD-BASE" title="GKD-BASE">GKD-BASE上設(shè)計(jì)并實(shí)現(xiàn)了兼容Oracle PL/SQL V2.3 語言規(guī)范的PL/SQL引擎,擴(kuò)展了GKD-BASE過程處理功能,。
??? 關(guān)鍵詞: 過程語言? PL/SQL? 符號(hào)表? 游標(biāo)
?
??? GKD-BASE數(shù)據(jù)庫是一個(gè)具有自主知識(shí)產(chǎn)權(quán)的數(shù)據(jù)庫管理系統(tǒng),具有兼容SQL89標(biāo)準(zhǔn)的SQL引擎,能夠?yàn)橛脩籼峁┮粋€(gè)統(tǒng)一、有效的數(shù)據(jù)庫訪問接口,,實(shí)現(xiàn)對(duì)數(shù)據(jù)庫的各種操作。但是SQL語言缺乏對(duì)算法的描述能力,,難以勝任復(fù)雜的程序設(shè)計(jì)。為了融合SQL語言強(qiáng)大的集合數(shù)據(jù)處理能力和第三代語言(3GL)靈活的過程處理能力,,主流數(shù)據(jù)庫管理系統(tǒng)產(chǎn)品都已提供了對(duì)過程式SQL語言的支持,,如Oracle的PL/SQL[1]。為了使GKD-BASE適應(yīng)發(fā)展現(xiàn)狀,,滿足管理人員和開發(fā)人員的需求,,急需開發(fā)GKD-BASE自身的PL/SQL引擎。
??? 本文在數(shù)據(jù)庫管理系統(tǒng)GKD-BASE上設(shè)計(jì)并實(shí)現(xiàn)了兼容Oracle PL/SQL V2.3語言規(guī)范的PL/SQL引擎,,擴(kuò)展了GKD-BASE過程處理功能,。
1 GKD-BASE PL/SQL引擎的體系結(jié)構(gòu)
??? GKD-BASE PL/SQL引擎的基本功能是將用戶用PL/SQL語言編寫的程序通過詞法分析程序、語法分析" title="語法分析">語法分析程序進(jìn)行解析,,生成中間代碼并解釋執(zhí)行,。如果在分析階段或解釋執(zhí)行階段發(fā)現(xiàn)錯(cuò)誤,則向用戶報(bào)告錯(cuò)誤號(hào)及相應(yīng)的錯(cuò)誤信息,,以便用戶排錯(cuò)[2],。根據(jù)PL/SQL語言兼有過程式語句和SQL語句的特點(diǎn),采取分治策略,,把過程語句和SQL語句分開處理,。PL/SQL引擎在對(duì)PL/SQL源程序編譯執(zhí)行時(shí),,首先進(jìn)行預(yù)處理,把SQL語句和過程語句分開,;然后對(duì)SQL語句和過程語句分別解析,,生成語法樹;最后通過執(zhí)行模塊對(duì)中間代碼進(jìn)行解釋執(zhí)行,。
??? GKD-BASE PL/SQL引擎對(duì)源程序編譯生成中間代碼,,不能直接在目標(biāo)機(jī)器上執(zhí)行,需要一個(gè)解釋中間代碼的環(huán)境,,以提供對(duì)PL/SQL語言中的數(shù)據(jù)類型的支持,,保證PL/SQL正確執(zhí)行。因此GKD-BASE PL/SQL引擎可分為編譯器和解釋器兩部分,,如圖1,。編譯器接收到PL/SQL語句塊后進(jìn)行預(yù)處理,將句子分為SQL語句和過程語句,。對(duì)于SQL語句,,編譯器建立SQL語句節(jié)點(diǎn),進(jìn)行相應(yīng)的變量綁定" title="綁定">綁定和語法檢查,;檢查無誤后產(chǎn)生中間代碼,。對(duì)于過程語句,編譯器對(duì)語句成分進(jìn)行語法分析并建立相應(yīng)的符號(hào)表,,也生成中間代碼,。因此,可以把編譯器劃分為SQL語言解析,、過程語言解析,、符號(hào)表生成與管理、中間代碼表示與管理等模塊,。解釋器的作用是對(duì)編譯器生成的中間代碼進(jìn)行解釋執(zhí)行[3],,與編譯器對(duì)應(yīng),具有獨(dú)立的SQL語句解釋模塊和過程語句解釋模塊,。解釋器還包括執(zhí)行狀態(tài)堆棧的管理,、與GKD-BASE SQL引擎的調(diào)用接口。異常處理模塊主要實(shí)現(xiàn)程序運(yùn)行時(shí)的錯(cuò)誤檢查和報(bào)告,,并支持用戶自定義異常和預(yù)定義異常的檢查和處理,。
?
2 GKD-BASE PL/SQL編譯器實(shí)現(xiàn)中的一些關(guān)鍵問題
??? GKD-BASE PL/SQL編譯器主要是對(duì)PL/SQL源程序進(jìn)行詞法分析、語法分析和語義處理[4],。本文借助構(gòu)建詞法分析器的Lex和編譯程序自動(dòng)產(chǎn)生工具Yacc[5],,實(shí)現(xiàn)了對(duì)PL/SQL源程序的編譯。下面分別說明符號(hào)表的設(shè)計(jì)與管理,、SQL語句解析以及游標(biāo)解析,。
2.1 符號(hào)表的設(shè)計(jì)與管理
??? 符號(hào)表是一個(gè)包含程序中的變量,、自定義類型和函數(shù)信息的數(shù)據(jù)庫。通過索引對(duì)應(yīng)于庫中的一條記錄,;每條記錄對(duì)應(yīng)著一個(gè)對(duì)象的信息,,如變量的類型或函數(shù)的返回值等[2]。
??? 考慮到PL/SQL語言的塊結(jié)構(gòu)和名字作用域,,可以使用名字堆棧存放源程序中所使用的標(biāo)志符的索引,、名字和類型。每個(gè)項(xiàng)目只包括名字本身和用來表明它的類型的標(biāo)志值,,以及該名字在符號(hào)表中的項(xiàng)目索引,。名字堆棧采用層次結(jié)構(gòu),是鏈表型的堆棧,,堆棧的每一層存放了解析的語句塊嵌套層內(nèi)的所有名字信息,,如圖2。在進(jìn)入或退出一個(gè)嵌套層時(shí)調(diào)用相應(yīng)的壓棧和彈棧操作,;查找符號(hào)時(shí),,從棧頂向棧底搜索。名字堆棧實(shí)現(xiàn)了標(biāo)志符名稱與相應(yīng)的符號(hào)表索引間的映射,,解決了標(biāo)志符的作用域問題和可見性問題,,滿足了對(duì)符號(hào)表管理和調(diào)用的要求。
?
2.2? SQL語句的解析
??? 為了避免SQL語句在執(zhí)行時(shí)出現(xiàn)語法錯(cuò)誤,,需要提前檢查其語法的正確性,。SQL語句是面向集合的數(shù)據(jù)操作語言,只能交由SQL引擎處理,。但是PL/SQL語言為了增強(qiáng)SQL語句與過程式語句的交互能力,,在SQL語句中引入變量,GKD-BASE的SQL引擎無法識(shí)別,,必須在提交之前提取出變量,替換為SQL引擎可以識(shí)別的格式,。如:
??? SELECT empno, name INTO v_empno, v_name FROM emp WHERE birthday = v_date;
??? 這個(gè)SELECT語句首先把變量v_date綁定到列名birthday,,然后根據(jù)條件查出相應(yīng)的結(jié)果(empno , name),并賦值給預(yù)先定義的變量(v_empno , v_name),。對(duì)于GKD-BASE的SQL引擎來說,,只能識(shí)別出如下格式的SELECT語句:
??? SELECT empno, name INTO : v_empno, : v_name FROM emp WHERE birthday= :1;
??? 在把SQL語句交由GKD-BASE SQL引擎處理之前,識(shí)別出變量v_empno,、v_name及v_date進(jìn)行格式轉(zhuǎn)換,,在into之后的變量前面添加“:”,where后面的變量用帶有冒號(hào)的數(shù)字序號(hào)代替,,構(gòu)造出符合SQL引擎要求的語句,;完成這些處理之后,,把新的語句作為字符串交由SQL引擎進(jìn)行語法分析,檢查這條語句的語法是否正確,,以及語句中的變量與對(duì)應(yīng)的列是否匹配,;最后返回結(jié)果,報(bào)錯(cuò)或者生成語法樹,。
2.3 游標(biāo)的解析
??? 游標(biāo)是指向內(nèi)存中上下文區(qū)的句柄或指針,。借助于游標(biāo),PL/SQL程序可以控制上下文區(qū)和語句處理過程中游標(biāo)的變化,。PL/SQL游標(biāo)按使用方式可以分為顯式游標(biāo)和隱式游標(biāo),。
??? 顯式游標(biāo)的使用包括聲明游標(biāo)、打開游標(biāo),、游標(biāo)檢索,、關(guān)閉游標(biāo)四個(gè)步驟。編譯游標(biāo)聲明語句時(shí),,首先調(diào)用SQL引擎分析SQL語句成分,,轉(zhuǎn)換為SQL引擎可以識(shí)別的格式,把游標(biāo)的索引信息加入名字堆棧和符號(hào)表中,。游標(biāo)打開操作在名字堆棧中搜索游標(biāo)名字,,獲取聲明階段在符號(hào)表保存的相關(guān)信息并加入到語法樹中。游標(biāo)檢索語句的編譯首先獲取游標(biāo)的符號(hào)表的信息,;然后關(guān)聯(lián)游標(biāo)中SQL語句的信息和取值變量鏈表的信息,,檢查游標(biāo)變量與游標(biāo)引用列是否匹配;最后保存相關(guān)信息,,加入語法樹,。游標(biāo)的關(guān)閉操作釋放資源并把游標(biāo)狀態(tài)初始化,把游標(biāo)在符號(hào)表中的信息保存并加入語法樹,。
?? ?隱式游標(biāo)一般用于對(duì)DML語句的處理,。每條DML語句對(duì)應(yīng)于一個(gè)隱式游標(biāo),編譯時(shí)可以作為一般的SQL語句來處理,,直接調(diào)用GKD-BASE的SQL引擎對(duì)其進(jìn)行編譯,。這些語句的游標(biāo)處理是由SQL引擎自動(dòng)完成的,不需要PL/SQL引擎對(duì)干涉,。
3 GKD-BASE PL/SQL解釋器實(shí)現(xiàn)中的一些關(guān)鍵問題
??? 解釋器實(shí)現(xiàn)中的關(guān)鍵問題" title="關(guān)鍵問題">關(guān)鍵問題有語句的執(zhí)行,、執(zhí)行狀態(tài)堆棧的設(shè)計(jì)以及返回值的處理。
??? 對(duì)于語句的執(zhí)行,,可分為SQL語句執(zhí)行和過程語句執(zhí)行兩部分,,根據(jù)語法樹上相應(yīng)節(jié)點(diǎn)分別編寫函數(shù)來完成解釋任務(wù)。這些函數(shù)例程之間也是樹狀的層次調(diào)用結(jié)構(gòu),,樹根的解釋執(zhí)行依賴于其子樹上各個(gè)節(jié)點(diǎn)的解釋函數(shù)的成功運(yùn)行,。
??? 在GKD-BASE PL/SQL引擎的解釋執(zhí)行器中,,設(shè)計(jì)了“執(zhí)行狀態(tài)”的數(shù)據(jù)結(jié)構(gòu)來記載函數(shù)的執(zhí)行狀態(tài)信息。解釋器中所有的解釋函數(shù)都擁有一個(gè)指針參數(shù)指向這個(gè)結(jié)構(gòu),,需要在這些函數(shù)間傳遞的信息將被拷貝到這個(gè)結(jié)構(gòu),。PL/SQL引擎調(diào)用子程序的過程中,構(gòu)造“執(zhí)行狀態(tài)堆?!?。調(diào)用之前,保存現(xiàn)場(chǎng),,將執(zhí)行狀態(tài)壓棧,;調(diào)用結(jié)束后恢復(fù)現(xiàn)場(chǎng),彈出當(dāng)前執(zhí)行狀態(tài),,回到上一層繼續(xù),,如圖3。
?
??? 在語句塊執(zhí)行完畢后,,解釋器會(huì)根據(jù)情況給出三種類型的返回狀態(tài):ok,、exit、return,。當(dāng)正常執(zhí)行完一條過程語句或SQL語句后,,返回ok;或者當(dāng)執(zhí)行狀態(tài)當(dāng)前層中所有語句都執(zhí)行正常,,向上一層返回ok,。當(dāng)執(zhí)行時(shí)遇到EXIT關(guān)鍵字,如果執(zhí)行狀態(tài)中的退出標(biāo)號(hào)與輸入?yún)?shù)中的退出標(biāo)號(hào)一致時(shí),,說明是正常退出,,返回exit。當(dāng)執(zhí)行時(shí)遇到RETURN關(guān)鍵字,,說明語句鏈中所有語句執(zhí)行完畢,,返回return。直到到達(dá)執(zhí)行狀態(tài)頂層并給出返回值,,結(jié)束整個(gè)解釋執(zhí)行過程,。
參考文獻(xiàn)
1 Tom Portfolio. PL/SQL User's Guide and Reference, Release?8.1.6. Oracle Corporation. 1999.
2 Scott Urman.陳維軍, 王蕾譯. Oracle9i PL/SQL 程序設(shè)計(jì).北京:機(jī)械工業(yè)出版社, 2002
3 Alfred V.Aho, Ravi Sethi, Jeffery D.Ullman. Compilers:?Principles, Techniques, and Tools, 2001,Addsion-Wesley?Publishing Company
4 陳火旺.程序設(shè)計(jì)語言——編譯原理,,北京:國(guó)防工業(yè)出版社,2000
5? Levine,,J.R. lex與yacc(第二版). 北京:機(jī)械工業(yè)出版社,,2003