A PL/SQL programozási nyelv

PL_SQL Oracle 11g kiegészítései

Bevezetés

Az Oracle 11g 2007 nyarán látott napvilágot és sok újdonságot hozott az Oracle felhasználók és fejlesztők életébe. Ez a menüpont a pl/sql-ben történt változtatások, új szolgáltatások leírását hivatott bemutatni. Minden menüpont alatt egy-egy módosítás bemutatása látható, ahol lehetséges példákkal szemléltetve a jobb és gyorsabb megértés végett. Akinek nem elég a leírás, annak további olvasmány található az Oracle honlapján

Oracle homepage

Illetve ha ki akarná próbálni, akkor érdemes letölteni az Oracle XE verzióját, ami ingyenesen letölthető és használható.

Oracle XE download site

A 10g release 2 újítása során a perl stílusú kifejezések is szupportálttá váltak. Maga a 11g egy új, ötödik függvényt ad, ez pedig:
REGEXP_COUNT: A REGEXP_INSTR egy fejlesztett változata. Visszatérési értéke nem a találat kezdőpozíciója a karakterláncon belül, hanem az előfordulások száma. Minden másban megegyeznek.

REGEXP_COUNT(karakterlánc, minta, kezdő pozíció, találati paraméterek)

regexp_count leiras

Illetve két meg lévő függvény változott, kiegészültek 1-1 paraméterrel. Az egyik ilyen a REGEXP_SUBSTR(), amiben zárójelekkel elválasztva al-reguláris kifejezéseket adhatunk meg és a plusz paraméter segítségével kiválaszthatjuk, melyik eredményére vagyunk kíváncsiak.

SQL> SELECT REGEXP_SUBSTR( 2 string, 3 '(\.)([a-z-]+)(\.)', --<-- expression with subexpressions 4 1, --<-- starting position 5 1, --<-- nth occurrence 6 'i', --<-- match parameter (ignore case) 7 2 --<-- 11g: subexpression to return 8 ) AS url_middle_11g 9 FROM v;

A másik a REGEXP_INSTR. Ugyanaz a paraméter lett hozzáadva, ugyanúgy a fent említett változtatásokkal.

Simple_integer adattípus

Az oracle 9 óta van az úgy nevezett real native compiler, ami gyorsabbnak bizonyult az interpreteres megvalósításnál. A Simple integer nem egy valódi adattípus, csak a pls_integer egy alosztálya, ami felhasználja ezt a compilert illetve sokkal inkább a hardver aritmetikára támaszkodik, semmint a szoftveresre, ezzel elérve a nagyobb performanciát. Leginkább a 32 bites integerhez hasonló, - 2,147,483,648 és 2,147,483,647 közötti értékeket kezel. Nem támogatja a null értéket, viszont nem dob hibát túlcsordulás esetén, hanem átfordul.

Ezekből fakadóan a deklaráláskor már adnunk kell neki értéket:

num1 simple_integer:= 1;

Ez így helyes, viszont az alábbi kifejezés fordítás idejű hibát fog dobni:

num1 simple_integer; PLS-00218: a variable declared NOT NULL must have an initialization assignment

Fontos, hogy a not null tulajdonságot a program futásának egész ideje alatt meg kell őriznünk. Tehát, egy olyan változót, amely bármikor kaphat null értéket, nem deklarálhatunk simple_integer-nek. A másik tulajdonság, a túlcsordulás kezelése:

declare v1 pls_integer := 2147483647; begin v1 := v1 + 1; dbms_output.put_line('v1='||v1); end;

Ez a kód numeric overflow hibát dob, viszont ha a v1-et simple integerként deklaráljuk:

declare v1 simple_integer := 2147483647; begin v1 := v1 + 1; dbms_output.put_line('v1='||v1); end;

Akkor az alábbi kimenetet kapjuk: v1=-2147483648

Intra-unit inline

Az Intra-unit inlining a szubrutinok hívásának helyére a szubrutin kódjának behelyettesítését foglalja magában. A módosított kód bizonyítottan gyorsabban fut le. A 11g-nek megvan az a tulajdonsága, hogy felismeri, melyik hívás helyére mely kódrészletet kell behelyettesítenie, ezzel érve el a jobb teljesítményt. A jobb szemléltetésért egy példa:

create or replace procedure upd_int is /* original version */ l_rate_type balances.rate_type%type; l_bal balances.balance%type; l_accno balances.accno%type; l_int_rate number; procedure calc_int ( p_bal in out balances.balance%type, p_rate in number ) is begin if (p_rate >= 0) then p_bal := p_bal * (1+(p_rate/12/100)); end if; end; begin for ctr in 1..10000 loop l_accno := ctr; select balance, rate_type into l_bal, l_rate_type from balances where accno = l_accno; select decode(l_rate_type, 'C', 1, 'S', 3, 'M', 5, 0) into l_int_rate from dual; for mth in 1..12 loop calc_int (l_bal, l_int_rate); update balances set balance = l_bal where accno = l_accno; end loop; end loop; end;

