摘 要: 兼容Oracle PL/SQL V2.3 語言規(guī)范,基于國產(chǎn)數(shù)據(jù)庫管理系統(tǒng)" title="管理系統(tǒng)">管理系統(tǒng)GKD-Base" title="GKD-Base">GKD-Base內(nèi)核與PL/SQL引擎,提出了Instead-Of視圖觸發(fā)器的編譯存儲(chǔ)和點(diǎn)火執(zhí)行算法,并設(shè)計(jì)實(shí)現(xiàn)了Instead-Of 視圖觸發(fā)器編譯及執(zhí)行處理模塊" title="處理模塊">處理模塊。從而在GKD-Base上實(shí)現(xiàn)了Instead-Of視圖觸發(fā)器機(jī)制,擴(kuò)展了國產(chǎn)數(shù)據(jù)庫GKD-Base功能。
關(guān)鍵詞: PL/SQL引擎 Instead-Of觸發(fā)器
GKD-Base是一個(gè)具有自主知識(shí)產(chǎn)權(quán)的數(shù)據(jù)庫管理系統(tǒng),經(jīng)過十幾年的發(fā)展和應(yīng)用,該系統(tǒng)已經(jīng)被證明是穩(wěn)定可靠的。但是,隨著應(yīng)用需求向深度和廣度的發(fā)展,GKD-Base在很多方面都暴露出了不足,如不支持過程式SQL語言、不支持存儲(chǔ)過程和函數(shù)、缺少觸發(fā)器功能等,這都為GKD-Base數(shù)據(jù)庫管理系統(tǒng)的進(jìn)一步推廣應(yīng)用帶來了不小的障礙。
為此筆者開發(fā)了GKD-Base PL/SQL引擎,其兼容Oracle PL/SQLV2.3規(guī)范。進(jìn)而在引擎的基礎(chǔ)上實(shí)現(xiàn)了GKD-Base DML觸發(fā)器功能[1]。但目前GKD-Base對(duì)于視圖更新的支持還很不夠,對(duì)于連接視圖的更新有著十分嚴(yán)格的限制。國外數(shù)據(jù)庫系統(tǒng)" title="數(shù)據(jù)庫系統(tǒng)">數(shù)據(jù)庫系統(tǒng)如Oracle[2]、SQL Server[3]、PostgreSQL[4]等都提供了所謂的Instead-Of視圖觸發(fā)器來支持視圖更新。定義有Instead-Of觸發(fā)器的視圖被DML語句操作時(shí),相應(yīng)的DML語句不執(zhí)行,而觸發(fā)器體被執(zhí)行,于是用戶可以按照自己定義的語義修改定義視圖的基本表,以達(dá)到修改視圖的目的。因此,為了使GKD-Base適應(yīng)應(yīng)用需求的發(fā)展,在GKD-Base PL/SQL引擎的基礎(chǔ)上實(shí)現(xiàn)了GKD-Base Instead-Of視圖觸發(fā)器功能[1]。
1 視圖更新歧義問題
視圖是虛擬的關(guān)系,數(shù)據(jù)庫系統(tǒng)中只存儲(chǔ)它的定義,不存儲(chǔ)元組數(shù)據(jù)。一個(gè)視圖可以看成一個(gè)臨時(shí)關(guān)系,視圖是產(chǎn)生這種臨時(shí)關(guān)系的查詢定義[5]。
由于視圖是虛擬的關(guān)系,對(duì)視圖的更新操作必須映射到對(duì)相應(yīng)的基本表操作才能實(shí)現(xiàn)。完成視圖更新后的數(shù)據(jù)庫狀態(tài)由視圖定義導(dǎo)出一個(gè)新的視圖狀態(tài),新的視圖狀態(tài)對(duì)應(yīng)由原視圖狀態(tài)直接完成視圖的更新操作。
如圖1所示,u是關(guān)系數(shù)據(jù)庫DB的視圖v(DB)的更新操作,T(u)是對(duì)視圖更新操作的變換,它作用到DB上產(chǎn)生新的數(shù)據(jù)庫狀態(tài)DB′、新的視圖狀態(tài)v(DB′)。正確的視圖更新操作使得u(v(DB))= v(DB′)。但是對(duì)視圖更新操作的變換T(u)并不總存在[6]。即使存在,也不總是惟一的。視圖的更新存在固有的歧義性,僅有上面的語義是不夠的。
并且,由于視圖本身的歧義性和語義不完整性[7],無法對(duì)于有著集合操作符(如:UNION、MINUS等)、聚集函數(shù)(如:SUM、AVE等)和GROUP BY子句的視圖更新提供支持。
2 Instead-Of觸發(fā)器設(shè)計(jì)實(shí)現(xiàn)
2.1 PL/SQL引擎體系結(jié)構(gòu)
根據(jù)PL/SQL語言兼有過程式語句和SQL語句的特點(diǎn),GKD-Base PL/SQL引擎把過程式語句和SQL語句分開處理。為了降低引擎實(shí)現(xiàn)的復(fù)雜程度,從功能性的角度將整個(gè)引擎劃分為前端編譯器和后端解釋執(zhí)行器" title="執(zhí)行器">執(zhí)行器,每個(gè)處理模塊盡量降低相互間的耦合程度。
前端編譯器包括語言預(yù)處理、SQL語句分析、過程語句分析以及中間代碼生成等功能。PL/SQL語句塊輸入后,由語言預(yù)處理功能分離成SQL語句和過程語句。對(duì)于SQL語句,由GKD-Base SQL引擎解析后,建立SQL語句結(jié)點(diǎn),進(jìn)行相應(yīng)的變量綁定和語法檢查,檢查無誤后產(chǎn)生語法樹形式的中間代碼。對(duì)于過程語句,將語句成分進(jìn)行語法分析,在分析中把聲明的變量和數(shù)據(jù)類型加入到名字空間和符號(hào)表中,同時(shí)產(chǎn)生語法樹形式的中間代碼。
后端解釋執(zhí)行器的功能就是對(duì)前端編譯器生成的中間代碼進(jìn)行解釋執(zhí)行。因此在結(jié)構(gòu)上,解釋執(zhí)行器與編譯器對(duì)應(yīng),也有過程語句執(zhí)行模塊和SQL語句執(zhí)行模塊,過程語句解釋執(zhí)行器解釋執(zhí)行過程語句的中間代碼,SQL命令則直接由SQL引擎執(zhí)行。另外,解釋器還包括例外處理模塊,負(fù)責(zé)檢查錯(cuò)誤和報(bào)告錯(cuò)誤[8]。
2.2 Instead-Of觸發(fā)器設(shè)計(jì)
2.2.1觸發(fā)器模型
GKD-Base DML觸發(fā)器采用傳統(tǒng)的ECA(Event-Condition-Action,事件—條件—?jiǎng)幼?規(guī)則設(shè)計(jì)。與之類似的Instead-Of 視圖觸發(fā)器也采用了ECA規(guī)則。
為了適應(yīng)觸發(fā)器的具體情況,在GKD-Base中,Instead-Of 視圖觸發(fā)器擴(kuò)展為一個(gè)四元組模型:Trigger:=
E(Event):激發(fā)Instead-Of 視圖觸發(fā)器的事件。這里主要是指操作視圖的DML事件,包括Insert、 Delete和Update等。
C(Condition):定義觸發(fā)器時(shí)指定的條件。是一個(gè)一元謂詞表達(dá)式。
A(Action):當(dāng)Event發(fā)生,并且Condition為真時(shí),觸發(fā)的動(dòng)作。
S(Status):觸發(fā)器有活躍和休眠兩種狀態(tài),觸發(fā)器處于活躍狀態(tài)時(shí),才可被激發(fā)。
2.2.2 觸發(fā)器實(shí)現(xiàn)框架
觸發(fā)器實(shí)現(xiàn)框架如圖2所示。觸發(fā)器類別判決器是在系統(tǒng)執(zhí)行SQL語句之前,對(duì)SQL語句的操作對(duì)象進(jìn)行判斷,如果是對(duì)基本表操作,則啟動(dòng)DML觸發(fā)器的監(jiān)測功能;如果是對(duì)視圖進(jìn)行操作,則啟動(dòng)Instead-Of 視圖觸發(fā)器的監(jiān)測功能。事件監(jiān)視器是在有關(guān)的系統(tǒng)行為發(fā)生時(shí),為各種預(yù)定的事件給觸發(fā)器調(diào)度器發(fā)送信號(hào)。觸發(fā)器調(diào)度器接收事件監(jiān)視器的信號(hào),從數(shù)據(jù)字典中獲取該事件點(diǎn)火的所有觸發(fā)器,并且按照特定的順序排序,調(diào)用條件評(píng)價(jià)器檢查各觸發(fā)器的觸發(fā)條件是否滿足,若滿足則由觸發(fā)器調(diào)度器通知PL/SQL引擎解釋執(zhí)行該觸發(fā)器的動(dòng)作代碼。條件評(píng)價(jià)器是用來檢查觸發(fā)條件是否滿足的部件。對(duì)于語句級(jí)觸發(fā)器,由于不存在觸發(fā)條件子句,所以觸發(fā)條件始終為真。對(duì)于行(元組)級(jí)觸發(fā)器,條件評(píng)價(jià)器可以將其觸發(fā)條件WHEN子句轉(zhuǎn)換成一個(gè)PL/SQL語言的IF語句,然后由PL/SQL引擎實(shí)現(xiàn)觸發(fā)器條件的計(jì)算。
2.3 Instead-Of觸發(fā)器實(shí)現(xiàn)
2.3.1 觸發(fā)器謂詞以及new和old元組的設(shè)計(jì)
觸發(fā)器謂詞是指觸發(fā)器內(nèi)部用來標(biāo)識(shí)激發(fā)觸發(fā)器動(dòng)作的DML語句的布爾變量,為:INSERTING、UPDATING、DELETING。其分別對(duì)應(yīng)于PL/SQL程序中的三個(gè)布爾變量,它們?cè)诰幾g觸發(fā)器時(shí)被加載到符號(hào)表中,在調(diào)用PL/SQL引擎執(zhí)行觸發(fā)器動(dòng)作體之前,它們的值被準(zhǔn)備好,供PL/SQL引擎取用。
NEW和OLD元組作為PL/SQL程序中的記錄樣式加載到符號(hào)表中,被編譯器引用。其記錄域與新舊元組對(duì)應(yīng)的表的各個(gè)屬性一一對(duì)應(yīng)。在調(diào)用PL/SQL引擎執(zhí)行觸發(fā)器動(dòng)作體之前,必須準(zhǔn)備好NEW和OLD的值。但NEW和OLD元組是偽記錄類型,不能完全按照記錄的語法來訪問[12]。這一點(diǎn)必須在編譯時(shí)加入新的語義規(guī)則。
2.3.2 Instead-Of觸發(fā)器的編譯與存儲(chǔ)
功能:編譯觸發(fā)器定義語句后,將觸發(fā)器信息存儲(chǔ)于數(shù)據(jù)字典中。
輸入:一條用戶輸入的觸發(fā)器定義語句。
輸出:觸發(fā)器數(shù)據(jù)字典的元組。
(1)判斷當(dāng)前事務(wù)是否存在,如果存在,則提交當(dāng)前事務(wù),并開始一個(gè)新事務(wù);否則,直接開始一個(gè)新事務(wù)。
(2)用戶權(quán)限檢查。如果當(dāng)前用戶無權(quán)執(zhí)行該操作,轉(zhuǎn)(12);否則轉(zhuǎn)(3)。
(3)檢查觸發(fā)表(視圖)名及觸發(fā)事件所涉及的屬性是否存在。在GKD-Base的數(shù)據(jù)字典SYS.TABLES中查找,如果觸發(fā)表或某個(gè)屬性不存在,轉(zhuǎn)(12);否則,轉(zhuǎn)(4)。
(4)觸發(fā)器名存在性檢查。如果當(dāng)前定義的觸發(fā)器與以往定義的某個(gè)觸發(fā)器重名,轉(zhuǎn)(5);否則轉(zhuǎn)(7)。
(5)如果聲明語句中沒有包含 OR REPLACE選項(xiàng),轉(zhuǎn)(12);否則,轉(zhuǎn)(6)。
(6)如果觸發(fā)表(視圖)不一致,轉(zhuǎn)(12);否則轉(zhuǎn)(7)(觸發(fā)表指定義了DML觸發(fā)器或Instead-Of 視圖觸發(fā)器的基本表或視圖)。
(7)檢查定義觸發(fā)器的合法性,DML觸發(fā)器只能定義在基本表上,而Instead-Of視圖觸發(fā)器只能定義在視圖上。檢查合法,轉(zhuǎn)(8),否則轉(zhuǎn)(12)。
(8)調(diào)用PL/SQL引擎編譯觸發(fā)器動(dòng)作體,并且將觸發(fā)器的WHEN條件子句轉(zhuǎn)換成一個(gè)IF語句,這個(gè)IF語句的真值部分包括了觸發(fā)器動(dòng)作體。如果觸發(fā)器動(dòng)作體中出現(xiàn)語法或語義錯(cuò)誤,轉(zhuǎn)(12);否則轉(zhuǎn)(9)。
(9)在數(shù)據(jù)字典SYS.TRIGGERS表中插入一個(gè)新元組,填入此觸發(fā)器的信息。如果出現(xiàn)磁盤I/O錯(cuò)誤,轉(zhuǎn)(12);否則轉(zhuǎn)(10)。
(10)釋放所占資源。
(11)提交當(dāng)前事務(wù),正常結(jié)束。
(12)回滾當(dāng)前事務(wù),報(bào)錯(cuò)退出。
2.3.3 Instead-Of視圖觸發(fā)器的點(diǎn)火執(zhí)行
與DML觸發(fā)器不同,Instead-Of 視圖觸發(fā)器在激發(fā)時(shí),不必考慮各種觸發(fā)器(如語句級(jí)前觸發(fā)器和行級(jí)后觸發(fā)器)之間的相互纏結(jié)。其點(diǎn)火算法也相對(duì)簡單。 在觸發(fā)事件當(dāng)前的事務(wù)中構(gòu)造一條SQL查詢語句,從觸發(fā)器數(shù)據(jù)字典表中獲取與該觸發(fā)事件相關(guān)的處于活躍狀態(tài)的Instead-Of視圖觸發(fā)器元組。如果查詢結(jié)果不為空,將觸發(fā)器條件轉(zhuǎn)換成一個(gè)PL/SQL語言的IF語句,并將觸發(fā)事件當(dāng)前所用到的元組值(新值和舊值)準(zhǔn)備好,啟動(dòng)PL/SQL引擎,對(duì)觸發(fā)器動(dòng)作體的源代碼進(jìn)行解釋執(zhí)行。釋放所占的資源,結(jié)束觸發(fā)器調(diào)用。
3 系統(tǒng)應(yīng)用實(shí)例
3.1實(shí)驗(yàn)數(shù)據(jù)
Rooms表如表1所示,Classes表如表2所示。在Classes表和Rooms表中Room_ID相等的連接條件上創(chuàng)建一個(gè)名為Classes_rooms的視圖,進(jìn)行連接運(yùn)算。Classes_rooms視圖如表3所示。
定義關(guān)于Classes_rooms 的Update語義:通過對(duì)Classes_rooms的Update操作,實(shí)現(xiàn)對(duì)一個(gè)班級(jí)某門課程占用教室的調(diào)整。通過Instead-Of觸發(fā)器實(shí)現(xiàn):如果修改了Classes_rooms的Dept和Course屬性,那么就修改Classes基本表的相應(yīng)屬性,如果修改了Classes_rooms的Building和Room_Num屬性,那么就修改Rooms基本表的相應(yīng)屬性。再適當(dāng)調(diào)整兩個(gè)基本表的Room_ID。
3.2 實(shí)驗(yàn)結(jié)果
執(zhí)行UPDATE classes_rooms SET Dept=‘NUT’, course = 307 WHERE building=‘Buidling 7’ AND room_num = 201; 查詢更新后的視圖,觀察Instead-Of觸發(fā)器對(duì)視圖的作用。
表4、表5、表6演示了本實(shí)驗(yàn)的結(jié)果。由結(jié)果可知,通過Instead-Of觸發(fā)器,成功地對(duì)Classes_rooms視圖進(jìn)行了修改,將歷史系101課的教室調(diào)整給了營養(yǎng)系307課程使用。通過以上應(yīng)用實(shí)例驗(yàn)證了Instead-Of觸發(fā)器帶給數(shù)據(jù)庫系統(tǒng)的視圖修改功能。
本文參照Oracle PL/SQL V2.3 語言規(guī)范,在數(shù)據(jù)庫管理系統(tǒng)GKD-Base 的PL/SQL引擎的基礎(chǔ)上,給出了Instead-Of 視圖觸發(fā)器的編譯存儲(chǔ)和點(diǎn)火執(zhí)行的相關(guān)算法,設(shè)計(jì)了Instead-Of視圖觸發(fā)器編譯及執(zhí)行處理模塊,從而在實(shí)現(xiàn)DML 觸發(fā)器的基礎(chǔ)上實(shí)現(xiàn)了Instead-Of 視圖觸發(fā)器,并在實(shí)際中得到了驗(yàn)證。擴(kuò)展了GKD-Base的功能,使其能夠應(yīng)用于更多的領(lǐng)域。
參考文獻(xiàn)
1 Tom Portfolio. PL/SQL User′s Guide and Reference. Release 8.1.6. Oracle Corporation,1999
2 Ken Henderson. The Guru′s Guide to Transact-SQL. AddisonWesley Pub Co., 2000;2
3 PostgreSQL 7.4 Documentation.The PostgreSQL Global Development Group, 2003
4 景 寧. SQL查詢處理與實(shí)現(xiàn)技術(shù)研究.長沙:國防科技大學(xué).工學(xué)博士學(xué)位論文,1990;4
5 E.F.Codd. Recent Investigations in a Relational Database System. North-Holland Publishing Company,1974
6 劉念祖. 數(shù)據(jù)庫系統(tǒng)中視圖問題的研究. 計(jì)算機(jī)工程,1997;12
7 陳火旺. 程序設(shè)計(jì)語言——編譯原理.北京:國防工業(yè)出版社,2000