Budapesti M˝uszaki és Gazdaságtudományi Egyetem Villamosmérnöki és Informatikai Kar Távközlési és Médiainformatikai Tanszék
Adatbázis migráció Microsoft SQL Server adatbázisról Oracle adatbázis-kezel˝ore
Tánczos Zoltán Csaba F966Q8
Konzulens: Kardkovács Zsolt Tivadar
Diplomaterv 2009
Nyilatkozat Alulírott Tánczos Zoltán Csaba, a Budapesti M˝uszaki és Gazdaságtudományi Egyetem hallgatója kijelentem, hogy ezt a diplomatervet meg nem engedett segítség nélkül, saját magam készítettem, és a diplomatervben csak a megadott forrásokat használtam fel. Minden olyan részt, melyet szó szerint, vagy azonos értelemben, de átfogalmazva más forrásból átvettem, egyértelm˝uen, a forrás megadásával megjelöltem.
Budapest, 2009. május 31.
Tánczos Zoltán Csaba
Kivonat Ebben a dolgozatban az adatbázisok közötti migráció kérdéseivel foglalkozok. Bemutatom, hogy általános esetben egy adatbáziskezel˝o rendszer cseréje során milyen jelleg˝u problémákkal szembesülhetünk, illetve ezek kezelésére milyen módszerek léteznek. Ezután két konkrét rendszerre, a Microsoft SQL Serverre és az Oracle adatbáziskezel˝ore helyezem a hangsúlyt. Ismertetek olyan szoftvereket, amik segítik az ezen rendszerek közötti átállást, kitérve ezek használatának korlátaira is. Bemutatok egy módszertant, ami egyfajta keretet nyújt a migrációs munka szervezéséhez, elvégzéséhez, jól definiálva az elvégzend˝o fázisokat, a fázisok során felmerül˝o feladatokat. A különbségek taglalása után arra a megállapításra jutok, hogy a két rendszer közötti elvi különbségek miatt nem létezhet olyan szoftver, ami képes a teljes migrációs folyamatot automatizáltan véghezvinni. Ezeket a „problémás területeket” külön kiemelem, részletezem. A dolgozat második fejezetében egy olyan fordító funkcionális tervét mutatom be, ami képes Transact-SQL kód PL/SQL-re fordítására, az ismertetett korlátok között. A fordítót az ANTLR és a StringTemplate rendszerek segítségével implementálom. Az elkészített fordító a céljaim szerint bizonyos részfeladatok automatizálásával hatékony segédeszköz lehet azok számára, akik SQL Server-r˝ol Oracle adatbáziskezel˝o alá migrálják a tárolt programokat, eljárásokat. A függelékben bemutatott tesztesetek tanulsága szerint bizonyos szituációkban jobb fordítási eredményt sikerült elérnem, mint az Oracle által fejlesztett SQL Developer.
Abstract In this thesis I discuss database migration issues. I present the general problems one would face during the exchange of a database management system, and what methods exist to deal with them. Then I place the emphasis on two specific systems: Microsoft SQL Server and Oracle Database. I review database migration tools which can help the transition between these systems, and I also present limitations of such softwares. I describe a methodology which can provide a framework for the recommended process for the migration of an existing third-party database to Oracle. It provides well-defined phases, and step-by-step instructions to be carried out. After I show the main differences between those database systems, I’ve come to the conclusion that because the two system differ in principle a fully automatic migration software which covers the whole migration process could not exist. I describe these problematic areas in details. In the second chapter of the work I present the functional plan of a language translator which is capable of translating Transact-SQL source code into PL/SQL, in respect of the described limitations. I implement the translator using the ANTLR and StringTemplate frameworks. The purpose of this translator is to help the migration from SQL Server to Oracle Database with the automation of certain tasks. As shown in the Appendix, in some cases I achieved better translation results as the SQL Developer, which is developed by Oracle.
Tartalomjegyzék 1. Bevezet˝o
1
1.1. Adatbázisok migrációinak általános problémái . . . . . . . . . . . . . . . . . .
1
1.1.1. Adatok migrációja . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2
1.1.2. Programnyelvek közötti fordítás . . . . . . . . . . . . . . . . . . . . .
3
1.2. SQL Server és Oracle közötti migrációs eljárások . . . . . . . . . . . . . . . .
6
1.2.1. Az Oracle Relational Migration Map módszertan bemutatása . . . . .
6
1.2.2. Migrációt segít˝o szoftverek bemutatása . . . . . . . . . . . . . . . . .
10
1.2.3. A migrációs eszközök korlátai . . . . . . . . . . . . . . . . . . . . . .
12
1.3. Összefoglalás . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
22
2. Fordító tervezése
24
2.1. Formális nyelvi elemzés . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
25
2.1.1. Az ANTLR elemz˝o-generátor bemutatása . . . . . . . . . . . . . . . .
27
2.1.2. A StringTemplate sablon-motor bemutatása . . . . . . . . . . . . . . .
30
2.2. Funkcionális terv . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
32
2.2.1. A feladat leírása . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
32
2.2.2. A rendszer célja . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
33
2.2.3. Komponensek leírása . . . . . . . . . . . . . . . . . . . . . . . . . . .
33
2.3. Összefoglalás . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
40
3. Értékelés
43
3.1. B˝ovíthet˝oség . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
45
3.2. Limitációk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
45
4. Összefoglalás
46
A. Oracle SQL Developer Migration Workbench
48
B. A funkcionális tervben specifikált transzformációk muködés ˝ közben
52
1
Ábrák jegyzéke 1.4. Egy T-SQL tárolt eljárás lehetséges visszatérési értékei . . . . . . . . . . . . .
21
2.2. A fordítás folyamata ANTLR+StringTemplate-el . . . . . . . . . . . . . . . .
32
2.3. Egy T-SQL tárolt eljáráshoz tartozó absztrakt szintaxis fa . . . . . . . . . . . .
35
2.4. A fordítóhoz tartozó grafikus kezel˝oi felület . . . . . . . . . . . . . . . . . . .
42
3.1. Szintaktikailag hibás bemenet fordítása a fordító segítségével . . . . . . . . . .
44
B.1. Kurzorváltozók használata kimeneti eredményhalmaz el˝oállításához . . . . . .
52
B.2. SELECT utasítás FROM klauzula nélkül . . . . . . . . . . . . . . . . . . . . .
53
B.3. SELECT utasítás kétféle alias szintaxisa . . . . . . . . . . . . . . . . . . . . .
53
B.4. SELECT utasítás INTO klauzulájának fordítása . . . . . . . . . . . . . . . . .
53
B.5. UPDATE utasítás átalakítása MERGE utasításra 1. . . . . . . . . . . . . . . .
54
B.6. UPDATE utasítás átalakítása MERGE utasításra 2. . . . . . . . . . . . . . . .
54
B.7. IF EXISTS szerkezet szimulálása . . . . . . . . . . . . . . . . . . . . . . . . .
54
B.8. Tárolt eljárás visszatérési értékkel . . . . . . . . . . . . . . . . . . . . . . . .
55
B.9. WHILE ciklus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
55
B.10. Hibajelzés: RAISERROR fordítása . . . . . . . . . . . . . . . . . . . . . . . .
56
B.11. INSERT utasítás INTO kulcsszó nélkül . . . . . . . . . . . . . . . . . . . . .
56
B.12. DELETE utasítás második FROM klauzulával . . . . . . . . . . . . . . . . . .
56
B.13. DELETE utasítás második FROM klauzulával – összetettebb példa . . . . . . .
57
B.14. DELETE utasítás hibás fordítása az Oracle Migration Workbench-el . . . . . .
57
2
Táblázatok jegyzéke 1.1. Feltételes szerkezetek leképezhet˝osége a T-SQL és a PL/SQL között . . . . . .
4
2.1. A SELECT utasításnál szükséges transzformációk . . . . . . . . . . . . . . . .
38
2.2. Az INSERT utasításnál szükséges transzformációk . . . . . . . . . . . . . . .
38
2.3. A DELETE utasításnál szükséges transzformációk . . . . . . . . . . . . . . .
39
2.4. Az UPDATE utasításnál szükséges transzformációk . . . . . . . . . . . . . . .
39
2.5. Az IF EXISTS szerkezetnél lehetséges transzformációk . . . . . . . . . . . . .
41
A.1. Az sqlserver_utilities csomagban található függvények . . . . . . .
49
3
1. fejezet Bevezet˝o 1.1. Adatbázisok migrációinak általános problémái Adatbázisok ritkán léteznek önmagukban. Adatbázisokat azért készítünk, hogy a bennük tárolt adatokhoz hatékonyan, rendszerezetten, kontrolláltan férjünk hozzá. Ez az esetek kis hányadában jelenti azt, hogy a felhasználó közvetlenül az adatbázishoz csatlakozik, és az adatbáziskezel˝o nyelvén utasításokat ad ki. A gyakoribb az, amikor valamilyen rendszer van az adatbázis el˝ott, amin keresztül érjük el az adatokat, az adatbáziskezel˝o funkcióit. Ez a küls˝o „burok” tetsz˝olegesen összetett lehet. Az egyszer˝u kliens-szerver architektúrától kezdve a három réteg˝u architektúrán át egészen a különböz˝o adattárház-rendszerekig számos kombináció elképzelhet˝o. Ezen kívül több adatbázis-szerver is elképzelhet˝o, melyek egymással közvetlenül is kommunikálhatnak, adatokat cserélhetnek. Ezen sokszín˝uség miatt az adatbázis-kezel˝o lecserélése komplex probléma, mely rendszerszint˝u szemléletmódot igényel. Az adatbázis-kezel˝o egy kiszolgáló, melynek bármilyen módosítása a hozzá közvetve vagy közvetlenül kapcsolódó összes entitás m˝uködését befolyásolhatja. Az 1.2.1 fejezetben bemutatott módszertan egy olyan keretet próbál nyújtani, ami segíti a migrációs folyamat rendszerszint˝u átfogó kezelését. Egy probléma mérnöki megoldása absztrakciót, részfeladatokra bontást igényel. Ebben a dokumentumban kifejezetten az adatbázis-migráció problémáival, lehetséges megoldásaival foglalkozok, azt a célt szem el˝ott tartva, hogy a folyamat a lehet˝o legkisebb módosítást igényelje a kliens-alkalmazásokban. A migráció során kezelend˝o problémákat az alábbi kategóriákba oszthatjuk: • Adat-migrációval kapcsolatos problémák: a forrásrendszerb˝ol az adatokat valahogyan át kell emelni a célrendszerbe, meg˝orízve az adatok konzisztenciáját, integritását. Ez különösen különböz˝o paradigmájú adatbáziskezel˝ok közötti váltásnál kritikus (pl.: nemrelációsról relációsra), de pusztán az alkalmazható adattípusok közötti különbségek is okozhatnak problémákat. 1
• Nyelvi különbségekb˝ol adódó problémák: a legtöbb adatbáziskezel˝o az SQL nyelv valamilyen dialektusát támogatja, de természetesen nem egységesen. Az egyes gyártók megpróbálják minél több kiegészítéssel ellátni a saját verziójukat, és még a szabványokat is eltér˝oen értelmezik. Ez különösen akkor kritikus, ha az üzleti logika jelent˝os része az adatbázisban van megvalósítva (tárolt programok, eljárások formájában). • Adminisztrációval, üzemeltetéssel kapcsolatos problémák: az adatbázisokat általában szakemberek üzemeltetik, akik értenek az adott szoftver adott verziójával kapcsolatos feladatok ellátásához. Ha lecseréljük ezt a szoftvert, elengedhetetlen, hogy biztosítsuk az üzemeltet˝oknek a feladatuk ellátásához szükséges kompetencia megszerzését (vagy cseréljük le o˝ ket is). Mivel az adminisztratív feladatok köre illetve elvégzésük módja nem csak a gyártók között különbözik, hanem akár verzióról verzióra is változhat, ezen problémakör általános kezelése nem megoldható. A fejezet további részében az els˝o két problémakörrel foglalkozok: el˝oször általánosságban, majd két konkrét rendszer, az SQL Server és az Oracle adatbáziskezel˝o közötti migrációs lehet˝oségek, korlátok bemutatásán keresztül.
1.1.1. Adatok migrációja Az adatbázisban tárolt két legnagyobb érték az adatok maguk, illetve az üzleti logika (tárolt programok). Ha cseréljük az adatbázist, akkor értelem szer˝uen mindkét értéket meg szeretnénk o˝ rizni, mitöbb, növelni szeretnénk az együttes hasznosságukat, különben nem lenne racionális döntés a váltás. Ebben a részben az adatok migrációjának kérdéseivel foglalkozok. Az adatok migrációja általában három fázisra bontható[4]: • A forrás adatok elemzése • Modell leképezése vagy elkészítése • Forrás adatok átmozgatása Az els˝o lépés során a forrásrendszerben található adatok illetve a séma elemzésével elkészítjük a forrásrendszer adatmodelljét. Szerencsés esetben ez a modell rendelkezésre áll. Ezután megalkotjuk a leképezéseket, illetve definiáljuk az esetlegesen szükséges transzformációkat. Ez a lépés közel sem triviális, hiszen elképzelhet˝o, hogy egynél több forrás-adatbázist szeretnénk egy modellre, egy adatbázisra leképezni. Az adatok átmozgatása is egy összetett lépés, ami gondos tervezést igényel. Például, maga a sorrend sem mindegy, mely adatokat töltjük át el˝oször, és melyeket kés˝obb, ha biztosítani szeretnénk a referenciális integritást a célrendszerben: el˝oször az els˝odleges kulcsokat tartalmazó táblákat, majd utána a hozzá kapcsolódóakat[2]. 2
Adatok migrációjáról szóló szakirodalom viszonylag sz˝uk ahhoz képest, hogy mennyi publikáció, szakkönyv született az adattárházak betöltését szolgáló ETL folyamatról (Extract, Transform, Load). A két dolog pedig közel azonos: egy vagy több heterogén forrásrendszerb˝ol az adatokat át akarjuk emelni egy vagy több célrendszerbe. Mindösszesen a cél és az id˝ozítés különbözik: nem egy új igényeket kielégít˝o, új rendszert akarunk rendszeresen (hetente, naponta, real-time) adatokkal táplálni, hanem a meglév˝o rendszer funkcionalitását meg˝orízve (esetleg kiegészítve) „csak” adatbázist akarunk váltani1 . Ezért az ETL folyamat során felmerül˝o problémák – leszámítva talán a performanciát érint˝oeket – itt is el˝ojönnek. Ezeket alapvet˝oen két csoportra oszthatjuk[9]: • Egy forrásból ered˝o problémák • Több forrásból ered˝o problémák Mindkét csoportot tovább bonthatjuk séma-szint˝u illetve adat-szint˝u problémákra. A sémaszint˝u problémákra példák lehetnek a hibás tervezésb˝ol adódó hibák (egyediség hiánya, referenciális integritás megsértése), vagy több forrás esetén az elnevezésekb˝ol adódó félreértések (pl.: az a mez˝o, hogy cím valójában mit is jelent?). Ha egy „tökéletesen” megtervezett forrás adatbázisunk van, amit nem akarunk más forrásokkal integrálni, csupán egy közel megegyez˝o architektúrájú másik adatbáziskezel˝o alá szeretnénk migrálni, akkor is lehetnek az adattípusok különböz˝oségéb˝ol adódó problémák. Az SQL Server és az Oracle adatbáziskezel˝o például egymástól különböz˝o adattípusokkal rendelkezik. Ezen különbségekkel részletesen az 1.2.3 fejezetben foglalkozok. Az igazi fejfájást okozó problémák a látszólagos egyez˝oségekb˝ol erednek: mindkét el˝obb említett adatbáziskezel˝o rendelkezik dátumok tárolására alkalmas típussal. Ez SQL Server alatt a DATETIME míg Oracle alatt a DATE. Viszont ez a típus SQL Server alatt 3.33 milliszekundum, Oracle alatt pedig másodperc pontosságú, és a tárolható intervallum is különbözik: 1753-t˝ol 9999-ig SQL Server alatt, és I.e. 4712-t˝ol 9999-ig Oracle alatt. Érdemes még megemlíteni, hogy ugyanazt az adatot is lehet többféleképpen értelmezni: az Oracle adatbáziskezel˝o a “ értékeket (üres sztring) NULL-ként kezeli.
1.1.2. Programnyelvek közötti fordítás A nyelvek közötti fordítást több tényez˝o is motiválhatja. Az üzleti szempontokon kívül az egyik leggyakoribb cél a karbantarthatóság növelése. Számos szakirodalom foglalkozik régr˝ol megörökölt, legacy rendszerekr˝ol történ˝o átállással. A probléma ezekkel egyrészt az, hogy nehéz az integrációjuk az újabb rendszerekkel szoftver vagy hardver inkompatibilitási okokból[4], 1
Ezzel együtt esetleg architektúrát, paradigmát is, pl.: nem relációsról relációsra, objektum-orientáltra, stb.
3
másrészt, hogy – habár m˝uködnek – felmerülnek módosítási igények, viszont az oktatásból kikerül˝o szakemberek jó eséllyel már nem tanultak 10-15 évvel ezel˝otti technológiákat. Ezt a rést hivatottak áthidalni a különböz˝o nyelvek közötti automatizált fordító programok.[10] Egy forráskód átfordítása egy másik nyelvre a meglév˝o nyelvi konstrukciók leképezését jelenti a célnyelvre. Az 1.1 ábrán a lehetséges leképezések láthatóak. A natív szerkezetek azok a nyelvi elemek, amelyek egy adott feladatot kényelmesen oldanak meg. Például egy olyan programnyelvben, ami támogatja az if..then..else szerkezetet, egy feltételes kifejezés leírása kényelmes, viszont olyan nyelvben, amib˝ol ez hiányzik, szimulálnunk kell a m˝uködését. Ezeket a szerkezeteket szimulált szerkezeteknek nevezzük.
1.1. ábra. Nyelvi elemek leképezése a fordítás során. [10]
Az összes nyílnak megfelel˝o átmenet elképzelhet˝o. Ennek illusztrálására nézzük meg a Transact-SQL és a PL/SQL feltételes szerkezetét: IF 1=2 SET @x = 3
IF 1 = 2 THEN v_x := 3; END IF;
IF EXISTS(SELECT * FROM t1) DECLARE v_temp NUMBER(1, 0) := 0; SET @x = -1 BEGIN SELECT 1 INTO v_temp FROM DUAL WHERE EXISTS ( SELECT * FROM t1 ); IF v_temp = 1 THEN v_x := -1; END IF; END;
1.1. táblázat. Feltételes szerkezetek leképezhet˝osége a T-SQL és a PL/SQL között
4
Az 1.1 táblázatban az els˝o esetben egy natív szerkezetet egy natív szerkezetre tudunk leképezni. A második esetben viszont – mivel a PL/SQL nem támogatja az IF EXISTS.. szerkezetet – szimulálnunk kell a m˝uködését. A nem létez˝o konstrukcióknak megfelel˝o átmenetre példa lehet a T-SQL tranzakció kezdetét jelz˝o begin transaction utasítás: mivel Oracle alatt minden tranzakció implicit, azaz automatikusan, az els˝o végrehajtható SQL utasítással kezd˝odik, nincs megfelel˝o utasítás. Terekhov és Verhoef munkájukban[10] 9 követelményt támasztanak az automatikus fordításokkal szemben: • Szükséges összegy˝ujteni azokat a natív és szimulált nyelvi konstrukciókat, amelyeket át kell fordítani. • Minden egyes konstrukcióhoz meg kell alkotni a fordítási stratégiát. • Ki kell jelenteni, hogy az átfordított rendszer funkcionálisan megegyez˝o lesz-e a forrásrendszerrel. Erre válaszul kapásból igent mondhatnánk, pedig el˝ofordulhat, hogy fordítás közben felszínre kerülhetnek hibás, nem biztonságos kódrészletek, melyeket célszer˝u javítani. • Ki kell jelenteni, hogy a meglév˝o tesztesetek is fordításra kerülnek-e vagy sem. • A lehet˝o legnagyobb automatizáltságra kell törekedni, azaz minimalizálni kell az emberi beavatkozási igényt. • Az elkészített kódnak karbantarthatónak kell lennie. Ha ugyanaz a csapat fog dolgozni az új kóddal is, mint a régivel, akkor fontos, hogy a fordítás során a minél hasonlóbb szerkezeteket használjunk a forrásrendszerhez képest. Viszont ha új fejleszt˝oket vonunk be, akkor pedig az általánosan elfogadott, ismert konvencióknak megfelel˝o kódot célszer˝u generálni. • Az átfordított kódnak elfogadható hatékonyságúnak kell lennie. • Ha többször (pl.: rendszeresen) kell használni a fordítót, akkor annak is megfelel˝o hatékonyságúnak kell lennie. • Nem szabad túlzott méretnövekedést megengedni (a karbantarthatóság miatt). Sajnos egy teljes érték˝u fordító készítése általában nem megvalósítható. El˝oször is, ha sikerül egy natív konstrukciót natív konstrukcióra fordítani, nem biztos, ekvivalens kódot kapunk (habár szintaktikailag úgy t˝unhet). Ilyen esetek a típusok, típuskonverziók, hibák, mellékhatások eltér˝o kezeléséb˝ol adódhatnak. Például, az alábbi utasítások szintaktikailag ekvivalensek:
5
-- Transact-SQL: SELECT @x = col FROM t1 -- PL/SQL: SELECT col INTO v_x FROM t1 Viszont eltér˝o m˝uködést tapasztalunk, ha a t1 táblában nem pontosan 1 sor van: TransactSQL-ben ha kevesebb, mint 1 sor van, akkor a változó megtartja eredeti értékét, ha több, akkor pedig az utolsónak kiolvasott értéket kapja, míg PL/SQL-ben mindkét esetben kivétel dobódik2 . Másodszor, mikor egy magas szint˝u programnyelvr˝ol egy másik magas szint˝u programnyelvre fordítunk, akkor nem csak a nyelvi szerkezetek egymásnak történ˝o megfeleltetése szükséges, hanem a függvénykönyvtár-hívások megfeleltetése is[11]. Ezért egy teljes érték˝u fordító elkészítése csupán egy célként lebeghet a szemünk el˝ott, amit – a folyamatosan megjelen˝o új, illetve a változó függvénykönyvtárak miatt – valószín˝uleg sosem fogunk tudni elérni.
1.2. SQL Server és Oracle közötti migrációs eljárások A Microsoft SQL Server és az Oracle adatbáziskezel˝o közötti váltást els˝osorban üzleti szempontok motíválhatják. Mindkét gyártó támogatja a migrációs folyamatot automatizált fordítókkal, természetesen csak az egyik irányba. Oracle adatbázisról SQL Serverre (pontosabban a 2005-ös verzióra) való váltást az SSMA for Oracle (SQL Server Migration Assistant for Oracle) segíti. Ebben a dokumentumban a másik irányra koncentrálok, azaz hogyan, milyen módszertanok, eszközök segítségével lehet SQL Server adatbázisról Oracle adatbázisra átállni.
1.2.1. Az Oracle Relational Migration Map módszertan bemutatása Az Oracle Relational Migration Map[14] (röviden: Migration Map) az Oracle által használt és javasolt módszertan a meglév˝o adatbázisok Oracle platformra migrálásához. A módszertant els˝osorban az Oracle Technology Migration Factory mérnökei használják az ügyfelek adatbázisainak és alkalmazásainak migrációjához. Szerepkörök A módszertan az alábbi szerepköröket definiálja: • Ügyfél 2
ORA-01403: nincs adat és ORA-01422: a pontos lehívás a kívántnál több sorral tért vissza
6
• Migrációs projekt menedzser • Adatbázis migrációs mérnök • Alkalmazás migrációs mérnök Ügyfél
Az ügyfél els˝odleges feladata, hogy technikai segítséget nyújtson a migráció során a
rendszerrel kapcsolatban felmerül˝o kérdésekben. Ezen kívül a projekt elején ki kell tölteni egy úgynevezett Assessment Questionnaire3 -t, aminek célja az alapvet˝o követelmények meghatározása, a szükséges er˝oforrások felbecsülése, a jelenlegi alkalmazás bemutatása. Ezen kívül még el kell juttatnia az alkalmazás forráskódját a migrációs projekt menedzsernek. Az ügyfélnek a projekt során véleményeznie kell a migrációs csapat által leszállított dokumentumokat, programokat, script-eket, illetve meg kell vitatnia a migrációs projekt menedzserrel a felmerül˝o problémákat. Migrációs projekt menedzser A migrációs projekt menedzser áll a középpontban, o˝ felügyeli az egész projektet. Az o˝ feladata a min˝oségi munka biztosítása a migrációs mérnökök részér˝ol, illetve o˝ kezeli az ügyfél igényeit. Rajta keresztül zajlik a kommunikáció, o˝ tervezi meg a feladatokat, illetve azok id˝ozítését, a felmerül˝o problémák esetén o˝ tájékoztatja az ügyfelet, illetve o˝ szerzi be az engedélyeket a javasolt megoldások végrehajtásához. Adatbázis migrációs mérnök Az adatbázis migrációs mérnök az Oracle SQL Developer Migration Workbench (továbbiakban: OMWB) segítségével elvégzi a forrás adatbázis Oracle adatbáziskezel˝ore történ˝o migrációját, és teszteli, hogy ugyanúgy m˝uködik-e, mint a forrás adatbázis. Az o˝ feladata még, hogy megbecsülje a projekt elvégzéséhez szükséges er˝oforrásokat, illetve az id˝otartamot. Alkalmazás migrációs mérnök Ez a szerepkör igen hasonló az adatbázis migrációs mérnök szerepköréhez, azzal a különbséggel, hogy az els˝odleges feladat nem az adatbázis, hanem a hozzá kapcsolódó alkalmazás forráskódjában szükséges változtatások megtervezése és megvalósítása annak érdekében, hogy az alkalmazás képes legyen Oracle adatbáziskezel˝ot használni. Projekt fázisok A migrációs projekt az 1.2. ábrán látható módon 6 fázisra van bontva. A fázisok során az ábra bal oldalán felsorolt kategóriákba tartozó feladatokat kell elvégezni. 3
http://www.oracle.com/technology/tech/migration/maps/assessment_questionnaire.doc
7
1.2. ábra. Fázisok a Migration Maps módszertanban [14]
Definíciós fázis
A definíciós fázis arról szól, hogy elegend˝o információt gy˝ujtsünk a meglév˝o
rendszerr˝ol, hogy aztán megfelel˝o becsléseket (er˝oforrás, id˝o) tudjunk készíteni a migrációról. A meglév˝o rendszer vizsgálata magában foglalja a különböz˝o adatbázis objektumok típusainak, méretének, darabszámának kigy˝ujtését, az alkalmazás forráskódjából egy úgynevezett inventory készítését, amiben szintén rögzítjük a forrásfile-ok típusait illetve méretüket. Az ügyfél ebben a fázisban tölti ki a már említett Assessment Questionnaire-t annak érdekében, hogy a migrációt végz˝o mérnökök feltudják becsülni a feladat végrehajtásához szükséges er˝oforrásokat. A migráció megkezdéséhez meg kell határozni az alapvet˝o architektúrális technikai követelményeket, ami az alábbi információk begy˝ujtéséb˝ol áll: • Interface követelmények • Adatbázis partícionálási követelmények • Adatbázis biztonsági követelmények • Adatbázis adminisztrációs követelmények • Alkalmazás architektúra • Biztonsági mentési és visszaállítási stratégia Az alapvet˝o követelményeken kívül a módszertan definiálja a teljes architektúrális technikai követelmények fogalmát is, ami az alábbi részekb˝ol áll: • Operációs rendszer stratégia és architektúra • Hardver és tárolási stratégia • Adatbázis verzió stratégia 8
• Középs˝o réteg stratégia és architektúra • Hálózati stratégia és architektúra • Rendszer integrációs stratégia és architektúra • Skálázhatósági és teljesítmény stratégia Ebben a fázisban történik a forrás adatbázis metaadatainak kigy˝ujtése az Oracle Migration Workbench segítségével: az ügyfél, vagy a migrációt végz˝o mérnökök a program segítségével elkészítik az úgynevezett Captured Model-t (lásd kés˝obb). Analízis Az analízis fázisban kezd˝odik az igazi munka. Egyeztetni kell az ügyféllel a definíciós fázisban felderített kérdéseket, problémákat, javaslatokat. Meg kell vizsgálni az alap és a részletes architektúrális technikai követelményeket, hogy a következ˝o, tervezési fázisban el lehessen készíteni a célrendszer architektúrális terveit. Egy migráció során nem triviális, hogy az ügyfél mennyire ismeri a célrendszert, annak sajátosságait, a forrásrendszerrel szembeni különbségeit, ezért fontos feladat az oktatás. Az analízis fázisban kell meghatározni, hogy az ügyfélnek milyen témákban van szüksége oktatásra. Az ügyfélnek el kell készítenie a tesztelési és átállási követelményeket, amikben specifikálja a tesztelési ciklusokat, tesztel˝o scripteket, illetve az átállással kapcsolatos ütemezést, üzleti és hardver követelményeket. Tervezés A tervezési fázisban a migrációt végz˝o mérnökök a definíciós és analízis fázisok során szerzett ismeretek alapján megtervezik a felmerült feladatok, problémák megoldását, azaz elkészítik az oktatási tervet, a célrendszer hardver, hálózati és szoftver architektúráját, a felmerült architektúrális problémákra a megoldási terveket, az adatok migrációjának a stratégiáját, illetve az átállási stratégiát. Migráció
A migrációs fázis célja, hogy tömör, megbízható script-ek és riportok álljanak az
ügyfél rendelkezésére, amikb˝ol felépítheti a célrendszer alatt az adatbázis sémát. Ebben a fázisban mind a migrációs mérnököknek, mind az ügyfélnek részt kell venniük oktatásokon, hogy rendelkezzenek az adatbázis és az alkalmazás migrációjához szükséges ismeretekkel. A fázis legfontosabb része a séma illetve a tárolt programok migrációjának elkészítése, azaz DDL (Data Definition Language) utasításokat tartalmazó scripteket kell készíteni, amik létrehozzák a táblatereket, felhasználókat, táblákat, kulcsokat, indexeket, tárolt eljárásokat, függvényeket, stb. Miután megtörtént a script-ek leszállítása, az ügyfél megvizsgálja a migrált sémát, és aláírásával igazolja annak helyességét. 9
Ezzel párhuzamosan történhet az alkalmazás migrációja, ami az analízis fázis során felderített esetlegesen problémás kódrészletek egyesével történ˝o vizsgálatát, és a szükséges módosítások elvégzését jelenti. A megállapodástól függ˝oen a tesztelést vagy a migrációt végz˝o mérnökök, vagy az ügyfél végzi. Átállás
Az átállás fázis – mint ahogy a nevéb˝ol is következik – az átállást hivatott megvalósí-
tani, azaz a migrált rendszer feltelepítését, ügyfél általi tesztelését, adatkonverziót illetve élesbe állítást. Az átálláshoz célszer˝u három különálló rendszert felépíteni, egy fejlesztéshez használt DEV környezetet, teszteléshez használt TEST környezetet, illetve az éles m˝uködéshez használt PROD környzetet. A tesztelésnél a DEV környezetr˝ol egy pillanatkép készül, majd ezt követ˝oen telepíteni kell a TEST környezetre az aktuális állapotot. Ezen történnek majd többek között a UAT (user acceptance test) tesztek. Amennyiben minden teszt sikeresen lezárult, következhet a PROD környezet feltelepítése a TEST környezetr˝ol. Üzemeltetés Az utolsó, üzemeltetési fázisban a megállapodástól függ˝oen szükség lehet a már feltelepített, éles rendszerben támogatás nyújtására.
1.2.2. Migrációt segít˝o szoftverek bemutatása A migráció során felmerül˝o részfeladatok automatizálására, megkönnyítésére több eszköz is rendelkezésre áll. Ezek sikeres használhatósága több szemponton is múlik: • El˝oször is pontosan tudnunk kell, hogy mit csinál az adott eszköz. A fekete doboz megközelítés itt nem megengedhet˝o. Rendelkezésre kell állnia egy részletes dokumentációnak, amiben a gyártó specifikálja, hogy mit mire képez le az eszköz, ez milyen esetekben jó, és mikor igényel további kézi beavatkozást. Az 1.2.3 fejezetben részletesen megindoklom, hogy miért nincs értelme a teljes migrációs folyamat automatizálásának. • Másodszor pedig tudnunk kell, hogy mit nem csinál: a dokumentációban szerepelnie kell, hogy milyen konstrukciók fordításával nem foglalkozik az eszköz, akár az aktuális verzió limitációjából, akár a nyelvek különbségéb˝ol adódó korlátok miatt. Erre kiváló példa [12], amiben például a szerz˝ok leírják, hogy habár SQL Server és Oracle alatt a SELECT utasítással egy változónak történ˝o értékadás szemantikailag nem ekvivalens4 , a fordító 4 A hibakezelés miatt, lásd: @@error és ORA-01403: no data found és ORA-01422: too many rows
10
ezzel nem foglalkozik. A továbbiakban vázlatosan bemutatok három ilyen eszközt a gyártók dokumentációja illetve saját tapasztalatok alapján. Az Oracle SQL Developer Migration Workbench lehet˝oségei Az Oracle SQL Developer Migration Workbench (röviden OMWB) az eredetileg Oracle Migration Workbench néven futó migrációt segít˝o különálló szoftver újraírt, kiegészített, és az SQL Developerbe integrált változata. Az OMWB segítségével Microsoft Access, SQL Server, MySQL és Sybase adatbázisokat lehet Oracle adatbázis alá migrálni. Kiemelend˝o, hogy az OMWB részletes, átlátható dokumentációval rendelkezik ([12]), mely szisztematikusan bemutatja a támogatott fordítási lehet˝oségeket, és külön jelzi, hogy mely területek igényelnek manuális beavatkozást. Sajnos hibás állításokat is tartalmaz az SQL Server-rel kapcsolatban. Például, a NULL értékek kezelését illet˝oen azt állítja, hogy a NULL = NULL kifejezés true, ami nyilvánvalóan hibás: a kifejezés értéke az ANSI_NULLS5 beállítás értékét˝ol függ[16]. Ez is azt az álláspontot igazolja, hogy amíg vélt, vagy valós különbségek vannak az adatbáziskezel˝o rendszerek között, addig a köztük történ˝o migráció egy szakértelmet igényl˝o mérnöki feladat lesz, melyet az automatizáló szoftverek maximum segíthetnek, helyettesíteni nem tudják. Az OMWB migrációs beállításainak bemutatásához, illetve a migrációs folyamat részletezéséhez lásd az A. fejezetet. A SwisSQL Migration Tool lehet˝oségei Az Oracle SQL Developer Migration Workbench-en kívül találhatunk még más szoftvereket is a migráció bizonyos részeinek automatizálására. Az egyik konkurens termék a SwisSQL SQL Server to Oracle Migration Tool (a továbbiakban: SwisSQL). A SwisSQL-t az AdventNet cég készítette. Ezzel SQL Server 2000 adatbázisokat (pontosabban csak adatbázis objektumokat) lehet Oracle 8, 9i, 10g adatbázis alá migrálni. Ha adatokat is szeretnénk migrálni, akkor külön meg kell vásárolni a SwisSQL Data Migration Tool-t. A SwisSQL bizonyos szempontból az OMWB ellentéte: míg az OMWB részletes dokumentációkkal segíti a felhasználót, addig a SwisSQL-ben mindössze egy vázlatos Súgó áll a rendelkezésre. A cég a terméket kvázi szolgáltatásként pozícionálja: ha adatbázist szeretnél migrálni, egyrészt vedd meg a szoftvert, másrészt vedd igénybe a támogatásunkat. Emiatt a megközelítés 5
Megjegyzend˝o, hogy ez a beállítási lehet˝oség az SQL Server következ˝o verzióiban meg fog sz˝unni, és csak az ANSI szabványnak megfelel˝o m˝uködést lehet majd elérni.
11
miatt a SwisSQL értékelésére nincs mód, következtetéseket csak tapasztalat útján lehetne levonni, amit tovább nehezít az ingyenes változatban lev˝o korlátozás: maximum 2000 sor kódot hajlandó lefordítani. Az SQLWays lehet˝oségei Az SQLWays az Ispirer cég által fejlesztett migrációs szoftver. A SwisSQL-hez hasonlóan ez is egy kereskedelmi termék, ingyenesen csak egy próbaverzió áll rendelkezésre. Ami kiemeli az el˝oz˝o két szoftver közül az az, hogy – a honlapja6 szerint – 22 forrás- és 8 cél-adatbáziskezel˝ot támogat. Rendelkezik dokumentációval ([13]), ami viszont nem felel meg az 1.2.2. fejezetben ismertetett követelménynek: számos esetben nem lehet tudni, hogy mit mire fordít. Kiragad problémákat, amikre bizonyos forrás-cél konfigurációk esetén megadja a leírást, más esetekben nem. Például sehol sem említi, hogy SQL Server → Oracle irány esetén hogyan kezeli a tárolt eljárások által visszaadott eredményhalmazok kérdését. A SwisSQL-hez hasonlóan az SQLWays részletes tárgyalása sem megvalósítható, mert sem kielégít˝o dokumentáció, sem teljes érték˝u ingyenes változat nem áll rendelkezésre.
1.2.3. A migrációs eszközök korlátai A bemutatott eszközök vegyesen próbálják megközelíteni a tárolt programok átfordítását: van, ahol szimulálnak egy nyelvi konstrukciót, függvényt, van, ahol szintaktikailag ekvivalens, natív konstrukciót alkalmaznak (és a dokumentációban kijelentik, hogy szemantikailag nem ekvivalens), és van, ahol egész egyszer˝uen hibásan fordítanak. Ebben a részben sorra veszem azokat a területeket, amik miatt az automatikus fordítók csupán korlátozott sikert érhetnek el: a natív konstrukciók más m˝uködésre vezetnének, a szimuláció pedig túlburjánzó, karbantarthatatlan és fölösleges kódot eredményezne. Azonosító nevek, fenntartott kulcsszavak Az SQL Server az azonosító nevek tekintetében igen laza: engedi, hogy oszlopnévnek fenntartott, vagy kulcsszót adjunk (pl.: date), az objektumok nevei igen hosszúak is lehetnek, és természetesen az SQL Server által fenntartott szavak listája közel sem egyezik meg az Oracle adatbáziskezel˝o által fenntartott szavakkal. Ökölszabályként kijelenthet˝o, hogy ne használjunk se fenntartott, se kulcsszavakat azonosító névként7 . Ha vannak ilyenek, akkor azokat a forrás oldalon is nevezzük át. Egy fontos szabály, amit nem lehet áthágni: azonosító név maximum 30 karakter (30 byte) hosszú lehet (kivéve adatbázis név - 8 byte, adatbázis-link név - 128 byte). Ha van olyan táblánk, 6
http://www.ispirer.com Oracle alatt fenntartott és kulcsszavak listája: http://68.142.116.68/docs/cd/B28359_01/appdev.111/b31231/appb.htm 7
12
oszlopnevünk, T-SQL változónk, függvényünk, stb., ami 30 karakternél hosszabb, akkor azt át kell nevezni (a Migration Workbench egyszer˝uen levágja a végét, ha névütközés van, akkor sorszámmal látja el az azonos neveket, pl: myverylongtable_1, myverylongtable_2, stb.). A ""-k között szerepl˝o fenntartott szavak lehetnek azonosító nevek, például: "DATE", de ebb˝ol lehetnek problémák: Ha egy date típusú oszlopnak a "DATE" nevet adjuk, akkor – habár a tábla létrejön – majdnem minden hivatkozás az adott táblára hibát fog eredményezni: ORA-06550: line 5, column 61: PL/SQL: ORA-06552: PL/SQL: Compilation unit analysis terminated ORA-06553: PLS-320: the declaration of the type of this expression is incomplete or malformed ORA-06550: line 5, column 2: Az igazán nagy problémát az jelenti, hogy ha átnevezünk egy azonosítót, akkor minden rá történ˝o hivatkozást is módosítani kell. Ez kihathat az adatbázishoz csatlakozó kliensekre is. Ezért ezt a problémát még a fordítás megkezdése el˝ott, attól függetlenül kell kezelni: olyan elnevezési konvenciókat kell bevezetni, amikkel ez a probléma megsz˝unik. Tranzakciókezelés Az SQL Server és az Oracle adatbáziskezel˝o tranzakció kezelése alapvet˝oen különbözik egymástól. Microsoft SQL Server 2000 alatt három féle módon lehet tranzakciót kezdeni: • explicit módon: egy BEGIN TRANSACTION utasítás kiadásával • implicit módon: amennyiben a SET IMPLICIT_TRANSACTIONS ON utasítással bekapcsoltuk ezt a módot, akkor az ezt követ˝o utasítás automatikusan egy tranzakciót fog nyitni. Amikor az befejez˝odik, akkor a következ˝o utasítás egy új tranzakciót kezd, és így tovább. • autocommit: ez az alapértelmezett mód az SQL Server-ben: minden egyes T-SQL utasítás vagy véglegesítésre kerül (commit), vagy visszagörget˝odik (rollback). Explicit tranzakciók esetén a programozó határozza meg a tranzakció elejét és végét is, Transact-SQL scriptek esetén BEGIN TRANSACTION / COMMIT / ROLLBACK utasításokkal, ADO.NET esetén pedig az SqlConnection objektum BeginTransaction() illetve Commit() / Rollback() metódusaival. A BEGIN TRANSACTION utasítás 1-el növeli a @@TRANCOUNT változó értékét (alapesetben a változó 0), a COMMIT 1-el csökkenti, míg a ROLLBACK 0-ra állítja. Ez azért van 13
így, mert SQL Server alatt úgy lehet tranzakciókat egymásba ágyazni, hogy a beágyazott tranzakciók esetében az adatbázis a COMMIT utasításokat figyelmen kívül hagyja, csak a legküls˝o COMMIT után lesznek a módosítások véglegesítve. A ROLLBACK utasítás viszont minden aktív tranzakciót visszagörget. Ezzel szemben Oracle adatbáziskezel˝o alatt egy tranzakció az els˝o végrehajtható SQL utasítással kezd˝odik, és vagy akkor ér véget, amikor explicit módon kiadunk egy COMMIT illetve ROLLBACK utasítást, vagy implicit módon, pl.: egy DDL utasítás végrehajtásával, vagy az adatbázisból történ˝o kilépéskor (disconnect). Léteznek még úgynevezett autonóm tranzakciók (autonomous transactions), amik teljesen függetlenek a "hívó" tranzakciótól. Például, ha egy tárolt eljárás az AUTONOMOUS_TRANSACTION direktívával lett lefordítva, akkor, amikor meghívódik egy küls˝o tranzakcióból, nem látja annak a még nem véglegesített adatait, illetve t˝ole függetlenül lesz véglegesítve vagy visszagörgetve. Ez például naplózást megvalósító eljárások esetén lehet hasznos. Kérdéses lehet, hogy ezek után egy begin tran... commit blokkot hogyan lehet PL/SQL-re fordítani. Sajnos a – diplomatikus – válasz az, hogy attól függ. Amennyiben ez a legküls˝o blokk egy végrehajtás során, akkor a begin utasítást elhagyjuk, a commit-ot meg meghagyjuk. Ekkor közel azonos m˝uködést érhetünk el. Viszont, ha ez egy beágyazott tranzakció, azaz már a hívó eljárás megnyitott egy tranzakciót, akkor ezen két utasítás hatása mindösszesen annyi, hogy a @@TRANCOUNT változó értékét módosítják. Tehát a tranzakciókezel˝o utasítások m˝uködése a futási lánctól függ. Ezen kívül van még egy fontos különbség a két rendszer között: máshogy kezelik a zárolásokat. Az alapértelmezett izolációs szinten (READ COMMITTED) az SQL Server a SELECT utasítás hatására egy shared zárat helyez a táblára, míg az Oracle semmilyet se. Gondoljuk végig, hogy ez mit jelent: egy SELECT tehát csak akkor tud lefutni SQL Server alatt, ha rá tud tenni egy shared zárat, azaz a táblán maximum shared zár van jelenleg (nincs exclusive zár). Ennek következtében a SELECT és az UPDATE utasítások fizikailag szerializáltan hajtódnak végre [16]. Ezzel szemben Oracle alatt egy SELECT utasítást nem blokkol semmi, és egy SELECT utasítás nem blokkol senkit (FOR UPDATE klauzula nélkül) [17]. Képzeljünk el egy olyan T-SQL tárolt eljárást, ami kiolvassa egy számla egyenlegét egy változóba, elszöszmötöl egy darabig, majd – ha van elég pénz az egyenlegen – csökkenti azt. Ennek az eljárásnak a kódja valahogy így nézhet ki: declare @balance money begin transaction select @balance = balance from tran_balance where userid=20 14
-- some very serious calculation.. if @balance > 1500 update tran_balance set balance=balance-1500 where userid=20 commit transaction Mi itt a hiba? Ez a kód bizonyos id˝ozítés mellett helyesen m˝uködik SQL Server alatt, Oracle alatt viszont (alapértelmezett izolációs szinten) szinte sehogy se. Tegyük fel, hogy az 1.3 ábrán látható módon indul el két tranzakció.
1.3. ábra. Két tranzakció konkurrens végrehajtása
SQL Server alatt az alábbi lépések fognak történni: • A SELECT kirak egy shared lock-ot a táblára • Az UPDATE kirak egy exclusive lock-ot a táblára • Indulna a 2. tranzakció, de a SELECT nem tud shared lock-ot kirakni, mert a másik tranzakció exclusive lock-ja még érvényben van • Az els˝o tranzakció lefut, végrehajtódik a COMMIT utasítás • Elindul a 2. tranzakcióban lev˝o SELECT utasítás is, és az els˝o tranzakció által véglegesített értéket olvassa ki. Ha az id˝ozítésen variálunk egy picit, pl: feljebb „toljuk” a 2. tranzakció SELECT-jét az els˝o tranzakció SELECT és UPDATE utasítása közé, akkor SQL Server-en is „nem várt” m˝uködést tapasztalhatunk: • lefut az els˝o SELECT • lefut a második tranzakció SELECT-je is, a shared lock miatt (a shared lock-ok egymással kompatibilisek) lefut az els˝o UPDATE • a második UPDATE blokkolódik, egészen addig, amíg az els˝o tranzakció nem fejez˝odik be. 15
Mi a helyzet Oracle alatt? A SELECT utasítás mindkét (bármilyen) esetben le fog futni, kiolvasva az utolsó elcommitált értéket. A fenti példakód esetében tehát a konkurens tranzakciók lehet, hogy úgy terhelik be az egyenleget, hogy már nincs is rajta fedezet. Azaz, ha automatikusan fordítjuk át T-SQL kódjainkat PL/SQL-re, akkor a fenti „kicsit” rossz kódból nagyon rossz kódot kapunk. Ebben a példában két lehet˝oség van a javításra, Oracle oldalon. Az egyik a SERIALIZABLE izolációs szint használata: ezen a szinten lev˝o tranzakciók ha egy tábla olyan sorát szeretnék módosítani, amit egy másik – még el nem commitált – tranzakció már módosított, akkor hibát kapunk akkor, amikor a másik tranzakció elengedi a zárait: Hiba a(z) 1. sorban: ORA-08177: ehhez a tranzakcióhoz nem lehet sorbarendezni a hozzáférést ORA-06512: a(z) helyen a(z) 6. sornál A másik megoldás a LOCK TABLE használata: még miel˝ott bármit is olvasnánk a táblából, rárakunk egy zárat. Ezzel elérhetjük az SQL Server-éhez hasonló m˝uködést, azzal a különbséggel, hogy nem a SELECT utasítás fog blokkolódni, hanem az el˝otte lév˝o LOCK TABLE. Adattípusok A támogatott adattípusokból ered˝o probléma súlyát a két gyártó egymástól eltér˝oen ítéli meg. [15] szerint habár az SQL Server és az Oracle adattípusai különböznek egy kicsit, ennek igen kis hatása van a migrációra nézve. Ezzel szemben [3] azt írja, hogy a legtöbb Oracle adattípusnak nincs pontos SQL Server oldali megfelel˝oje. A továbbiakban ezeket a különbségeket veszem sorra. Karakteres adattípusok
A karakteres adattípusok összehasonlítását az 1.2 táblázat mutatja.
A táblázatban felsorolt típusoknak mindkét rendszer alatt megvan a Unicode-os megfelel˝oje is (NCHAR, NVARCHAR...). A táblázat nem tartalmazza a már nem ajánlott típusokat (TEXT, NTEXT, LONG). A méretbeli különbségek az alkalmazástól függ˝oen okozhatnak gondot. Fontos még tudni, hogy Oracle alatt az, hogy egy karakteres adattípus n byte vagy n karakter méret˝u, az az NLS_LENGTH_SEMANTICS paramétert˝ol függ. Dátum típusok A dátum adattípusok összehasonlítását az 1.3 táblázat mutatja. Mindkét rendszer rendelkezik dátum és id˝o tárolására alkalmas adattípusokkal, viszont ezek pontossága, és a bennük tárolható adatok értéktartománya is különbözik. Az alkalmazási területt˝ol függ, hogy
16
SQL Server CHAR fix hosszúságú, n byte-os típus, ahol 0 < n <= 8000 VARCHAR változó hosszúságú, n byte-os típus, ahol 0 < n <= 8000 VARCHAR(max) változó hosszúságú, maximum 231 − 1 byte méret˝u
Oracle CHAR fix hosszúságú, n byte-os/karakteres típus, ahol 0 < n <= 2000 VARCHAR2 változó hosszúságú, n byte-os/karakteres típus, ahol 0 < n <= 4000 CLOB változó hosszúságú, maximum 128 terabyte méret˝u
1.2. táblázat. Karakteres adattípusok összehasonlítása Oracle és SQL Server alatt. Forrás: [16], [17]
ezeket a különbségeket figyelmen kívül hagyhatjuk-e, vagy kezelnünk kell o˝ ket (pl.: DATE helyett TIMESTAMP ha szükséges a pontosság, illetve CHECK CONSTRAINT-ek alkalmazása, ha sz˝ukebb értéktartományra van szükség). Fontos látni azt, hogy a helyes döntést egy algoritmus itt nem tudja meghozni, ehhez a teljes rendszert átfogó elemzésre van szükség. SQL Server DATETIME Dátum és id˝o tárolására alkalmas típus, értéktartomány: 1753-01-01 – 9999-1231, pontosság: 3.33 ms
SMALLDATETIME Dátum és id˝o tárolására alkalmas típus, értéktartomány: 1900-01-01 – 2079-0606, pontosság: perc
Oracle DATE Dátum és id˝o tárolására alkalmas típus, értéktartomány: I.e. 4712-01-01 – 999912-31, pontosság: másodperc TIMESTAMP Dátum és id˝o tárolására alkalmas típus, értéktartomány: I.e. 4712-01-01 – 999912-31, pontosság: másodperc 10−9 -ed része DATE
1.3. táblázat. Dátum adattípusok összehasonlítása Oracle és SQL Server alatt. Forrás: [16], [17]
Numerikus típusok
A numerikus adattípusok összehasonlítását az 1.4 táblázat mutatja. Az
eltérések itt is az értéktartományok különbségéb˝ol adódnak. Ha szükséges az azonos tartományok kikényszerítése, alkalmazhatunk CHECK CONSTRAINT-eket.
17
SQL Server BIGINT −263 – 263 INT −231 – 231 SMALLINT −215 – 215 TINYINT 0 – 255 DECIMAL(p,s), NUMERIC(p,s) Fix pontosságú számok tárolására alkalmas típus, maximum −1038 +1 – 1038 −1 MONEY −922, 337, 203, 685, 477.5808 – 922, 337, 203, 685, 477.5807 SMALLMONEY −214, 748.3648 – 214, 748.3647 FLOAT(n) Lebeg˝opontos számok 4 vagy 8 byte-on tárolva (n függvénye) REAL Ekvivalens a FLOAT(24)-el BIT 0 vagy 1
Oracle NUMBER(19) Maximum 19 számjegyb˝ol álló egész. NUMBER(10) Maximum 10 számjegyb˝ol álló egész. NUMBER(5) Maximum 5 számjegyb˝ol álló egész. NUMBER(3) Maximum 3 számjegyb˝ol álló egész. NUMBER(p,s)
NUMBER(19,4) Maximum 19 egész és 4 tizedes jegyb˝ol álló szám NUMBER(6,4) Maximum 6 egész és 4 tizedes jegyb˝ol álló szám FLOAT(n) A NUMBER altípusa, n pontossággal, 1-22 byte-on tárolva FLOAT(24) NUMBER(1) 1 számjegyb˝ol álló egész.
1.4. táblázat. Numerikus adattípusok összehasonlítása Oracle és SQL Server alatt. Forrás: [16], [17]
18
LOB típusok A LOB típusok szolgálnak nagy méret˝u adatok tárolására. Ezek összehasonlítását mutatja az 1.5 táblázat. SQL Server VARCHAR(max) Maximum 231 − 1 byte méret˝u NVARCHAR(max) Maximum 231 − 1 byte méret˝u, Unicode szöveg VARBINARY(max) Maximum 231 −1 byte méret˝u bináris adat
Oracle CLOB Maximum 128 terabyte méret˝u NCLOB Maximum 128 terabyte méret˝u Unicode szöveg BLOB Maximum 128 terabyte méret˝u bináris adat
1.5. táblázat. LOB adattípusok összehasonlítása Oracle és SQL Server alatt. Forrás: [16], [17]
XML típus Az XML adattípus az SQL Server 2005-ös verziójában jelent meg. Az Oracle oldali megfelel˝oje az XMLType. Típusok közti konverziók A típuskonverziókat felbonthatjuk explicit és implicit konverziókra. Explicit típuskonverzió az, amikor a programozó explicit kijelenti, hogy mit és mire szeretne konvertálni, implicit konverzió pedig az, amikor ezt a döntést ráhagyjuk az adatbáziskezel˝ore. Explicit konverziók SQL Server alatt az explicit típuskonverziót a CAST és CONVERT függvények valósítják meg[16]: CAST ( expression AS data_type [ (length ) ]) CONVERT (data_type [ ( length ) ] ,expression [ , style ]) A CONVERT függvény SQL Server specifikus, és nagyobb rugalmasságot biztosít dátumok és tört számok konvertálásakor. A CAST pedig inkább ANSI-szer˝u, ezért többé-kevésbé ugyanolyan szintaxissal lehet használni a különböz˝o adatbázis szerverek alatt. Implicit konverziók Implicit konverzió például akkor történik, amikor két különböz˝o típusú adatot hasonlítunk össze, vagy ha egy tábla adott oszlopába szúrunk be egy attól különböz˝o típusú értéket. Az implicit konverzió a felhasználó el˝ol rejtve marad. A lehetséges implicit konverziókat mindkét gyártó mátrix formájában adja meg a dokumentációban: melyik típusról milyen típusra hajlandó automatikusan konvertálni.
19
Ami különbözik, az a konverzió módja, például: milyen formában megadott dátumot tartalmazó karaktersorozatból hajlandó dátum típusú értéket konvertálni. Az SQL Server elfogadja az ÉÉÉÉ-HH-NN, ÉÉÉÉ.HH.NN, NN-HH-ÉÉ, NN.HH.ÉÉ formátumok közül bármelyiket. Oracle alatt viszont ez a formátum a v$NLS_PARAMETERS táblában van tárolva: select value from v$NLS_PARAMETERS where parameter = ’NLS_DATE_FORMAT’ --------RR-MON-DD Habár implicit típuskonverzió alkalmazása több okból is helytelen (a kód nehezebben értelmezhet˝o, nem feltétlen optimális az utasítások végrehajtása performancia szempontból, a különböz˝o verziók során változhatnak a konverziós szabályok, stb.), mégis sokan alkalmazzák. Ezért a migráció során figyelnünk kell arra is, hogy az esetleges implicit konverziókat vagy explicitté, vagy „megfelel˝o” implicitté tegyük. Visszatérési értékek SQL Server alatt egy tárolt eljárás háromféle módon képes adatokat visszaadni a hívója felé: • kimen˝o paraméterekkel: CREATE PROCEDURE sp_demo (@something int OUT) • visszatérési értékkel: return @someValue • úgynevezett eredményhalmazokkal (result set-ekkel): egy T-SQL tárolt eljárás képes visszaadni egy tetsz˝oleges SELECT utasítás által visszaadott eredményhalmazt Kimen˝o paraméterekb˝ol és visszaadott eredményhalmazokból tetsz˝oleges számú lehet. Egy példa ezen módok bemutatására: CREATE PROCEDURE sp_demo (@something int out) AS begin set @something = 5 select 7 return 9 end
20
1.4. ábra. Egy T-SQL tárolt eljárás lehetséges visszatérési értékei
Az eljárást futtatva az 1.4. ábrán látható eredményt kapjuk. Az els˝o eredményhalmazt a tárolt eljárás adta vissza (SELECT 7), a második pedig az @i, @j változók tartalmát mutatja. Oracle adatbáziskezel˝o alatt viszont egy tárolt eljárás csak kimen˝o paraméterekkel képes adatokat visszaadni. Nincs sem visszatérési érték, sem eredményhalmaz. Eredményhalmazokat kurzor referenciákkal (REF CURSOR vagy SYS_REFCURSOR) lehet emulálni. Az OMWB és a SwisSQL is ezt a módszert követi: ha egy T-SQL tárolt eljárás eredményhalmazokat adna vissza, azt úgy fordítja át PL/SQL-re, hogy felvesz annyi darab kurzor referencia kimen˝o paramétert, ahány eredményhalmazt az eljárás visszaad. Például, a fenti sp_demo eljárás PL/SQLes változata így nézne ki: CREATE OR REPLACE FUNCTION sp_demo ( v_something OUT NUMBER, cv_1 IN OUT SYS_REFCURSOR ) RETURN NUMBER AS BEGIN v_something := 5; OPEN cv_1 FOR SELECT 7 FROM DUAL ; RETURN 9; END;
21
Az OMWB ilyen esetekben függvénnyé alakítja a tárolt eljárásunkat. Ez azért van, mert visszatérési értéke csak és kizárólag függvényeknek lehet PL/SQL-ben. Viszont egy függvény és egy tárolt eljárás között számos lényegi különbség van, amik miatt nem szerencsés csak úgy egyikb˝ol a másikat csinálni. Egy függvény nem végezhet adatmódosító (DML) utasításokat SQL utasításokban, más a hívás módja is (pl.: .NET-b˝ol). Csupán azért alakította a migráló eszköz függvénnyé, mert csak azoknak lehet visszatérési értéke. A SwisSQL-ben egy konfigurációs paraméter segítségével adhatjuk meg, hogy az ilyen eljárásokat alakítsa-e függvénnyé, vagy vegyen fel egy RETURNPARAMETER nev˝u kimen˝o paramétert, ami a visszatérési értéket tartalmazza. Ökölszabályként kijelenthet˝o, hogy ha vannak olyan T-SQL tárolt eljárásaink, amiknek van visszatérési értékük, akkor célszer˝u részletesen megvizsgálni, hogy hogyan alakítsuk át o˝ ket. Például felvehetünk kimen˝o paramétereket, vagy, ha eddig valójában függvényként használtuk az eljárást, akkor alakítsuk is át függvénnyé. Az eredményhalmazok kérdése viszont egyéb problémákat vet fel: a kimen˝o paramétereket az eljárás hívásakor legtöbbször explicit fel kell venni. Ha egy eljárás hív egy másikat, akkor a hívó eljárásban is deklarálni kell egy kurzor változót, amit paraméterül adunk a másik eljárásnak. Az olyan tárolt eljárások esetében, melyek több eredményhalmazt adnak vissza, több kimen˝o kurzor változót kell deklarálni. Felmerülhet a kérdés, hogy miért nem valamilyen kurzor változókból álló kollekciót (tömböt) használunk. A válasz egyszer˝u: jelenleg nem támogatott: PLS-00990: Index Tables of Cursor Variables are disallowed PLS-00989: Cursor Variable in record, object, or collection is not supported by this release A második hibaüzenet kis bizakodásra adhat okot. Talán az Oracle adatbáziskezel˝o kés˝obbi változataiban támogatva lesz ez a módszer is.
1.3. Összefoglalás A fejezetben az adatbázisok közötti migráció f˝obb problémáit mutattam be, a hangsúlyt az SQL Server és Oracle adatbáziskezel˝o közötti különbségek bemutatására helyezve. Az alábbi felsorolásban összegzem a problémás területeket: • Adattípusok közötti különbségek: habár alkothatunk olyan leképezéseket a két rendszerben elérhet˝o adattípusok között, melyek az esetek jelent˝os részét lefedik, ezek helyessége mindig csak egy konkrét rendszer esetében igazolható a típusok pontosságának, értékkészletének különbségei miatt. A migrációs eszközök ezt a leképezések testreszabásával segítik. 22
• Azonosító nevek, fenntartott kulcsszavak: mind SQL Server, mind Oracle alatt rendelkezésre áll a kulcs és fenntartott szavak listája. Viszont azokat az adatbázis-objektumokat, amiknek a neve a cél-rendszerben ezen kategóriákba tartozik, nem célszer˝u automatizáltan átnevezni, ezeket a módosításokat az egész rendszeren végig kell vezetni, beleértve az adatbázishoz kapcsolódó kliens-alkalmazásokat is. Emiatt a pusztán adatbázis-migrációt segít˝o eszközök erre sem képesek megoldást nyújtani. • Tranzakciókezelés: a két rendszerben a tranzakciókezelés alapvet˝oen különbözik egymástól. SQL Server alatt a tranzakciót vezérl˝o utasítások jelentése az egymásba ágyazott tranzakciók koncepciója miatt a futási lánc függvénye, ezért ezek automatikus fordítása nem megvalósítható. Ezen felül a táblák illetve sorok zárolási mechanizmusa is különbözik (lásd: SELECT utasításnál a shared zárak esetét). Javaslom, hogy a tranzakciókezelés a célrendszer sajátosságait figyelembe véve mindig kerüljön manuális felülvizsgálatra. • Visszatérési értékek, eredményhalmazok: a tárolt eljárások által visszaadott eredményhalmazok hatékonyan szimulálhatóak a kimen˝o kurzor-változók segítségével. Ez egy jól automatizálható, fordító-programok által elvégezhet˝o feladat. Viszont figyelembe kell venni, hogy ez az átalakítás a kliens-alkalmazások módosítását is igényli. A visszatérési értékek szimulálására nincs mód, szintaktikailag a tárolt eljárás függvénnyé alakítása jelenthet (rész-)megoldást. Ezen eseteket egyedileg kell elbírálni. • Egyéb nyelvi különbségek: ezalatt azokat a nyelvi elemeket értem, amik hasonló formában léteznek mindkét rendszerben, közöttük meghatározható transzformáció. A következ˝o fejezetben bemutatott fordító program erre a problémára kíván megoldást nyújtani.
23
2. fejezet Fordító tervezése Az el˝oz˝o fejezetben bemutattam a Transact-SQL és a PL/SQL nyelvek közötti f˝obb különbségeket illetve hasonlóságokat. Bemutattam három szoftvert is, amik képesek – többé-kevésbé – helyes PL/SQL kódot el˝oállítani T-SQL kódból. Habár mindkét szoftvernek vannak hibái, limitációi, a migrációs folyamatban az adatbázis-objektumok, ezen belül is a tárolt programok átfordítását képesek – az ismertetett korlátok között – automatizálni, ami egy nagyobb rendszer migrációjakor hatalmas el˝ony. Ebben a fejezetben egy saját fordítót fogok tervezni. A cél nem az SQL Developer Migration Workbench-nél vagy a SwisSQL-nél jobb szoftver készítése, hiszen ezek sokkal több funkciót ellátnak a fordításnál, például: adatbázis-objektumok kódjának kiolvasása az adatbázisból (Capture), szintaxis-kiemelés. Egy komplex migrációs szoftver tervezése, implementálása meghaladja ezen dokumentum korlátait. Ezért én kifejezetten a fordításra fogok koncentrálni: az elkészített program a bemenetként kapott T-SQL kódból PL/SQL kódot fog el˝oállítani kimenetként. Más funkciója nem lesz. A fejezetben el˝oször definiálom a formális nyelvi elemzés használt alapfogalmait, majd vázlatosan bemutatom a fordító készítéséhez használt keretrendszert: az ANTLR-t1 . Az ANTLR is hagyományos értelemben egy fordító: a bemenetként kapott nyelvtanból programkódot állít el˝o. Készíttethetünk vele nyelvi elemz˝oket2 , interpreter-eket, illetve fordítókat. A fejezet második része a funkcionális terv: részletesen bemutatom a rendszer célját, komponenseit, specifikálom, hogy mely utasításokat kell, hogy lefordítsa a fordító, és melyeket nem (pl.: SQL Server specifikus rendszer-szint˝u tárolt eljárás). 1
http://www.antlr.org egy nyelvi elemz˝o (parser) a levezetési fa el˝oállításán keresztül eldönti egy mondatról, hogy az adott nyelv része-e 2
24
2.1. Formális nyelvi elemzés A nyelveket formálisan nyelvtanok segítségével írhatjuk le. Nyelvtanok segítségével a nyelv mondatai levezethet˝oek, generálhatóak.[1] A gyakorlatban a nyelvtanokat mégis arra használjuk, hogy eldöntsük, egy mondat eleme-e az adott nyelvnek. A nyelvtanokat egy négyes határozza meg: G = (N, Σ, P, S) ahol N a nyelvtani szimbólumok véges halmaza, Σ a nyelv karakterkészlete, alfabetája, P a levezetési, vagy másnéven helyettesítési szabályok összessége, S pedig a mondatszimbólum: a kályha – innen indul a levezetés. Egy levezetés mondatszer˝u formáknak nevezett jelsorozatok egymásutánja. A mondatszer˝u forma abban különbözik a mondattól, hogy abban nem csak a nyelv szimbólumai, vagyis a Σ elemei, hanem grammatikai szimbólumok is szerepelhetnek. A levezetés a mondatszimbólumtól indul: innen kezdve a helyettesítési szabályok alkalmazásával juthatunk el a nyelv egy mondatához. A fentiek illusztrálásához képzeljünk el egy olyan nyelvet, aminek a karakterkészlete: Σ = (a, b), és csak két szava lehet: aa, bb. Az ezt leíró nyelvtan például:
S→A S→B A → aa B → bb Az S mondatszimbólumtól indulva az A vagy B mondatszer˝u formán keresztül juthatunk el a nyelv szavaiig. A nyelvtanokat meghatározó helyettesítési szabályok (vagy másnéven levezetési szabályok) bonyolultsága alapján Chomsky a nyelveket osztályokba sorolta.[1] 3-as nyelvosztály A 3-as nyelvosztály nyelvtanaiban csak kétféle levezetési szabálytípus engedélyezett: A → a illetve A → aB ahol a nemterminális szimbólumokat nagy, a terminális szimbólumokat kis bet˝uvel jelöljük. Az ilyen alakú nyelvtanokat reguláris (jobbreguláris) nyelvtanoknak nevezzük. Ezek a nyelvtanok generálják a reguláris nyelveket.
25
2-es nyelvosztály A 2-es nyelvosztály helyettesítési szabályainak alakja: A→α ahol α tetsz˝oleges terminális és nemterminális szimbólumokat tartalmazható jelsorozat. Az ilyen alakú szabályokat úgy lehet értelmezni, hogy az A nemterminális szimbólum a környezetét˝ol függetlenül bármikor helyettesíthet˝o az α jelsorozattal. Ezért ezen nyelvosztály nyelveit környezetfüggetlen, Context Free (CF) nyelveknek nevezik. 1-es nyelvosztály Az 1-es nyelvosztály helyettesítési szabályainak alakja: βAγ → βαγ azaz a A → α szabály csakis a β − γ környezetben alkalmazható. Ezért ezeket a nyelveket környezetfügg˝o, Context Sensitive (CS) nyelveknek nevezik. 0-ás nyelvosztály A 0-ás nyelvosztályban alkalmazható szabályokra nézve nincsen korlátozás. Fordítók
Egy fordító általánosságban nem más, mint egy olyan program, ami valamilyen be-
meneti jelsorozatra valamilyen kimeneti jelsorozattal válaszol.[5] A különböz˝o bemenetekhez általában különböz˝o kimeneteket kell rendelni, azaz a fordítónak meg kell tudnia különböztetni egymástól az ilyen mondatokat, fel kell o˝ ket ismernie. A felismerés két fázisra bontható: lexikai és szintaktikai elemzés (lexing, parsing). A lexikai elemzés a bemeneti jelsorozatot tokenekre bontja. A szintaktikus elemz˝o bemenetként már nem karakterfolyamokat, hanem tokeneket ( szavakat) kap, és ezekb˝ol a tokenekb˝ol próbálja meg el˝oállítani a levezetési fát. Ha sikerül, akkor az adott mondat a nyelv része. A szintaktikus elemz˝ok általában interpreterek vagy fordítók részei, a feladatuk ebben az esetben a bemeneti tokenekb˝ol valamilyen bels˝o, köztes adatstruktúra felépítése. Ez a struktúra általában egy absztrakt szintaxis fa (AST).[5] A fordítás utolsó fázisa a kimenet el˝oállítása. Ez egyszer˝ubb esetekben történhet a szintaktikus elemz˝o kódjába akciók illesztésével (pl.: ha ’+’-t látsz, írj ki ’-’-t, és fordítva), összetettebb esetekben pedig az AST bejárása közben lépésr˝ol lépésre történik a kimenet el˝oállítása, amit egy utolsó, emitter fázis bocsát ki magából. A kimenet el˝oállítása történhet kézzel (pl.: print utasításokkal), vagy sablonok segítségével.
26
2.1.1. Az ANTLR elemz˝o-generátor bemutatása Az ANTLR egy olyan nyelvi elemz˝o generátor, ami képes lexikai, szintaktikai elemz˝oket készíteni, absztrakt szintaxis fákat építeni, illetve felhasználói akciókat (beágyazott programkódokat) végrehajtani.[6] A bemenetként kapott nyelvtanból az ANTLR egy rekurzív-leszálló LL(*) elemz˝ot készít: olyan LL(k) elemz˝ot, ami tetsz˝olegesen nagy el˝ore tekintést tesz lehet˝ové.[5] Ezen túlmen˝oen szemantikus és szintaktikus predikátumok segítségével lehet˝ové teszi számos környezetfügg˝o nyelv elemzését is.[6] A szemantikus predikátumokkal azt ellen˝orízhetjük, hogy egy levezetési szabályt alkalmazhatunk-e az adott környezetben. Egy szemantikus predikátum tetsz˝oleges logikai kifejezés lehet. Például, a levezetés attól függhet, hogy egy adott azonosító korábban miként volt deklarálva. Ebben az esetben egy szemantikus predikátummal belenézhetünk egy szimbólum-táblába, és eldönthetjük, hogy olyan típusú-e, mint amit keresünk. A szintaktikus predikátumok környezetfüggetlen nyelvtanok.[6] Segítségükkel sorrendet állíthatunk fel a többértelm˝u alternatívák között. Az ANTLR megpróbálja a szintaktikus predikátumban szerepl˝o nyelvtannak megfelel˝o levezetést el˝oállítani. Ha sikerül, akkor az adott alternatíva érvényes, ha nem, akkor a következ˝o alternatívával próbálkozik. Az LL(*) elemz˝o az alternatívák között egy véges automata (DFA – Deterministic Finite Automaton) segítségével dönt. Az ANTLR EBNF (Extended Backus-Naur Form) nyelvtanokat támogat[5], azaz támogatja a x+ (1 vagy többszöri ismétl˝odés), x* (0 vagy többszöri ismétl˝odés), x? (0 vagy egyszeri el˝ofordulás) posztfix operátorokat, ahol az x tetsz˝oleges nyelvi szimbólum, illetve a zárójelezést. Ezen kívül ha az elemz˝ovel egy szintaxis fát akarunk készíteni, lehet˝oség van úgynevezett fa-épít˝o operátorok, vagy szabályok alkalmazására: • El˝oször meg kell adnunk, hogy kimenetként egy AST-t akarunk el˝oállítani: options { output=AST; } • A fa megépítéséhez használhatunk posztfix operátorokat: subTableSource : dbObject^ (alias)? | ’(’! derivedTable^ ’)’! (alias)? ;
27
A ˆ operátorral mondhatjuk meg, hogy melyik elem legyen a gyökér, és a ! operátorral, hogy mely elemeket szeretnénk kihagyni. A fenti példában a dbObject lesz a gyökér-elem, aminek lehet egy opcionális alias gyereke. • vagy szabályokat: delete_statement : DELETE FROM? dbObject fromClause? whereClause? -> ^(DELETE ^(FROM dbObject) ^(FROM fromClause)? ^(WHERE whereClause)?) ; A -> operátor után ˆ (ROOT child1 child2 . . . childn) formában adhatjuk meg az elemeket, ahol ROOT a gyökér, és utána tetsz˝oleges számú gyerek szerepelhet.
2.1. ábra. Absztrakt szintaxis fa egy DELETE utasításból
A 2.1 ábrán egy AST-re láthatunk példát. Az elemz˝onek az alábbi utasítás volt a bemenete: DELETE FROM MyTable WHERE col1 > 50 Mint a példából is látható, egy szabályban egyszerre több gyökérelemet is megadhatunk, ezzel további szinteket képezhetünk a fában. Egy AST-vel szemben az alábbi követelményeket állíthatjuk[5]: • Tartalmazza a jelentéssel bíró tokeneket (és csak azokat), azaz sz˝urjük ki a szintaktikai édesít˝oszereket. 28
• Kétdimenziós formában kódolja a mondat nyelvtani szerkezetét. • Legyen könnyen értelmezhet˝o, illetve könnyen bejárható egy program számára. Ezeket a követelményeket a nyelvtanok készítésekor általános irányelvekként kezelhetjük. El˝ofordulhatnak olyan esetek, amikor a mondat értelme csak implicit szerepel a szövegben, a bemenetb˝ol nem tudunk olyan tokent kiválasztani, ami jó gyökér elem lenne. Például egy C-szer˝u nyelvben egy változó deklarációja így nézhet ki: int i;. Ennek a mondatnak a jelentése: „deklarálj egy int típusú, i nev˝u változót”. Ilyenkor felvehetünk absztrakt, vagy másnéven képzeletbeli csomópontokat, amik értelmesen kódolják a jelentést. Ezek a képzeletbeli csomópontok olyan tokenek, melyekhez nem tartozik bemenet, hanem a levezetés közben születtek. Az ANTLR segítségével tehát viszonylag kényelmesen készíthetünk nyelvi elemz˝oket: megadjuk a nyelvtant, melyet kiegészíthetünk tetsz˝oleges programkóddal, hogy akár környezetfügg˝o nyelveket is képes legyen leírni, majd az ANTLR elkészíti a nyelvtanhoz tartozó elemz˝ot, mely képes eldönteni egy bemeneti karaktersorozatról, hogy a nyelv része-e, és ha igen, akkor esetleg elkészíti a hozzá tartozó AST-t. Ha fordítót szeretnénk készíteni, akkor a feladat ezen AST bejárása, és transzformálása. Egy AST bejárásához készíthetnénk saját algoritmusokat, de ez fölösleges: egy AST is tekinthet˝o egy nyelvi elemz˝o bemeneteként, azaz az ANTLR-t használhatjuk arra is, hogy eldöntsük, egy AST eleme-e egy fa-nyelvtannak (tree grammar) vagy sem. Mindösszesen annyit kell tennünk, hogy a nyelvtan fejlécében megadjuk, hogy a bemeneti tokeneket nem a lexer szabályaink állítják el˝o, hanem azokat vegye a parser kimenetéb˝ol: options { tokenVocab=TSQL; } ahol a parser nyelvtan neve TSQL. A parser kimenete egy AST, melyet fa-készít˝o operátorokkal, vagy szabályokkal készíthetünk el. Egy ilyen nyelvtant viszonylag egyszer˝uen alakíthatunk át fa-nyelvtanná: a szabály jobb oldalán lev˝o kifejezést megtartjuk, a bal oldalán lev˝ot pedig egyszer˝uen eldobjuk: argumentList: argumentItem (’,’ argumentItem)* -> ^(ARGS argumentItem*) ; a fenti szabály egy képzeletbeli ARGS token gyökérrel rendelkez˝o fát készít, melynek tetsz˝olegesen sok argumentItem gyereke lehet. A bemenetben az elemek vessz˝ovel vannak elválasztva. Ebb˝ol a szabályból a fa nyelvtanban csupán a jobb oldalt tartjuk meg: 29
argumentList: ^(ARGS argumentItem*) ; Egy AST bejárása során két lehet˝oségünk van a fordításra: illeszthetünk kódrészleteket a szabályok közé, melyek valamilyen kimenetet generálnak (pl.: print utasítások), vagy használhatunk egy sablon-motort. Az ANTLR sablon-készít˝o szabályokkal (template construction rules) integrálható a StringTemplate nev˝u sablon-motorral, mely használatával elkülöníthetjük a logikát a megjelenítést˝ol és így átláthatóbb, s˝ot, akár újra felhasználható kódot kapunk.[5]
2.1.2. A StringTemplate sablon-motor bemutatása Egy sablon alapvet˝oen nem más, mint egy dokumentum „lyukakkal”[8]. Ezeket a lyukakat – melyeket attribútumoknak is nevezhetünk – úgy lehet adatokkal kitölteni, mintha paramétereket adnánk át a sablonnak[5]. A Model-View-Controller (MVC) paradigmának megfelel˝oen a sablon tekinthet˝o a nézetnek, a modell az attribútumokat megalkotó kód, a kontroller pedig a sablont attribútumokkal kitölt˝o kód[8]. A StringTemplate szigorúan megköveteli a modell és a nézet elkülönítését. Az elkülönítés úgy valósítható meg, ha a modell és a nézet is egységbe zárt. Ezen fogalmak formális definícióját Terence Parr [7]-ben adja meg: Definíció Egységbe zárt modell: a modell egységbe zárt, ha minden adatfügg˝o számítás és logika a modellben valósul meg. Definíció Egységbe zárt nézet: a nézet egységbe zárt, ha minden megjelenítési és elrendezési információt a nézet tartalmaz. Definíció Szigorú elkülönítés: a modell és a nézet szigorúan elkülönített, ha mindkett˝o egységbe zárt, továbbá a nézet nem képes módosítani a modellt, és a nézet nem feltételez semmit a modell adatainak típusáról. A fentieknek megfelel˝oen a megjelenítésre vonatkozó információkat a sablonban kell elhelyezni, ahol már nem lehet az attribútumokon számításokat, vagy logikai vizsgálatokat végezni, leszámítva egy attribútum létezésének ellen˝orzését. A sablon függvényekb˝ol áll, melyek attribútumokat attribútumokra képeznek le az alábbi formában: F (a1 , a2 , ..., am ) ::= t0 e0 ...ti ei ti+1 ..tnt ene ahol ai attribútum, ti kimeneti szöveg, ei pedig kifejezés. A kifejezéseket az különbözteti meg a kimeneti szövegekt˝ol, hogy < > jelek között szerepelnek[8]. 30
A kifejezéseknek négy típusa megengedett: • hivatkozás egy attribútumra:
• egy sablon meghívása: • feltételes kifejezés: teszt szöveg<endif> • sablon alkalmazás: – értsd: a vars attribútum (vagy attribútum-lista) minden értékére alkalmazd a decl() sablont. Az ANTLR és a StringTemplate Az ANTLR – a fa-épít˝o szabályokhoz hasonlóan – tartalmaz sablon-készít˝o szabályokat is, melyek segítségével az elemzés közben formázott kimenetet állíthatunk el˝o. Ezen szabályok általános formája: ruleN : ^(ROOT childItem) -> template( attrName = {<>}, ... ) ; Ezen kívül a beágyazott kódrészletekben is használhatunk pár sablon-készít˝o operátort[5]: • %foo(a={},b={}, ... ) – A foo nev˝u sablonból készít egy példányt, beállítva az a, b attribútumok értékét • %({«stringExpr»})(a={}, ...) – Az el˝oz˝ohöz hasonló, azt leszámítva, hogy a sablon nevét a stringExpr kifejezés értéke tartalmazza. • %x.y = «z» – Beállítja az x sablon y attribútumát z-re. • %{«stringExpr»} – Egy névtelen sablont készít a stringExpr szövegb˝ol. Ezen a ponton minden adott egy fordító elkészítéséhez. A lépéseket illetve komponenseket a 2.2. ábrán foglalom össze. Az ábrán a bemeneti karaktersorozatból a második komponens, a Lexer tokeneket készít, melyek a Parser bemeneteként szolgálnak. A parser ezekb˝ol a tokenekb˝ol eldönti, hogy a bemeneti karaktersorozat eleme-e a nyelvnek, vagy sem. A levezetés közben a releváns elemekb˝ol szintaxis-fát (AST) készít, ami a Treewalker bemeneteként fog szolgálni. A Treewalker a bejárás közben StringTemplate sablon-hívásokkal, vagy szabályok közé beágyazott kód futtatásával formázott kimenetet készít el˝o. Ezt a kimenetet a Translator alakítja szöveggé. A 2.2. ábrán kék színnel jelzett komponens, a Translator saját készítés˝u, a zöld szín˝ueket az ANTLR generálta (a nyelvtanok alapján), míg a sárga a StringTemplate osztálykönyvtár. 31
2.2. ábra. A fordítás folyamata ANTLR+StringTemplate-el
2.2. Funkcionális terv Ebben a részben specifikálom, hogy az elkészített Transact-SQL → PL/SQL fordítónak mi a célja, milyen funkciókkal rendelkezik, illetve ezeket hogyan valósítja meg. Ezen a ponton is szeretném kihangsúlyozni, hogy nem célom teljes érték˝u fordítót készíteni, ugyanis – ahogy ezt az 1. fejezetben részletesen megindokoltam – ilyen nem létezhet a két adatbáziskezel˝o rendszer közötti elvi különbségek miatt.
2.2.1. A feladat leírása A feladat a bemenetként kapott T-SQL tárolt eljárás lehet˝o legjobb PL/SQL fordításának elkészítése. A rendszer a bemenetet szöveges formában kapja, azaz nem képes azt az adatbázisból venni. A kimenetet is ehhez hasonlóan szöveges formában állítja el˝o, tehát nem rendelkezik kapcsolattal sem az SQL Server, sem az Oracle adatbáziskezel˝o felé. Számos olyan szituáció képzelhet˝o el, amikor egy nyelvi elem fordításának nincs értelme: az SQL Server rendelkezik számos rendszer-szint˝u tárolt eljárással, melyek speciális (adminisztratív, biztonsági, automatizálási, stb.) funkciókat látnak el3 . Ezek egy részének van Oracle oldali megfelel˝oje, más részének vagy nincs, vagy teljesen más formában áll rendelkezésre. Ezek az eljárások – jó esetben – nem képezik az üzleti logika részét, hanem az SQL Server szerves részének tekinthet˝ok, ezért a továbbiakban nem foglalkozok velük, minden tárolt eljárás-hívást egységesen fogok kezelni: feltételezem, hogy az eljárás létezik, és a felhasználó által készített 3
SQL Server 2005 alatt a rendszer-szint˝u tárolt eljárások teljes listájáért lásd: http://msdn.microsoft.com/enus/library/ms187961(SQL.90).aspx
32
eljárásról van szó. A fordítási nehézségekre másik példa lehet a dinamikus SQL utasítások esete: az SQL Server is megengedi futásid˝oben összeállított utasítások végrehajtását. Azaz, lehet˝oségünk van arra, hogy egy T-SQL utasítást szöveges formában, akár paraméterként, akár egy adatbázistáblából véve adjunk meg. Mivel az utasítás csak futásid˝oben áll rendelkezésre, ezért az ilyen konstrukciókat nem lehet átfordítani. A fentiek miatt én az alapvet˝o T-SQL szerkezetekre fogok koncentrálni: DML utasítások (SELECT, INSERT, UPDATE, DELETE), vezérl˝o szerkezetek (IF, WHILE), változó-deklarációk, tárolt eljárás-hívások, hibakezelés (RAISERROR), valamint a tárolt eljárásokból visszaadott eredményhalmazok kezelése.
2.2.2. A rendszer célja A rendszer célja, hogy SQL Server → Oracle adatbázis migráció során a tárolt eljárások fordításához hatékony segédeszköz legyen. Az eddigiek során azt indokoltam meg, hogy miért nem lehet teljes-érték˝u fordítót készíteni, most viszont azt fogom, hogy miért van értelme egy részleges megoldásnak is. Egy adatbázis migráció során általános esetben akár többezer sor T-SQL kódot is át kell fordítani. Egy fordító ezt kétféleképpen tudja segíteni: • Ötleteket adhat: bemenetként megadhatunk teszt-eseteket, melyek fordításából tanulhatunk: akár azt, hogy az adott konstrukciót nem lehet átfordítani, vagy pedig kaphatunk egy lehetséges megoldást. • Részfeladatokat automatizálhat: ha a fordítandó kódunk többszáz helyen tartalmaz olyan UPDATE utasításokat, amiknek van második FROM klauzulájuk, akkor igen unalmas, monoton feladat ezeket manuálisan MERGE utasításokká alakítani. Viszont egy fordító képes ezt elvégezni helyettünk.
2.2.3. Komponensek leírása A rendszer alapvet˝oen három komponensb˝ol áll, melyek fölött egy egyszer˝u grafikus kezel˝oi felület biztosítja a felhasználói interfészt. A komponensek az ANTLR segítségével automatikus kódgenerálással készültek a nyelvtanok (parser és treewalker) alapján. Célnyelvként a Java-t választottam4 , ennek megfelel˝oen a nyelvtanokba beágyazott kódrészletek is Java nyelven íródtak. 4
Az ANTLR jelenleg C, C#, Java, Python, ActionScript, JavaScript célnyelveket támogat. Forrás: http://www.antlr.org/wiki/display/ANTLR3/Code+Generation+Targets
33
A rendszer szerves részét képezi a StringTemplate sablon-file, melynek elkészítéséhez nagy segítségemre voltak az Oracle SQL Developer StringTemplate sablonjai. A következ˝okben a komponenseket, illetve azok generálásához szükséges nyelvtanok f˝obb tulajdonságait mutatom be. Lexer A Lexer, vagy lexikai elemz˝o feladata egy karakterfolyam tokenekre bontása. Például, a SELECT * FROM myTable bemenetb˝ol 4 tokent hoz létre, a szóközöket eldobja: SELECT, STAR, FROM, myTable. A Lexer szabályok nevét nagy kezd˝obet˝uvel kell kezdeni: SELECT
: ’SELECT’ ;
Az ANTLR (pontosabban a generált Java kód) megkülönbözteti egymástól a kis és nagybet˝uket, viszont sem a T-SQL, sem a PL/SQL nem, ezért a Lexerbe bele kell építeni, hogy ne tegyen különbséget. Ehhez használhatjuk Jim Idle által készített ANTLRNoCaseFileStream osztályt, ami felüldefiniálja az LA (lookahead – el˝ore tekintés) metódust5 . Ezután a Lexer szabályokban a szavakat csupa nagybet˝uvel kell megadni. A Lexer az egy- illetve többsoros megjegyzéseket figyelmen kívül hagyja. Ezt az ANTLR úgynevezett csatornák segítségével támogatja: a szabályban megadhatjuk, hogy az adott tokent rejtse el a Parser el˝ol: SL_COMMENT : ’--’ ~(’\n’|’\r’)* ’\r’? ’\n’ {$channel=HIDDEN;} ; Ezek a tokenek nem vesznek el, pusztán a rejtett csatornára kerülnek, amihez – ha akarunk – hozzáférhetünk. Parser A Parser feladata, hogy a bemeneti tokenekb˝ol eldöntse, egy adott mondat része-e a nyelvnek, vagy sem, illetve elkészítse a mondathoz tartozó absztrakt szintaxis-fát. A Parser szabályok nevét kis kezd˝obet˝uvel kell kezdeni. Fa építésére egyaránt használok operátorokat és fa-készít˝o szabályokat. 5
Forráskódja elérhet˝o: http://www.antlr.org/wiki/pages/viewpage.action?pageId=1782
34
A nyelvtan nem ellen˝orzi a bemenet szemantikai helyességét (pl.: egy változó értékadásnál nem ellen˝orzi, hogy a változó deklarálva lett-e, illetve megfelel˝o-e a típusa), pusztán szintaktikai ellen˝orzést végez. Megjegyzend˝o, hogy ezek nagyrészét meg lehetne valósítani szemantikus predikátumokkal, illetve beágyazott kódrészletekkel, viszont a fordítás szempontjából nincs értelme: adatbázis migráció során feltételezzük, hogy a meglév˝o kódbázis m˝uködik. A mondatszimbólum a start_rule, innen indul a levezetés. Ezután utasítások sorozatának kell következnie, amib˝ol kimenetként egy AST-t készít. Például az alábbi kódrészletb˝ol: CREATE PROC sp_testbed ( @foo INT ) AS SELECT col1 FROM myTab WHERE col2 = @foo a 2.3. ábrán látható szintaxis-fa készül.
2.3. ábra. Egy T-SQL tárolt eljáráshoz tartozó absztrakt szintaxis fa
Az ábráról könnyen leolvasható az eljárás szerkezete: egy paraméterrel rendelkez˝o tárolt eljárás létrehozása, ami összesen egy utasításból álló blokkot tartalmaz. Az utasítás egy SELECT utasítás, ami három klauzulából áll: select, from és where. Érdemes még felfigyelni arra, hogy a változó (pontosabban paraméter) neve foo, nincs az elején a változók jelölésére szolgáló ’@’ 35
karakter. Ez az információ viszont nem veszik el, a változónév gyökér-eleme a szintaxisfában a VARIABLE csomópont, ami annak megjelölésére szolgál, hogy valójában egy változóról van szó, nem pedig adatbázis objektumról (pl.: oszlopról). Treewalker A Treewalker feladata, hogy a bemeneti szintaxis-fát bejárva kimenetet állítson el˝o. A Treewalkerhez szükséges nyelvtant legkönnyebben a Parser nyelvtanból állíthatjuk el˝o: elhagyjuk a fában nem szerepl˝o tokeneket, illetve a fa-épít˝o szabályok bal oldalait. A kimenet el˝oállításához sablon-készít˝o szabályokat és beágyazott kódrészleteket használok. Mivel ez a komponens készíti el˝o a kimenetet, itt szükséges a transzformációkat elvégezni. A 2.3. ábrán látható példán keresztül részletesen bemutatom, hogy erre milyen lehet˝oségek vannak. A példa eljárás egyszer˝usége ellenére egy fontos problémára mutat rá: egy T-SQL tárolt eljárás képes eredményhalmazokat visszaadni, míg a PL/SQL eljárások nem. Tehát ezt a konstrukciót valahogy szimulálni kell. Erre egy lehetséges módszer kimeneti kurzorváltozók használata. Viszont nem elég pusztán a SELECT utasításhoz tartozó részfát kozmetikázni, deklarálni is kell a kimeneti változót az eljárás fejlécében. Viszont az a tény, hogy szerepel az eljárás-blokkban valahol egy SELECT utasítás, még nem elég, ugyanis lehet, hogy egy változónak történ˝o értékadást tartalmaz. Összefoglalva: akkor kell kimeneti kurzorváltozót deklarálni, ha tárolt eljárás blokkjában vagyunk, és nem változónak történ˝o értékadásról van szó. A SELECT utasításhoz tartozó szabály a következ˝o: select_statement scope { boolean resultSet; String cursorName; } : ^(SELECTSTMT query_expression orderbyClause?) -> {$select_statement::resultSet}? selectStatement(queryExpression={$query_expression.st}, orderList={$orderbyClause.st}, cursor={$select_statement::cursorName}) -> selectStatement(queryExpression={$query_expression.st}, orderList={$orderbyClause.st}) ; Azaz a levezetési szabályhoz tartozik két változó: az egyik azt tartalmazza, hogy van-e 36
visszaadott eredményhalmaz, vagy sem, míg a másik az eredményhalmaz visszaadásához használandó kurzor nevét tartalmazza. Az el˝obbi változótól függ (szemantikus predikátum), hogy milyen attribútumokkal lesz meghívva a sablon. Természetesen ezen a szinten még nem derül ki, hogy melyik alternatíva fog érvényesülni, ezt a levezetési fában lentebb lev˝o szabályok döntik majd el. Amikor kiderül, hogy fel kell venni egy új kimen˝o paramétert a kurzorváltozónak, akkor egyrészt lefut egy Java eljárás, ami generál egy azonosítót, másrészt az eljárás paraméter-listájához hozzáf˝uzésre kerül az új paraméter. Ezt úgy lehet megvalósítani, hogy a paraméter-lista szó szerint egy (Java) lista, amihez az add metódussal lehet új elemeket hozzáf˝uzni: create_proc scope { List parameters; } A fordító kimenetként végül az alábbi kódot állítja el˝o: CREATE OR REPLACE PROCEDURE sp_testbed ( v_foo NUMBER , cv_1 IN OUT SYS_REFCURSOR ) AS BEGIN OPEN cv_1 FOR SELECT col1 FROM myTab WHERE col2 = v_foo; END; A fenti példából jól látszódik, hogy a bejárás során gyakorlatilag bármelyik részfába beszúrhatunk vagy elhagyhatunk tetsz˝oleges elemeket. Ezért – ha definiálható, hogy milyen transzformációkat kell elvégezni – a fordítást meg lehet valósítani. A gyakorlatban a problémát az jelenti, hogy ezeket a transzformációkat nem mindig lehet meghatározni, mert egy adott nyelvi konstrukciónak nem létezik ekvivalens párja, és a pontos m˝uködést elvi eltérésekb˝ol adódóan szimulálni sem lehet. A következ˝oekben az elvégezhet˝o transzformációkat fogom specifikálni. Ezeket [16], [18], [12] alapján dolgoztam ki. 37
SQL Server Oracle FROM klauzula opcionális, ha a SELECT A FROM klauzula kötelez˝o. lista nem tartalmaz oszlopneveket Ha hiányzik, szimulálni kell a DUAL táblából való lekérdezéssel: SELECT 1 FROM DUAL A DUAL tábla egy egy oszlopból és egy sorból álló tábla. Oszlop aliasoknál megengedett szintaxis: Az oszlop aliasok szintaxisa: alias1 = column1 column1 [AS] alias1 Létezik INTO klauzula: Ennek az utasításnak nem lehet autoSELECT <select_list> INTO matikusan elkészíteni a szemantikus ek vivalensét! Az adatokat táblába beszúró részt lehet szimulálni az INSERT INTO...SELECT utasításokkal, de a tábla létrehozását nem lehet megoldani a kifejezések futásidej˝u kiértékelése nélkül! 2.1. táblázat. A SELECT utasításnál szükséges transzformációk SQL Server Az INTO kulcsszó opcionális
Oracle Az INTO kulcsszó kötelez˝o. Ha hiányzik, be kell szúrni.
2.2. táblázat. Az INSERT utasításnál szükséges transzformációk
SELECT A SELECT utasítással kapcsolatos transzformációkat a 2.1. táblázat tartalmazza. A táblázatban utolsóként említett SELECT. . . INTO problémát egy fordító nem tudja teljes érték˝uen megoldani. Ezért én azt a kompromisszumos megoldást választottam, hogy feltételezem, a felhasználó gondoskodik a cél-tábla létrehozásáról. INSERT Az INSERT utasítással kapcsolatos transzformácókat a 2.2. táblázat tartalmazza. DELETE A DELETE utasítással kapcsolatos transzformációkat a 2.3. táblázat tartalmazza. UPDATE Az UPDATE utasítással kapcsolatos transzformációkat a 2.4. táblázat tartalmazza. Figyeljük meg, hogy az UPDATE utasítás esetében szükség lehet egy másik utasítás használata: a MERGE utasítás képes ellátni ugyanazt a funkciót, mint az UPDATE. . . FROM (és még sokkal többet is). Érdekesség még, hogy annak függvényében, hogy hány forrás-táblát használunk az UPDATE utasításban, más és más transzformációt célszer˝u alkalmazni. Megjegyzend˝o, hogy az SQL Server 2008-as verziótól kezdve már támogatja a MERGE utasítást is, ezért ha az ANSI szabványt szeretnénk követni, programjainkban használjuk inkább azt az UPDATE. . . FROM helyett. 38
SQL Server Második FROM klauzula: törlési feltétel megadása más táblák adatai alapján: DELETE FROM FROM WHERE
Oracle Második FROM klauzula esetén egy lehetséges transzformáció: DELETE FROM WHERE ROWID IN (SELECT .ROWID FROM WHERE )
2.3. táblázat. A DELETE utasításnál szükséges transzformációk
SQL Server FROM klauzula: adatok/logikai feltétel egyéb táblákból: UPDATE SET <setters> FROM WHERE
Oracle FROM klauzula helyett MERGE utasítás: ha két tábla szerepel a FROM klauzulában: MERGE INTO USING ( SELECT * FROM ) ON WHEN MATCHED THEN UPDATE <setters> ha kett˝onél több tábla: MERGE INTO USING ( SELECT .ROWID row_id, <setter_values> FROM WHERE ) ON (.ROWID = .row_id) WHEN MATCHED THEN UPDATE <setters>
2.4. táblázat. Az UPDATE utasításnál szükséges transzformációk
39
RETURN
A RETURN utasítással, illetve a visszatérési értékekkel kapcsolatos problémákat
az 1.2.3. fejezetben részletesen bemutattam. A fordító implementálásakor az Oracle SQL Developer által is járt utat választottam, azaz, ha egy tárolt eljárásnak van visszatérési értéke, akkor függvénnyé alakítom, azzal a különbséggel, hogy a visszatérési érték típusának mindig NUMBER-t (INTEGER-t) választok. Ugyanis – habár szintaktikailag értelmes egy karaktersorozat visszaadása – egy tárolt eljárás csak egész számot adhat vissza. Ha más típusú adatot próbál, aminek nem lehetséges az implicit konverziója integer típusra, futás id˝oben hibát fogunk kapni. IF EXISTS... Feltételes elágazás van a T-SQL és a PL/SQL nyelvben is. Viszont abban különböznek, hogy milyen kifejezést lehet megadni feltételként. A T-SQL programokban igen gyakran használt IF EXISTS szerkezet sajnos nem elérhet˝o PL/SQL nyelven, a m˝uködését szimulálni kell. Erre a 2.5. táblázatban három lehetséges transzformációt mutatok be. A 2.5. táblázatban szerepl˝o konstrukciók szemantikailag ekvivalensek egymással, a szemléletességükben, illetve a transzformáció elvégzésének nehézségében viszont különböznek. Jól látható, hogy az els˝o megoldás érintetlenül hagyja az eredeti SELECT utasítást, pusztán „köré” épít, a második megoldás kiegészíti a WHERE klauzulát plusz egy feltétellel, míg a harmadik megoldás a lekérdezési listát is módosítja. Mindhárom megoldás közös tulajdonsága, hogy igényel egy ideiglenes változót is. Grafikus kezel˝oi felület A rendszer magját képez˝o három komponens fölé egy grafikus kezel˝oi felületet illesztettem, aminek szerepe a használat megkönnyítése. A felület – melynek képerny˝oképe a 2.4. ábrán látható – két szövegdobozból, és egy gombból áll. A gomb megnyomására a bal oldali szövegdobozban szerepl˝o szöveget a fordító megpróbálja lefordítani PL/SQL nyelvre, aminek az eredményét a jobb oldali szövegdobozban jeleníti meg. A háttérben a 2.2. ábrán bemutatott folyamat zajlik. Ha esetleg kiváncsiak vagyunk a forrás absztrakt szintaxis-fájára, ezt a fordító az alapértelmezett kimenetre kiírja.
2.3. Összefoglalás A fejezetben bemutattam, hogy az ANTLR és a StringTemplate segítségével hogyan lehet egy fordítót elkészíteni. Szándékosan nem mentem bele az implementációs részletekbe, ugyanis a cél nem ezen eszközök részletes bemutatása volt6 , hanem egy fordító megtervezése. 6
Ezzel kapcsolatban lásd: [5] és http://www.antlr.org valamint http://www.stringtemplate.org
40
SQL Server IF EXISTS(<select_statement>)
Oracle DECLARE v_temp NUMBER(1, 0) := 0; BEGIN SELECT 1 INTO v_temp FROM DUAL WHERE EXISTS ( <select_statement> ); IF v_temp = 1 THEN - ... END IF; END; második alternatíva: DECLARE found boolean := false; BEGIN for x in (<select_statement> AND ROWNUM=1) loop found := true; - ... exit; end loop; END; harmadik alternatíva DECLARE v_temp INTEGER; BEGIN SELECT COUNT(*) INTO v_temp FROM WHERE AND ROWNUM = 1; IF v_temp = 1 THEN - Do something END IF; END;
2.5. táblázat. Az IF EXISTS szerkezetnél lehetséges transzformációk
41
2.4. ábra. A fordítóhoz tartozó grafikus kezel˝oi felület
A fejezet számos elméleti és gyakorlati témakörre is rámutat, amik önmagukban is témáját képezhetik további munkáknak: az LL(*) elemz˝ok m˝uködése, környezetfügg˝o nyelvek elemzése szintaktikus és szemantikus predikátumok segítségével, illetve amir˝ol nem esett szó, de a fordításhoz szükséges nyelvtanok implementálásakor er˝osen támaszkodtam rá: az ANTLR úgynevezett backtracking lehet˝osége, ami azt teszi lehet˝ové, hogy a levezetési szabályok alkalmazásakor ha az egyik alternatívát nem sikerült alkalmazni, az ANTLR visszatekeri a bemenetet, és megpróbálja a következ˝o alternatívával. A következ˝o fejezetben az elkészített rendszert értékelem: bemutatom, hogy a funkcionális tervnek mennyire felel meg a fordító, illetve, hogy a kit˝uzött célt sikerült-e elérnem.
42
3. fejezet Értékelés Egy rendszer értékelésekor azt kell vizsgálni, hogy megfelel-e a vele szemben támasztott követelményeknek. A jelen esetben ez azt jelenti, hogy elvégzi-e, illetve helyesen végzi-e el a funkcionális tervben specifikált átalakításokat. Ennek vizsgálatára teszt-eseteket állítottam fel (lásd: B. függelék). A teszt-esetek jól lefedik egy átlagos T-SQL tárolt eljárásban használt utasításokat, szerkezeteket, ugyanis tartalmazzák a DML utasításokat (SELECT, INSERT, UPDATE, DELETE), feltételes szerkezeteket, programvezérl˝o utasításokat, változók deklarációját, értékadásokat, illetve a hibajelzéshez kapcsolódó utasításokat. A tranzakció kezel˝o utasítások tudatosan maradtak ki: az 1.2.3. fejezetben bemutatott problémák miatt ezen utasítások egy részének nem létezik szemantikailag ekvivalens megfelel˝oje. Szimulációjuk megítélésem szerint kifejezetten káros lenne: szintaktikailag helyes kódot kaphatunk ugyan, de a két rendszer közötti elvi különbségekb˝ol adódóan futás közben el˝ojöhetnek nem várt hatások. Ezért automatizált fordításukra adott bármilyen kísérlet abban a tévhitben tarthatja a felhasználót, hogy létezik általános megoldás, pedig épp ellenkez˝oleg: ilyen esetekben a programkód és az azt hívó eljárások kódjának alapos analízise szükséges. Az el˝oállított kód jól olvashatóságát és szintaktikai helyességét a sablon-alapú megközelítés biztosítja. Ugyanis a fordító kimenetként a sablonban megadott formájú és szerkezet˝u szöveget fog adni. Belátható, hogy ha a sablont a célnyelv szintaktikai szabályainak megfelel˝oen készítjük el, akkor a kimenet vagy helyes lesz, vagy hiányozni fog. Megjegyzend˝o, hogy a fordító csak szintaktikailag helyes T-SQL kódból képes PL/SQL kódot el˝oállítani, az esetleges hibák kijavítása vagy jelzése nem volt cél. Ilyen esetekben a Parser nem képes az adott utasítást elemezni, és az ANTLR hibakezelési stratégiájának megfelel˝oen megpróbál újra szinkronba kerülni. Ennek illusztrálásáért lásd a 3.1. ábrát, ahol a fordító bemenetként egy olyan tárolt eljárást kapott, ami tartalmaz szintaktikailag hibás utasítást. Jól látható, hogy az INSERT utasítás hibát tartalmaz: hiányzik a VALUES kulcsszó. A fordító a meglév˝o darabokból nem képes értelmes rész-utasítást el˝oállítani (hiányzik egy kötelez˝o
43
3.1. ábra. Szintaktikailag hibás bemenet fordítása a fordító segítségével
klauzula), ezért a kimenetb˝ol ez teljes egészében kimarad. A hibát az ANTLR jelzi is, amit a fordító az alapértelmezett kimenetre ír ki: line 6:21 no viable alternative at input ’@’ (CREATEPROC sp_wrong (PARAMS (PARAM (VARIABLE id) int (DEFAULT (CONSTANT null)))) (SQLBLOCK (if (EXPR (exists (SELECTSTMT (SELECT (SELECTLIST (CONSTANT 1)) (FROM (DBOBJECT myTab)) (WHERE (EQUAL (DBOBJECT id) (VARIABLE id))))))) return))) (insert myTab (DERIVED (SELECTSTMT (( ,6:21], resync=@id, ’hibas utasitas’>)))) X:\ANTLR\TSQLTree.g: node from line 0:0 no viable alternative at input ’@id, ’hibas utasitas’’ Az els˝o üzenetet a Parser adta, jelezve, hogy nem tud mit kezdeni a @ szimbólummal azon a helyen, ahol érkezett. A második sorban az AST látható, amib˝ol leolvasható, hogy egy INSERT INTO .. SELECT utasításnak próbálta értelmezni (a VALUES kulcsszó hiánya miatt), viszont a zárójel után egy SELECT kulcsszónak kellett volna következnie. A harmadik üzenetet a Treewalker adta, akinek hasonló gondja volt, mint a Parsernek: hibás, hiányos a részfa. Az ANTLR hibakezelési és újraszinkronizálási stratégiájának részletes bemutatásához lásd [5] 10. fejezetét.
44
3.1. B˝ovíthet˝oség Az ANTLR és a StringTemplate által biztosított fordítási architektúra (melynek általános vázlatát a 2.2. ábra mutatja) egyfel˝ol igen rugalmas, annak köszönhet˝oen, hogy a komponensek szerepköre jól definiált, egymástól elhatárolt. A végs˝o kód megjelenítéséért, formázásáért egyedül a StringTemplate sablon-leírás felel˝os. Ezen sablon-motor használata megköveteli a szigorú Model-View-Controller szeparációt, aminek következtében logikát, utasításokat nem tartalmaz. Ahogy a dolgozatban végig hangsúlyoztam, általános esetben teljes érték˝u automatizált TSQL → PL/SQL fordító nem készíthet˝o. Viszont elképzelhet˝oek olyan speciális esetek, amikre testreszabva a fordítót, közel hibamentes m˝uködés érhet˝o el. Ehhez a Treewalkerben megvalósított transzformációk módosítása, finomítása szükséges. Mivel a Treewalker a nyelvtan jórészt deklaratív leírásából kódgenerálással készült, ezért a testreszabás nagyságrendekkel egyszer˝ubb feladat, mintha a forráskódhoz kéne hozzányúlni. Ha pedig a forrás-nyelv változik (pl.: más T-SQL verzió esetén), akkor a Parser nyelvtanát kell módosítani. Amennyiben megtartjuk a kimenet, tehát az AST szerkezetét (pontosabban fogalmazva az el˝oállított kimenet ugyanannak a nyelvnek a része, mint eddig), a többi komponens módosítása nem szükséges.
3.2. Limitációk Az ANTLR+StringTemplate használata rendkívül kényelmes befektetésnek bizonyul, ha a forrás és a célnyelv hasonló. Azaz az utasításokat, blokkokat hasonló szintaxisfával tudjuk leírni, a köztük lev˝o transzformációkat meg tudjuk határozni. Sajnos ezt a módszert nem lehet kiterjeszteni általános célú magas szint˝u nyelvek közötti fordításra [11]. A 2.2.2. fejezetben a rendszer célját úgy határoztam meg, hogy képes legyen fordítási ötleteket adni, illetve automatizáljon bizonyos részfeladatokat. Ez a B. függelékb˝ol jól látható, hogy megvalósult, bizonyos esetekben jobb eredményt elérve, mint az Oracle Migration Workbench (lásd B.14. ábra). Ennél többet az 1.2.3. fejezetben bemutatott korlátok miatt nem lehet elvárni. Meg kell elégednünk annyival, hogy ha rendelkezünk az adatbázis és a hozzá kapcsolódó alkalmazások átfogó, rendszer-szint˝u ismeretével, és az aktuális alkalmazási környezet lehet˝ové teszi számunkra, bizonyos problémák kezelésére speciális megoldásokat építsünk a fordítóba. Például a túl hosszú objektumneveket egy adott algoritmus szerint rövidíthetné, amit az alkalmazásba is be lehet építeni.
45
4. fejezet Összefoglalás Adatbázisok migrációja komplex, többszint˝u feladat. Ebben a dolgozatban bemutattam azokat a f˝obb problémákat, amikkel egy migrációt végz˝o szakember szembesülhet. Ezek f˝oleg az adatok migrációjával, illetve a nyelvi különbségekb˝ol adódó problémák. A tárgyalás fókuszában az utóbbi állt: Microsoft SQL Server-r˝ol Oracle adatbáziskezel˝ore való áttérés során a tárolt programok, tárolt eljárások fordításának problémáit, illetve az ezekre adott megoldások elvi korlátait mutattam be. Bemutattam, hogy – habár jelenleg is léteznek a migrációs folyamatot támogató eszközök – ezek a két rendszer közötti elvi különbségekb˝ol adódóan nem lehetnek képesek általános esetben teljes érték˝u megoldást nyújtani. Az Oracle által készített és használt módszertan, az Oracle Relational Migration Maps egyfajta keretet nyújt a munka szervezéséhez, elvégzéséhez. Fontos, hogy a módszertan szerint a migrációt szakemberek végzik, a migrációs eszközök csupán segítik o˝ ket, munkájukat nem helyettesítik. A második fejezetben a formális nyelvi elemzés alapjainak bemutatása után egy T/SQL → PL/SQL fordító funkcionális tervét ismertettem, amit az ANTLR és a StringTemplate rendszerek felhasználásával valósítottam meg. A fordítóval a célom az volt, hogy a migrációt végz˝ok számára egyrészr˝ol fordítási ötleteket adjak, másrészt segítségével automatizálni lehessen részfeladatokat. Bízom benne, hogy hasznos segédeszközt hoztam létre, amit – kisebb átalakítások, testreszabások után – éles projektekben is fel lehet használni. Ezúton szeretnék köszönetet mondani az Fx Software Zrt. munkatársainak, kollégáimnak egyrészr˝ol a szakmai támogatásért, ötletekért, másrészr˝ol, hogy engedték, hogy adatbázis migrációs kérdésekkel foglalkozzak. Remélem, hogy a dolgozat elkészítése során szerzett tudást kamatoztathatom a jöv˝oben. Köszönet illeti bels˝o és küls˝o konzulenseimet, Kardkovács Zsoltot, Marton Józsefet és Herczegh Gézát, amiért konstruktív ötleteikkel, kritikáikkal segítették a munkámat, illetve rámutattak számos hibára, hiányosságra. Szeretném még megköszönni Sárecz Lajosnak az Oracle Hungary-tól, hogy már az önálló
46
labor tárgytól kezdve nyomon követte munkámat, segített megválaszolni a felmerült kérdéseket, illetve lehet˝oséget biztosított, hogy egy el˝oadást is tartsak az Oracle-nél migráció témában. Végül, de nem utolsó sorban Terence Parr munkája, az ANTLR és a StringTemplate nélkül valószín˝uleg nagyságrendekkel nehezebb dolgom lett volna.
47
A. függelék Oracle SQL Developer Migration Workbench Migrációs beállítások
Az SQL Developer Tools \ Preferences menüpontja alatt lehet˝oség
van pár, migrációval kapcsolatos beállítás elvégzésére. Ezek közül kiemelend˝o: • Az üres sztringek kezelése: Oracle alatt az üres sztring (”) a NULL értékkel ekvivalens. Ezért itt beállíthatjuk, hogy adatok migrálásakor a forrásrendszeri üres sztringeket mivé fordítsa át az OMWB: space-é, vagy NULL értékké. • Az azonosító nevekkel kapcsolatban be lehet állítani, hogy a migrált objektumok neve elé milyen prefixet szúrjon a rendszer. Például, ha itt prefixnek az ’xyz_’-t állítjuk, akkor a forrásrendszerbeli EMPLOYEES táblából xyz_EMPLOYEES lesz. • A forrásrendszerben be van-e kapcsolva a QUOTED_IDENTIFIER: ezzel a kapcsolóval lehet megadni, hogy a dupla idéz˝ojelek között szerepl˝o sztringeket azonosító névként értelmezze a rendszer. • A változónevek elé milyen prefixet szúrjon be a rendszer: külön meg lehet adni, hogy a változónevek elé, illetve a bemen˝o paraméterek neve elé milyen prefixet szúrjon be. Alapértelmezetten a v_ és az iv_ van beállítva. Amennyiben ennél részletesebb beállításokat szeretnénk tenni, akkor a Migration Repository-ban szerepl˝o MIGRATION, MIGRATION_REPORT, MIGRATION_TRANSFORMER PL/SQL csomagok kódját kézzel kell módosítani az igényeinknek megfelel˝oen. Migráció
A migráció elvégzésére alapvet˝oen két mód áll rendelkezésre:
• Quick Migrate: egy varázsló által vezérelt mód, ami minimális beleszólást tesz lehet˝ové • Manual Migrate: az ajánlott, kézi mód 48
A kézi migráció az alábbi lépésekb˝ol áll: • Associate Migration Repository: egy meglév˝o Oracle Database kapcsolaton ki kell jelölni a Migration Repository-t. Ez a gyakorlatban a PL/SQL csomagok, illetve táblák létrehozását jelenti. Ajánlott egy erre dedikált sémát használni. • Capture: a forrás adatbázis-kapcsolaton ki kell választani a migrálandó sémát, majd a Capture Model parancs hatására az SQL Developer beolvassa a forrásrendszerb˝ol a migrációhoz szükséges metaadatokat. • Convert to Oracle Model: ez a lépés jelenti a migrációt magát. El˝oször beállíthatjuk az adattípusok közti konverziót (err˝ol lásd b˝ovebben az 1.2.3 fejezetet), majd az SQL Developer elvégzi a sémaobjektumok átfordítását. • Generate DDL: az el˝oz˝o lépés hatására csak egy úgynevezett Converted Model jön létre a Migration Repository-ban, ezért a sémát létrehozó DDL utasításokat tartalmazó scriptet külön lépésben létre kell hoznunk. A fenti lépéseket elvégezve, illetve a DDL scriptet futtatva kapunk egy többé-kevésbé helyes, Oracle sémát. Ha szerencsések vagyunk, akkor az összes objektum sikeresen létrejött, és a Migration \ Migrate Data menüponttal az adatok migrációját is megkezdhetjük. Az sqlserver_utilities csomag Az sqlserver_utilities PL/SQL csomag pár SQL Server specifikus függvényt próbál emulálni Oracle környezetben. Mivel hivatalos dokumentációja nincs, ezért az itt leírtakat kizárólag tapasztalati úton következtettem ki. Az emulált SQL Server függvények: convert_ patindex year hex* month_ oct* day_ radians dateadd degrees isdate to_base* datepart rand datediff isnumeric parsename quotename stuff fetch_status*
round_ difference reverse_ pi datename str_to_date* stats_date ident_incr ident_seed str
A.1. táblázat. Az sqlserver_utilities csomagban található függvények Az A.1. táblázatban a *-al jelölt függvényeknek nincs SQL Server oldali megfelel˝ojük. A to_base függvény az els˝o paraméterében kapott decimális számot váltja át a második paraméterében kapott alapú számmá, és VARCHAR2 típusúként adja vissza. Maximum 16-os 49
számrendszerig képes kezelni az átváltásokat, de erre vonatkozó ellen˝orzés nincs megvalósítva. A hex és oct függvények a to_base függvényt hívják 16 illetve 8 paraméterrel. A fetch_status függvény némileg kilóg a sorból: ezzel a függvénnyel a készít˝oi a @@FETCH_STATUS globális változó m˝uködését próbálták emulálni. Például az OMWB a lenti Transact-SQL kódot: FETCH NEXT FROM c1 INTO @myVar WHILE (@@FETCH_STATUS <> -1) BEGIN IF (@@FETCH_STATUS <> -2) -- do something FETCH NEXT FROM c1 INTO @myVar END ilyen módon fordítja PL/SQL-re: FETCH c1 INTO v_myVar; WHILE ( sqlserver_utilities.fetch_status(c1%FOUND) <> -1 ) LOOP BEGIN IF (sqlserver_utilities.fetch_status(c1%FOUND) <> -2 ) THEN -- do something END IF; FETCH c1 INTO v_myVar; END; END LOOP; Ebb˝ol már rögtön látszódik a m˝uködési elve: egy PL/SQL kurzoron a %FOUND attribútum igazat ad vissza, ha a fetch m˝uvelet sikeresen végrehajtódott, és hamisat, ha nem. Ezt a logikai értéket alakítja a fetch_status függvény rendre 0-ra és -1-re. Viszont a @@FETCH_STATUS változónak lehet egy harmadik értéke is: -2, ha az adott sor már nincs meg (például a kurzor megnyitása és a fetch m˝uvelet között valaki kitörölte). A másik szembeötl˝o különbség az, hogy a T-SQL-es változó globális, míg a fetch_status függvény értéke a megadott kurzorra vonatkozik. Ehhez hasonló hibákat, hiányosságokat a többi függvény esetében is találhatunk. Ökölszabályként kijelenthet˝o, hogy ha az OMWB egy kódrészletet úgy fordít át, hogy valamelyik cso50
magbeli függvényt használja, érdemes megnézni, nem lehetne-e közvetlenül PL/SQL-es változatot használni (pl.: kurzor-attribútumok, convert helyett cast, stb.), vagy ha mégis a csomagot szeretnénk használni, akkor alaposan nézzük végig az egyes függvények implementációját, nehogy m˝uködés közben érjen minket meglepetés.
51
B. függelék A funkcionális tervben specifikált transzformációk muködés ˝ közben
B.1. ábra. Kurzorváltozók használata kimeneti eredményhalmaz el˝oállításához
A T-SQL tárolt eljárások által használt eredményhalmazokat a PL/SQL tárolt eljárásokban kimeneti kurzorváltozókkal lehet szimulálni. A B.1. ábrán a 2.2.3. fejezetben bemutatott transzformációt illusztrálom. Ha egy SELECT utasításnak nincs FROM klauzulája, akkor ezt „pótolni” kell: a 2.1. táblázatban definiált transzformációt a B.2. ábra mutatja. Az oszlop alias-okra a 2.1. táblázatban definiált transzformációt a B.3. ábra mutatja. A SELECT .. INTO utasítás átalakítását egy INSERT és egy SELECT utasításra a B.4. ábra mutatja. A transzformációt a 2.1. táblázatban definiáltam. A B.5. és a B.6. ábrán az UPDATE utasítás átalakítását mutatom be akkor, ha két, illetve ha több forrás-tábla van megadva a FROM klauzulában. Ezt a transzformációt a 2.4. táblázatban definiáltam. 52
B.2. ábra. SELECT utasítás FROM klauzula nélkül
B.3. ábra. SELECT utasítás kétféle alias szintaxisa
B.4. ábra. SELECT utasítás INTO klauzulájának fordítása
53
B.5. ábra. UPDATE utasítás átalakítása MERGE utasításra 1.
B.6. ábra. UPDATE utasítás átalakítása MERGE utasításra 2.
B.7. ábra. IF EXISTS szerkezet szimulálása
54
PL/SQL-ben nincs az IF EXISTS feltételes szerkezetnek közvetlenül megfelel˝o elem. Ezt a 2.5. táblázatban definiált módon szimulálni kell. Erre mutat példát a B.7. ábra.
B.8. ábra. Tárolt eljárás visszatérési értékkel
Egy PL/SQL tárolt eljárás nem rendelkezik visszatérési értékekkel. Ahogy a 2.2.3. fejezetben bemutattam, ezeket a tárolt eljárásokat a fordító függvényekké alakítja. A B.8. ábrán is látható a figyelmeztetés, hogy a két változat szemantikailag nem ekvivales egymással.
B.9. ábra. WHILE ciklus
A WHILE ciklus nem igényel átalakításokat pár apró szintaktikai különbséget leszámítva. A B.9. ábra azt illusztrálja, hogy a fordító az absztrakt szintaxis fából a PL/SQL szintaxisnak megfelel˝oen PL/SQL szintaktikai szabályainak megfelel˝o kimenetet állít el˝o, azaz magán a 55
szintaxis fán nem végez átalakításokat.
B.10. ábra. Hibajelzés: RAISERROR fordítása
B.11. ábra. INSERT utasítás INTO kulcsszó nélkül
A 2.2. táblázatban bemutatott átalakítást illusztrálja a B.11. ábra.
B.12. ábra. DELETE utasítás második FROM klauzulával
A 2.3. táblázatban bemutatott átalakítást a B.12 és a B.13 ábra illusztrálja. Figyeljük meg, hogy a B.14. ábrán láthatóan az Oracle Migration Workbench bizonyos esetekben hibásan fordítja le azokat a DELETE utasításokat, amik tartalmaznak második FROM 56
B.13. ábra. DELETE utasítás második FROM klauzulával – összetettebb példa
B.14. ábra. DELETE utasítás hibás fordítása az Oracle Migration Workbench-el
klauzulát is. A hiba abból adódik, hogy az els˝o és a második, join-nal összekapcsolt táblát egy táblaként kezeli, és ennek próbálja a ROWID oszlopát venni. Az általam készített fordító ezeket az eseteket is helyesen kezeli (lásd: B.13).
57
Irodalomjegyzék [1] Bach, Iván (2001): Formális nyelvek (Typotex) [2] Bansleben, Erik Peter (2004): Database Migration: A Literature Review and Case Study (diplomamunka, konzulens: Stephanie W. Haas) [3] Kisil, Vladimir; Sevastyanov, Denis; Fomenko, Valery; Rusakov, Yuri (2007): Guide to Migrating from Oracle to SQL Server 2005 (SQL Server Technical Article) [4] Lin, Chang-Yang (2008): Migrating to Relational Systems: Problems, Methods & Strategies (CMR Journal) [5] Parr, Terence (2007): The Definitive ANTLR Reference: Building Domain-Specific Languages (Pragmatic Bookshelf) [6] Parr, Terence; Quong, R. W. (1995): ANTLR: A Predicated-LL(k) Parser Generator (John Wiley & Sons) [7] Parr, Terence (2004): Enforcing Strict ModelView Separation in Template Engines (WWW ’04: Proceedings of the 13th international conference on World Wide Web) [8] Parr, Terence (2006): A Functional Language For Generating Structured Text http://www.cs.usfca.edu/ parrt/papers/ST.pdf (hozzáférve: 2009-05-08) [9] Rahm, Erhard; Hai Do, Hong (2000): Data cleaning: Problems and current approaches (IEEE Data Engineering Bulletin) [10] Terekhov, A.A.; Verhoef, C. (2000): The Realities of Language Conversions (IEEE Software) [11] Tripp, Andrew H. (2006): Why I Don’t Use StringTemplate For Language Translation: http://www.antlr.org/article/1136917339929/stringTemplate.html (hozzáférve: 2009-04-29)
58
[12] Sz.n. (2008): SQL Developer Supplementary Information for Microsoft SQL Server and Sybase Adaptive Server Migrations, Release 1.5, Part no.: E12156-01 [13] Sz.n. (2007): SQLWays Documentation – Database Migration Software Version 3.9 http://www.ispirer.com/doc/sqlways39/SQLWays.pdf (hozzáférve: 2009-04-30) [14] Sz.n.: Oracle Relational Migration Maps: http://www.oracle.com/technology/tech/migration/maps/index.html (hozzáférve: 2009-03-29) [15] Sz.n.: Migrating Applications from Microsoft SQL Server to Oracle9i Database – An Oracle White Paper (November 2003) [16] Sz.n.: MSDN Library – Microsoft Developer Network http://msdn.microsoft.com/en-us/library/bb545450.aspx [17] Sz.n.: Oracle Database Concepts, Release 1 (11.1) Part no.: B28318-05 [18] Sz.n.: Oracle Database SQL Language Reference, 11g Release 1 (11.1) Part no.: B2828605
59