A PL/SQL programozási nyelv

Típusok, típuskonstrukciók

Típusszerkezet

A PL/SQL egy erőssen típusos nyelv, vagyis minden konstansnak és változónak fordítási időben ismernünk kell a típusát. A változókat használat előtt definiálni kell. (A NULL, mint érték, némiképp kivétel ez alól a szabály alól - persze érthető okokból. Vigyázzunk azonban a NULL-lal! Viselkedése meglehetősen kiszámíthatatlan, mivel a beépített SQL eljárások és függvények nem egységesen "viszonyulnak" hozzá.)

Az adattípusok lehetnek:

Elemi típusok

A nyelv - tekintve, hogy az SQL nyelv kiterjesztése, és így szükségszerűen támogatja a natív SQL típusok használatát - meglehetősen nagy számú beépített adattípussal rendelkezik.
A PL/SQL adattípusainak csoportosítása:

Az alábbi ábra mutatja a lehetséges típusok csoportjait:

Adattipusok

Skalár típus(ok)

A skalár típusok funkciója és használata talán nem igényel különösebb magyarázatot. Vegyük észre, hogy a PL/SQL valóban kiterjeszti az SQL nyelvet, hiszen míg tartalmazza ugyan a beépített standard SQL típusokat, addig megtalálható benne például a logikai (BOOLEAN) típus is, amely nem része a szabványos SQL nyelvnek.
A BINARY_INTEGER megfelel az SQL-beli NUMBER(38)-nak, csak annyi különbséggel, hogy ez bináris. A POSITIVE és a NATURAL a BINARY_INTEGER altípusai, azaz a POSITIVE tartománya 1-től, a NATURAL típusé 0-tól kezdődik, és mindkettőé addig tart, amíg a BINARY_INTEGER tartománya.
A LONG, a RAW és a LONGRAW a VARCHAR2 altípusai. Ezek bináris adatokat tartalmaznak, melyeket "nem akarunk megjeleníteni".

LOB típus(ok)

A LOB (Large OBject) típusok strukturálatlan adatok (pl. szöveg, kép, hang video) nagy méretű (akár 4 Gigabyte-os méretű) blokkjainak kezelésére alkalmasak. Ezek a típusok támogatják az adatok gyors, hatékony, véletlenszerű elérést. A LOB típusok ún. LOB-lokátorokat tartalmaznak, amelyek valójában pointerek. Ezek a LOB-értékek vagy egy külső állományban vagy az adatbázis tábláiban tárolódnak.

Mutató és referencia típus(ok)

A referencia típusok gyakorlatilag a pointer-ek PL/SQL-beli megfelelői. Amint az az ábráról is leolvasható, kétfajta referencia típust támogat a PL/SQL.

A REF CURSOR típus kifejezetten a CURSOR típusú változók esetén használják. Szükségességét többek között az indokolja, hogy a CURSOR típus - speciális jellegéből adódóan - nem lehet például eljárások, illetve függvények paramétere, amely egy igen nagy korlátozás a nyelv hatékonyságát tekintve. A REF CURSOR típus feloldja ezt a korlátot, ugyanis REF CURSOR típusú változót nyugodtan használhatunk eljárás paramétereként.

A másik referencia típus a REF . Ez - akárcsak a REF CURSOR - egy pointer típus, és alapvetően arra szolgál, hogy az eljárások, stb. megoszthassanak egymással bizonyos adatokat (ebben szintén hasonlít a REF CURSOR-ra). A különbség, hogy ebben az esetben a mutató egy objektumra mutat, amelynek adatmezői, illetve metódusai is lehetnek. Ezeket el kell tudnunk érni a referencián keresztül, azonban a PL/SQL ezt nem oldja fel automatikusan, hanem kénytelenek vagyunk a REF operátor párját, a DEREF (dereference) operátort használni.

Példa:

DECLARE p_ref REF Person; phone_no VARCHAR2(15); BEGIN ... phone_no := p_ref.phone_number;
A példa használja a Person típust. Egyelőre ezzel ne foglalkozzunk, elég annyit tudnunk, hogy ez egy tetszőleges objektum típus, amelynek van egy phone_number nevű attribútuma.

A példa utolsó utasítása illegális, és fordítási hibát okoz. A pont, mint operátor nem oldja fel a pointer referenciákat. Ezt kénytelenek vagyunk manuálisan megtenni, például a következő módon:

DECLARE p Person; p_ref REF Person; phone_no VARCHAR2(15); BEGIN ... SELECT DEREF(p_ref) INTO p FROM dual; phone_no := p.phone_number;
A többszörös referenciákra a módszer értelemszerűen a DEREF operátor többszöri alkalmazásával kibővíthető.

Típuskonstrukciók

Tömb típus(ok)

Változó méretű tömbök (VARRAY - Variable size array)

Ez a típus áll a legközelebb a hagyományos értelemben vett tömbtípushoz. A deklarációkor meg kell adni egy maximális méretet, amelyet a program futása során a tömb nem léphet túl. Az elemeket 1-től n-ig indexeli. A tömb elemek elérésére a () operátort használhatjuk.

TYPE IS {VARRAY | VARYING ARRAY} () OF [NOT NULL];
A max_méret csak Pozitív egész szám lehet.

Beágyazott táblák (nested table)