Itt a hozam kiszámolása külön procedúrában történik, ami szebb kódot, talán átláthatóbbat is eredményez, viszont lassabb a fő ciklusban a call_int függvényt hívogatni, ahelyett, hogy ott lenne a függvény logikája. Az alábbi gyorsabb lefutású:

create or replace procedure upd_int is /* original version */ l_rate_type balances.rate_type%type; l_bal balances.balance%type; l_accno balances.accno%type; l_int_rate number; procedure calc_int ( p_bal in out balances.balance%type, p_rate in number ) is begin if (p_rate >= 0) then p_bal := p_bal * (1+(p_rate/12/100)); end if; end; begin for ctr in 1..10000 loop l_accno := ctr; select balance, rate_type into l_bal, l_rate_type from balances where accno = l_accno; select decode(l_rate_type, 'C', 1, 'S', 3, 'M', 5, 0) into l_int_rate from dual; for mth in 1..12 loop if (l_int_rate >= 0) then l_bal := l_bal * (1+(l_int_rate/12/100)); end if; update balances set balance = l_bal where accno = l_accno; end loop; end loop; end;

Ez ugyan gyorsabb, de rondább is. Ezért került ez az újítás a 11g-be, ahol is beállíthatjuk a metódusaink optimalizálási szintjét. Erre két lehetőségünk van:

1. alter session set plsql_optimize_level = 3; 2. alter procedure upd_int compile plsql_optimize_level = 3 reuse settings;

Az első esetben minden, a sessionben létrehozott függvényre teljesülni fog az inlining. A második esetben csak az adott metódusra lesz igaz. Itt még fontos megemlíteni egy parancsot, ami a

pragma inline(met_nev, ’YES’)

Ez is beállítja az inline-t, viszont ezt negálni is tudjuk, ha ’NO’ kulcsszót használjuk, akkor hiába adtunk meg előzőleg 3-mas optimalizálási szintet.

Sequence a PL/SQL-ben

A korábbi változatokban szekvencia lekéréséhez is sql szintakszist kellett használnunk:

DECLARE n NUMBER; BEGIN SELECT Seq.Nextval INTO n FROM Dual; END;

Ez rontott a performancián és a skálázhatóságon. Ezt kiküszöbölendő vezették be pl/sqlben is a Seq.Nextval-t.

Így most már írható így:

DECLARE n NUMBER := Seq.Nextval; BEGIN ...

Ugyanez igaz a Seq.Currval-ra is!

PL/Scope

A PL/Scope segít analóg módon feltérképezni a kódot, akárcsak a cscope a c forráskódokat. Rá lehet keresni illetve megjeleníteni a típusdefiníciókra, deklarációkra vagy referenciákra a pl/sql kódban

Et úgy éri el az Oracle, hogy meta adatokat gyűjt a forráskódról és azt az adatbázisban katalogizálja. Ezt elég olcsón teszi, nem képezi nagy részét a nyelvnek, viszont hasznos lehet reportok készítéséhez. Legelőször ez a funkció az Oracle SQL Developerében volt elérhető.

PL/SQL Continue

Nagyon sok programozási nyelv ad lehetőséget, hogy átadjuk a kódon belül a vezérlést más blokknak, ezzel megtörve a szekvenciát. Az eddigi PL/SQL verziókban az egyetlen kilépési lehetőség a ciklusokból az EXIT feltétel volt. Most már a Continue segítségével a cikluson belül át transzportálhatjuk egy új iterációba.

Hogy ennek mennyi előnye van vagy épp mennyi hátránya. Ennek mérlegelését az olvasóra bíznám.

Nevesített és kevert kifejezések SQL-be ágyazása

Legyen adott egy séma szintű f függvény:

FUNCTION f( p1 IN INTEGER := 1, p2 IN INTEGER := 2, ... pn IN INTEGER := 99) RETURN INTEGER

A 11g segítségével ez a függvény már meghívható akár SQL utasításokból is. Például:

SELECT f(pn=>3, p2=>2, p1=>1) FROM dual

A régebbi verziók ezt nem támogatták és hibát dobtak, ha ezzel próbálkoztunk. Ez akkor a legelőnyösebb, ha a pl/sql függvény legtöbb paramétere rendelkezik default értékkel és csak egyet-kettőt kell megadnunk.