對(duì)于這個(gè)問(wèn)題,開(kāi)始的設(shè)想比較簡(jiǎn)單,大致過(guò)程是:把Sql語(yǔ)句中不相同的關(guān)鍵字和函數(shù)名替換掉,如Oracle中的To_Date換成SqlServer的Convert,就可以在SqlServer上執(zhí)行了.對(duì)一些簡(jiǎn)單的Sql語(yǔ)句這樣確實(shí)可以,可是對(duì)復(fù)雜的應(yīng)用來(lái)說(shuō),Sql語(yǔ)句可能多層嵌套,函數(shù)也有多層嵌套,如果只是簡(jiǎn)單的替換,代碼中必然會(huì)有無(wú)數(shù)的if else,并且出錯(cuò)后的修改和調(diào)試幾乎是不可能的。
通過(guò)對(duì)Oracle和SqlServer兩種數(shù)據(jù)庫(kù)的Sql語(yǔ)法的研究比較,認(rèn)為必須采用語(yǔ)法分析,把Sql語(yǔ)句解析為一棵語(yǔ)法樹(shù),然后再按照語(yǔ)法的轉(zhuǎn)換規(guī)則把sql語(yǔ)句轉(zhuǎn)換到SqlServer上可執(zhí)行的語(yǔ)句。要實(shí)現(xiàn)這樣的功能,需要用到的模式有:
1. INTERPRETER(解釋器)—類行為型模式:給定一個(gè)語(yǔ)言,定義它的文法的一種表示,并定義一個(gè)解釋器,這個(gè)解釋器使用該表示來(lái)解釋語(yǔ)言中的句子。通過(guò)實(shí)現(xiàn)解釋器模式,把要執(zhí)行的Sql語(yǔ)句解釋為Sql的語(yǔ)法樹(shù)。例如一個(gè)Select語(yǔ)句的結(jié)構(gòu)如下
2. COMPOSITE(組合)—對(duì)象結(jié)構(gòu)型模式:將對(duì)象組合成樹(shù)形結(jié)構(gòu)以表示“部分-整體”的層次結(jié)構(gòu)。C o m p o s i t e使得用戶對(duì)單個(gè)對(duì)象和組合對(duì)象的使用具有一致性。
從上面的Sql語(yǔ)句的語(yǔ)法結(jié)構(gòu)可以看到一個(gè)查詢語(yǔ)句可能是很簡(jiǎn)單的select * from ATable,也可能在sql里面又包含其他的Sql語(yǔ)句。按照組合優(yōu)先于繼承的規(guī)則,并沒(méi)有給單獨(dú)的Sql和復(fù)合的Sql語(yǔ)句創(chuàng)建不同的類,而是在內(nèi)部組合并遞歸引用自己的定義,對(duì)訪問(wèn)語(yǔ)法樹(shù)的客戶代碼來(lái)說(shuō),并不需要了解所訪問(wèn)的Sql語(yǔ)句是否存在復(fù)合結(jié)構(gòu)。
3. VISITOR(訪問(wèn)者)—對(duì)象行為型模式:表示一個(gè)作用于某對(duì)象結(jié)構(gòu)中的各元素的操作。它使你可以在不改變各元素的類的前提下定義作用于這些元素的新操作。
前面已經(jīng)通過(guò)解釋器模式解析Sql語(yǔ)法,用組合模式來(lái)存儲(chǔ)解析的語(yǔ)法樹(shù),但是我們所需要的不僅如此。還要按照SqlServer的語(yǔ)法結(jié)構(gòu)把語(yǔ)法樹(shù)上的各個(gè)節(jié)點(diǎn)重新組合,最終輸出SqlServer上可以執(zhí)行的Sql語(yǔ)句。例如:Oracle中的一句連接查詢select a.*,b.* from a,b where a.id=b.id(+),在SqlServer中對(duì)應(yīng)的語(yǔ)句應(yīng)該是select a.*,b.* from a left join b on a.id=b.id。從這個(gè)簡(jiǎn)單的例子中可以看到對(duì)于表的左連接或右連接,兩種數(shù)據(jù)庫(kù)的語(yǔ)法結(jié)構(gòu)存在較大的差異。如果是在TSql類中寫(xiě)某個(gè)方法,由這個(gè)方法遍歷語(yǔ)法樹(shù)上的每個(gè)節(jié)點(diǎn),并按照SqlServer的語(yǔ)法結(jié)構(gòu)組合所需要的結(jié)果,是可以達(dá)到這個(gè)目的的??墒侨绻枰獜倪@棵語(yǔ)法樹(shù)導(dǎo)出其它數(shù)據(jù)庫(kù)上如sybase可執(zhí)行的sql語(yǔ)句呢,那又要在TSql類中再增加新的遍歷算法,所有的相關(guān)代碼又要重新編譯。通過(guò)采用訪問(wèn)者模式,把遍歷節(jié)點(diǎn)時(shí)組合語(yǔ)法樹(shù)節(jié)點(diǎn)的算法封裝再訪問(wèn)者的方法中,如SqlServer的語(yǔ)法就是一個(gè)TSqlServerVisitor類,語(yǔ)法樹(shù)遍歷每個(gè)節(jié)點(diǎn)時(shí),都會(huì)調(diào)用它的Visit方法,全部訪問(wèn)完后即可通過(guò)GetSql得到所需要的Sql語(yǔ)句。這時(shí)如果我們需要轉(zhuǎn)換到Sybase,只需要再實(shí)現(xiàn)一個(gè)TSybaseVisitor類,并傳給語(yǔ)法樹(shù),就可以得到sybase的sql語(yǔ)句了
4.有限狀態(tài)機(jī)--單詞和關(guān)鍵字的識(shí)別.在解析一句sql語(yǔ)句前,先要把其中的字符、數(shù)字、關(guān)鍵字和函數(shù)等語(yǔ)法元素識(shí)別出來(lái)。這顯然不能簡(jiǎn)單的用字符定位等來(lái)判斷,而必須用狀態(tài)機(jī)來(lái)識(shí)別不同的規(guī)則表達(dá)式。這方面現(xiàn)在c#里的規(guī)則表達(dá)式就很好用了。不過(guò)經(jīng)過(guò)重寫(xiě)這些模式識(shí)別,也把以前學(xué)的編譯原理好好復(fù)習(xí)了一遍,對(duì)有些概念的理解更深入一些,只怪當(dāng)初學(xué)的還不夠精啊。呵呵。
聯(lián)系客服