A beágyazott tábla egy olyan vektor, amelynek nincs felső korlátja. A mérete dinamikusan nő, ahogyan egyre több és több elemet szúrunk be a táblába. A tábla elemei egész számokkal vannak indexelve. De nem biztos, hogy egy adott index-intervallumban minden indexhez tartozik érték a táblában. Lehetnek benne lyukak is. Szerencsére a tervezők számos előre definiált függvényt készítettek, amelyek megkönnyítik a beágyazott táblák kezelését. Létrehozásának szintaxisa a következő:

TYPE típus_név IS TABLE OF elem_típus [NOT NULL];

Asszociatív tömbök (index-by table)

Az asszociatív tömböt úgy kell elképzelni, mint egy halmazt, amely (kulcs, érték) párokat tartalmaz. A kulcsnak egyedinek kell lennie. A tömb mérete nem korlátos. Gyakorlatilag csak a memória véges mérete szab határt a tömb méretének. Mivel a kulcsok egyértelműen meghatározzák a hozzájuk tartozó értéket, az elemek elérése nagyon gyorsan történik. A kulcs string vagy szám típus lehet. A következőképpen hozhatunk létre egy asszociatív tömböt:

TYPE IS TABLE OF [NOT NULL] INDEX BY [PLS_INTEGER | BINARY_INTEGER | VARCHAR2()]; INDEX BY ;

A kulcs_típus BINARY_INTEGER, PLS_INTEGER vagy VARCHAR2 lehet, illetve ezek altípusai.

Példa:

TYPE név IS TABLE OF elemtípus [NOT NULL] INDEX BY binary_integer;

Ebben az esetben BINARY_INTEGER lesz az indextípus, azaz az indexek a BINARY_INTEGER tartományból kerülnek ki.
PL/SQL tábla típusú változó használata:

Tabla(-205) := érték; Tabla(2000) := érték;

Ebben az esetben két eleme lesz csak a táblának, azaz a tábla egy adott indexű elemének értéket adva hozhatjuk létre konkrétan az adott elemet. Ha olyan elemre hivatkozunk, amit nem töltöttünk fel (pl. Tabla(557)-re), akkor NO_DATA_FOUND hibát kapunk.
A tábla kinullázása a tabla := 0; paranccsal történik, ekkor a megfelelő elemek 0-t kapnak értékül.
Amennyiben a táblát a NOT NULL opcióval hoztuk létre, akkor a táblának nem lehetnek ismerterlen (azaz NULL) értékei.

Direktszorzat típus

Rekordok

Rekord típus definiálása:

TYPE név IS RECORD ( név1 típus1 név2 típus2 . . );

A %TYPE és a %ROWTYPE:

Sok esetben, egy PL/SQL változó arra való, hogy egy meglévő relációban lévő adatokat manipuláljunk. Ebben az esetben elvárandó, hogy a változó típusa megeggyezen a tábla-oszlop típusával. Ha ez nem így van (típuskülönbözőség), akkor az értékadások és összehasonlítások nem biztos, hogy úgy működnek, ahogyan azt elvárnánk. Ahelyett, hogy explicit megmondanánk a változó típusát, biztonságosabb a %TYPE operátor használata. Például:

myName Students.name%TYPE;

A myName ekkor olyan típusú lesz, amilyennek a Students tábla name oszlopát deklarálták.

Egy változó lehet egy rekord típusú is, melynek több mezője van. Ilyen esetben a legegyszerűbb módszer a %ROWTYPE használata a reláció nevén. Az eredmény egy rekord típus lesz, olyan mező nevekkel és típusokkal, amilyenek a tábla attribútumai. Például:

beerTuple Beers%ROWTYPE;

A kódrészlet létrehoz egy beerTuple változót rekordként, aminek a mezői name és manufacture lesz, mivel a reláció sémája: Beers(name, manufacture).

Típuskonverziók

Egy nem korlátozott altípus minden további konverzió, stb. nélkül kompatibilis a bázis-típusával. A korlátozásokkal rendelkező altípus szintén kompatibilis bázis-típusával, azonban vigyázzunk, hogy a programunk futása közben ne sértsük meg a korlátozást, ugyanis az futási idejű hibát okoz (kivételt vált ki). Tipikus programozói hiba például egy korlátozott hosszú sztringnek (pl. VARCHAR2(10)) egy, a korlátnál hosszabb (jelen esetben ez több, mint tíz karakter hosszú) sztring értékül adása.

Eltérő altípusok kompatibilisek egymással, ha megegyezik a bázis-típusuk. A bázis-típus eltérése esetén is lehetséges konverzió nélküli kompatibilitás, például az azonos családba tartozó típusok esetén (pl. CHAR - VARCHAR2), de minden más esetben konverzióhoz kell folyamodnunk. Ezt néhány esetben a nyelv automatikusan megteszi (implicit konverzió), de mi is használhatunk konverziós függvényeket (explicit konverzió).

A következő táblázat tartalmazza az implicit konverzió lehetséges eseteit. Ha az ezen kívül eső esetekben nem alkalmazunk explicit konverziót, akkor fordítási hibát fogunk kapni.

Implicit konverzió

Változók, konstansok

A változókat használatuk előtt deklarálni kell:

változó_név típus; változó_név típus := érték;

Egy változót kötelezően inicializálnunk kell. Ez nem történik meg automatikusan, minden változó a deklarálás után a NULL értéket veszi fel. Egy változónak a ':=' operátorral adhatunk értéket. Példa:

szam NUMBER; sorszam ugyfel.sorszam%TYPE; tmp_str VARCHAR2(100) := 'Default ertek';

Konstansokat a következőképpen hozhatunk létre:

konstans_név CONSTANT típus := érték;

Példa:

credit_limit CONSTANT NUMBER := 5000;