/* 1. példa */

/* Először deklarálunk egy egészekből álló tömböt, majd azt inicializáljuk, de nem töltjük fel elemekkel.
Ezek után hivatkozunk egy elemére, ám mivel a tömb még egyetlen elemet sem tartalmaz, a rendszer úgy veszi, hogy
a tömb egyetlen elemet sem ta. Ez a más programozási nyelveknél megszokott eltérő viselkedés annak a
következménye, hogy a beágyazott táblát és a dinamikus tömböt az esetek legnagyobb részében relációs táblák attribútumaként használjuk. */

DECLARE
        TYPE egesz_tomb IS VARRAY(20) OF INTEGER;
        sor            egesz_tomb:=egesz_tomb(); -- a konstruktor függvény paraméterek nélkül
BEGIN
        sor(1):=3;
        DBMS_OUTPUT.PUT_LINE(TO_CHAR(sor(1)));
EXCEPTION
        WHEN SUBSCRIPT_BEYOND_COUNT THEN
                DBMS_OUTPUT.PUT_LINE('Olyan elemere hivatkoztunk a dinamikus tombnek, '
                        'melyet meg nem inicializáltunk, ezért az nem létezik.');
END;

/* Miután az inicializációnál a sor dinamikus tömb első és második eleme értéket is kapott a konstruktor
függvény meghívásakor, ezért azokra később hivatkozhatunk. Ha viszont a harmadik elemre hivatkozunk, ismét
kivétel váltódik ki. */

DECLARE
        TYPE egesz_tomb IS VARRAY(20) OF INTEGER;
        sor            egesz_tomb:=egesz_tomb(54); -- a konstruktor függvény paraméterekkel
BEGIN
        DBMS_OUTPUT.PUT_LINE('Elotte: ' || TO_CHAR(sor(1)));
        sor(1):=3-- Ezt lehet.
        DBMS_OUTPUT.PUT_LINE('Utana: ' || TO_CHAR(sor(1)));
        sor(3):=5-- Ezt már nem.
        DBMS_OUTPUT.PUT_LINE('Es most: ' || TO_CHAR(sor(3)));
EXCEPTION
        WHEN SUBSCRIPT_BEYOND_COUNT THEN
                DBMS_OUTPUT.PUT_LINE('Olyan elemere hivatkoztunk a dinamikus tombnek, '
                'melyet meg nem inicializáltunk, ezért az nem létezik.');
END;

/* Példa a SUBSCRIPT_BEYOND_COUNT és a SUBSRIPT_OUTSIDE_LIMIT kivételek közti különbségre. */

DECLARE
        TYPE egesz_tomb IS VARRAY(20) OF INTEGER;
        sor            egesz_tomb:=egesz_tomb(54); -- a konstruktor függvény paraméterekkel
BEGIN
        DBMS_OUTPUT.PUT_LINE('Elotte: ' || TO_CHAR(sor(1)));
        sor(1):=3-- Ezt lehet.
        DBMS_OUTPUT.PUT_LINE('Utana: ' || TO_CHAR(sor(1)));
        sor(21):=5-- Túl "nagy" indexre hivatkozunk.
        DBMS_OUTPUT.PUT_LINE('Es most: ' || TO_CHAR(sor(3)));
EXCEPTION
        WHEN SUBSCRIPT_BEYOND_COUNT THEN
                DBMS_OUTPUT.PUT_LINE('Olyan elemere hivatkoztunk a dinamikus tombnek,' 
                        'melyet meg nem inicializáltunk, ezért az nem létezik.');
        WHEN SUBSCRIPT_OUTSIDE_LIMIT THEN
                DBMS_OUTPUT.PUT_LINE('Tulleptuk a dinamikus tomb deklaraciojakor megadott felso hatart!')
END;

/* 2. példa */

DECLARE
        TYPE egesz_tomb IS TABLE OF INTEGER INDEX BY BINARY_INTEGER;
        sor            egesz_tomb; -- Itt nincs konstruktor függvény.
BEGIN
        sor(1):=3-- Ezt lehet.
        DBMS_OUTPUT.PUT_LINE(TO_CHAR(sor(1)));
        DBMS_OUTPUT.PUT_LINE('Es most: ' || TO_CHAR(sor(3))); -- Ezt nem.
EXCEPTION
        WHEN NO_DATA_FOUND THEN
                DBMS_OUTPUT.PUT_LINE('Olyan elemere hivatkoztunk az indexelt tablanak,' 
                        'melynek meg nem adtunk erteket, ezert az nem letezik.');
END;

/* 3. példa */

/* A program véletlen számokkal tölt fel egy mátrixot, majd kiírja az elemeit.
A kollekciók indexelt tábla típusúak, emiatt a ciklusok megszervezése kissé bonyodalmas. */

DECLARE
        TYPE sor IS TABLE OF INTEGER
                INDEX BY BINARY_INTEGER;
        TYPE matrix IS TABLE OF sor
                INDEX BY BINARY_INTEGER;
        v_matrix                       matrix;
        i                                      INTEGER;
        j                                      INTEGER;

BEGIN
-- Véletlen számokkal töltjük fel a mátrixot. Az indexek nem folytonosan szerepelnek.
        FOR i IN 1..3 LOOP
                FOR j IN 1..2 LOOP
                        v_matrix(2*i)(3*j):=ROUND(DBMS_RANDOM.NORMAL());
                END LOOP;
        END LOOP;
        DBMS_OUTPUT.PUT_LINE('Az első mátrix:');
        DBMS_OUTPUT.NEW_LINE;
-- Kiiratjuk a mátrix sorait.
        i:=v_matrix.FIRST;
        WHILE i IS NOT NULL LOOP
                j:=v_matrix(i).FIRST;
                WHILE j IS NOT NULL LOOP
                        DBMS_OUTPUT.PUT_LINE(v_matrix(i)(j) || ' ');
                        j:=v_matrix(i).NEXT(j);
                END LOOP;
                DBMS_OUTPUT.NEW_LINE;
                i:=v_matrix.NEXT(i);
        END LOOP;
END;

/* 4. példa */

/* A legelső példa javítása. Mielőtt a sor tömb első elemére hivatkoznánk, megnöveljük a sor méretét
eggyel, hogy ezt megtehessük. */

DECLARE
        TYPE egesz_tomb IS VARRAY(20) OF INTEGER;
        sor            egesz_tomb:=egesz_tomb();
BEGIN
        sor.EXTEND;
-- Most már hivatkozhatunk az első elemre.
        sor(1):=3;
        DBMS_OUTPUT.PUT_LINE(TO_CHAR(sor(1)));
EXCEPTION
        WHEN SUBSCRIPT_BEYOND_COUNT THEN
                DBMS_OUTPUT.PUT_LINE('Olyan elemere hivatkoztunk a dinamikus tombnek,' 
                                        'melyet meg nem inicializáltunk, ezért az nem létezik.');
END;

/* 5. példa */

/* A program azon ügyfeleknél, akiknek több, mint 500000 forint van a számláin összesen,
megnöveli a keretet 200000 forintra, majd kiírja, hogy hány ilyen változtatás történt az egyes
ügyfelek esetén. A feladat majdnem megegyezik a PL_SQL_kurzor.ppt fájlban található 5. feladattal. */


DECLARE
        TYPE azon_tomb IS VARRAY(20) OF VARCHAR2(3);
        sor            azon_tomb;
BEGIN
        SELECT u.azon
        BULK COLLECT INTO sor
        FROM ugyfel u, szamla sz
        WHERE u.azon = sz.ugyf_azon
        GROUP BY u.azon
        HAVING SUM(osszeg)>500000;
        FORALL i IN sor.FIRST..sor.LAST
                UPDATE ugyfel SET keret = 200000
                WHERE azon = sor(i);
        FOR i IN sor.FIRST..sor.LAST LOOP
                DBMS_OUTPUT.PUT_LINE(sor(i) ||' azonositonal ' || SQL%BULK_ROWCOUNT(i) || ' valtoztatas tortent.');
        END LOOP;      
END;