TRANSACTION TRIGGERS



Scopurile acestui capitol

Acest capitol va prezinta toate tipurile de triggere care sunt asociate cu momentul executiei instructiunii commit.

Dintre subiectele tratate:



Executia comenzii `commit'




Executia comenzii commit

Acesta este evenimentul care incearca sa faca datele din baza de date identice cu cele din forma. Acest proces implica:

  1. Scrierea sau trimiterea in baza de date

  2. Incredintarea datelor bazei de date



In cazul in care comanda se incheie cu succes toate modificarile devin permanente (daca nu vor fi modificate in tranzactii viitoare) si se reflecta in interogarile viitoare ale tuturor utilizatorilor.


Trimiterea datelor

Trimiterea consta in scriarea stergerilor, inserarilor si actualizarilor din forma in baza de date, dar fara executarea acestor tranzactii in baza de date. Fiecare commit trebuie sa eralizeze o trimitere.

Trimiterea poate surveni si separat de un `commit' prin procedura package POST. Nu exeista tasta functionala asociata cu POST.


Realizarea transformarilor

Commit garanteaza faptul ca tranzactiile care au fost trimise au devin permanente.


Ce produce Commit ?

Executia unui commit survine in oricare sin situatiile:


Puncte de salvare (savepoints) si reveniri (rollbacks)




Puncte de salvare si reveniri

Termenii urmatori se refera la executia unui commit :

Tranzactie
o unitate logiga de lucrare. In speta, o tranzactie este o secventa de comenzi SQL pe care Oracle le trateaza ca pe o unitate. O tranzactie incepe cu prima comanda SQL executabila dupa un Commit, Rollback sau conectare la baza de date. O tranzactie se incheie cu Commit, o revenire sau o deconectare de la baza de date.

Revenire (Roll Back)
o functie interna care anuleaza efectele operatiilor tranzactiei curente. SQL*Forms utilizeaza punctele de salvare pentru a imparti o tranzactie in segmente pentru reglarea revenirilor.

Punct de salvare (Savepoint)
un mod de identificare a unui punct dintr-o tranzactie la care se poate reveni.



Puncte de salvare aparute la trimitere (Post)

Ori de cate ori apare o trimitere (ca parte dintr-o executie Commit su Post), SQL*Forms genereaza un punct de salvare. La aparitia unei erori in timpul executiei tranzactiei, SQL*Forms readuce tranzactia la punctul de salvare.


La executia cu succes a lui Commit

Daca evenimentul in executie este un Commit (nu doar un Post) si executia se incheie cu succes, intreaga tranzactie este realizata. In alte cuvinte, un Commit realizeaza intreaga tranzactie, pe cand o revenire poate realiza intoarcerea la un punct de salvare din corpul tranzactiei.

Poate un trigger sa genereze un Savepoint ?

SQL*Forms mentine propriul sau unit pentru commit. Aceasta inseamna ca orice punct de salvare generat dintr-un trigger va fi ignorat.


Transaction Triggers

Secventa de actiuni la Commit (1)

        1. Navigheaza la nivelul formei                  ---------------
                                        \               |               |
        2. Activeaza PRE_COMMIT           \             |       1       |
                                            \           |               |
        3. Proceseaza blocurile               \          ---------------
                                                \
        ---------------------------------         \      ---------------
                                                    \   |               |
            Pentru fiecare bloc                       \ |       2       |
                                                        |               |
            Verifica fiecare inregistrare                ---------------

            (1) Executa stergerile                       ---------------
                                                        |               |
            (2) Executa Inserarile/actualizarile        |       n       |
                                                        |               |
        ---------------------------------                ---------------

        4. Activeaza POST_COMMIT



Secventa de actiuni la Commit (2)

  1. Executia stergerilor
                                   ----------------------
                                  | activeaza PRE-DELETE |
                                   ----------------------
                                    /                 \
                                   |                   |
                                   V                   V
                    ---------------------          ----------------------
                   | activeaza ON-DELETE |  SAU   | sterge inregistrarea |
                    ---------------------          ----------------------
                                   |                    |
                                    \                  /
                                     V                V
                                   -----------------------
                                  | activeaza POST-DELETE |
                                   -----------------------
    
    
  2. Executia Inserarilor/stergerilor
                             -----------------------------
                            | activeaza PRE-INSERT/UPDATE |
                             -----------------------------
                               /                       \
                              |                         |
                              V                         V
             ----------------------------       ------------------------
            | activeaza ON-INSERT/UPDATE | SAU | insereaza/actualizeaza |
            |                            |     |    inregistrarea       |
             ----------------------------       ------------------------
                            |                               |
                             \                             /
                              V                           V
                             --------------------------------
                            |  activeaza POST-INSERT/UPDATE  |
                             --------------------------------
    
    
    

Secventa de actiuni la Commit

Cand are loc un Commit sau Post, se produc urmatoarele :

  1. Cursorul "logic" navigheaza la nivelul formei, activand orice trigger de nevigatie relevant.

  2. Se activeaza PRE-COMMIT trigger

  3. Blocurile sunt executate dupa numarul de secventa
                  * In fiecare bloc :
                    
                            - e procesata fiecare inregistrare marcata pentru
                              stergere:
    
                                se activeaza PRE-DELETE trigger
    
                                se activeaza ON-DELETE trigger (daca exista) SAU
                                se sterge inregistrarea
    
                                se activeaza POST-DELETE trigger
    
                            - e procesata fiecare inregistrare marcata pentru
                              inserare/actualizare :
    
                                se activeaza PRE-INSERT/UPDATE trigger
    
                                se activeaza ON-INSERT/UPDATE trigger (daca exista)
                                SAU inregistrarea este inserata/actualizata
    
                                se activeaza POST-INSERT/UPDATE trigger
    


  4. Se activeaza POST-COMMIT trigger.

  5. Daca evenimentul este POST, este afisat un mesaj si executia se opreste.

    Daca evenimentul este COMMIT, actiunea are loc si este afisat un mesaj.


Utilizarea Transaction Trigger-elor la nivelul formelor



Utilizarea triggerelor ON-< eveniment>



Utilizarea triggerelor Pre- si Post-< eveniment>



Exemple de Pre- si Post-Inserare

De obicei Pre-Insert trigger este folosit pentru a atrbui o valoare unica unei chei primare a unui camp. Trigerul poate fie sa urilizeze o secventa de numere generata automat, fie sa citeasca un numar dintr-o tabela cu secventa de numere.

Exemplul 1 - Folosesind o secventa V6

De notat ca aceasta metoda "pierde" mai putine numere in secventa decat daca s-ar folosi: SEQUENCE.name.NEXTVAL ca valoare implicita a unui camp.

        PRE-INSERT on EMP BLOCK
        - - - - - - - - - - - - - - -
        SELECT          empno.nextval
        INTO            :emp.empno
        FROM            SYS.DUAL


        Exemplul 2 - Folosind o tabela cu secventa de numere
        ----------

        PRE-INSERT on EMP Block
        - - - - - - - - - - - - - - - - - - - - -
        SELECT          maxvalue + 1, ROWID
        INTO            :emp.empno, :emp.scr_rowid
        FROM            maxseqnos
        WHERE   table_name = 'EMP'
        FOR UPDATE OF maxvalue;


        POST_INSERT on EMP Block
        - - - - - - - - - - - - - - - - - - -
        UPDATE          maxseqnos
        SET             maxvalue = :emp.empno
        WHERE           ROWID = :emp.scr_rowid;


Dintr-un punct de vedere, utilizarea unei secvente versiunea 6 (ca in exemplul 1) este preferabila utilizarii unei tabele cu secventa de numere (exemplul 2) deoarece secventele nu sunt niciodata `zavorate' SI numerele de secventa sunt "ascunse". Avantajul folosirii unei tabele este acela ca secventele dumneavoastra vor fi continue.

Observati folosirea lui ROWID in exemplul de mai sus. ROWID pointeaza spre o locatie a unei linii in baza de date. In exemplu, este folosit pentru marirea vitezei actualizarii. Rowid este dezbatut in detaliu la sfarsitul capitololui.

Executia unei actualizari

                        ... cresterea salariului lui Scott

                                        tabela de pe    segment de
                                           ecran        revenire
        -------------------------------------------------------------
        interogarea liniei              3000    3000
        actualizarea liniei             4500    3000
        COMMIT
                                --------------------------------------
        (PRE-COMMIT)
        PRE-UPDATE                      4500    3000
        actualizare                     4500    4500      3000
        POST-UPDATE                     4500    4500      3000
        (POST-COMMIT)
                                ---------------------------------------
        generare COMMIT
        ------------------
        \                /
          \            /
            \        /
              \    /
                \/

        'transaction complete'


Executia unei actualizari

In alegerea tipului triggerului pe care sa-l folositi pentru un anume scop, trebuie sa stabiliti ce valori poate accesa fiecare tip de trigger.<

De exemplu, daca doriti sa aflati daca marirea de salariu a lui Scott este mai mare de 10% din vechiul salariu, ati avea nevoie sa folositi mai degraba un trigger Pre-Update (care poate accesa vechiul si noul salariu) decat un trigger Post-Update (care are acces doar la noul salariu).

Tabelul de mai jos indica vaorile pe care le poate accesa fiecare trigger.

        Tipul triggerului       Ce poate accesa din inregistrarea pe care o
                                proceseaza
        -----------------       --------------------------------------------
        Pre-Insert              doar campurile ecran ale liniei curente

        Post-Insert             doar inregistrarea noua, fie in baza da date,
                                fie pe ecran

        Pre-Update              noile valori ale datelor pe ecran SI vechile
                                valori ale datelor in baza de date

        Post-Update             numai valorile revizuite, fie in inregistrarea
                                din baza de date, fie pe ecran

        Pre-Delete              inregistrarea din baza de date SI inregistrarea
                                care a fost stearsa de pe ecran! Chir daca
                                linia nu mai este afisata,un trigger Pre-Delete
                                SE POATE referi la campurile sale

        Post-Delete             nici inregistrarea din baza de date, nici cea
                                stearsa de pe ecran


Exemple Commit Trigger (1)

Suita de triggere de mai jos pastreaza `urma' numerelor inregistrarilor actualizate, inserate sau sterse. Triggerul Post-Commit scrie informatia intr-un fisier de log.

        PRE-COMMIT
        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        :GLOBAL.changes_to_commit := 'Y';
        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        POST-UPDATE
        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        DEFAULT_VALUE('0', 'GLOBAL.updates');
        :GLOBAL.updates := TO_NUMBER(:GLOBAL.updates) + 1;
        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        POST-DELETE
        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        DEFAULT_VALUE('0', 'GLOBAL.deletes');
        :GLOBAL.updates := TO_NUMBER(:GLOBAL.deletes) + 1;
        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        POST-INSERT
        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        DEFAULT_VALUE('0', 'GLOBAL.inserts');
        :GLOBAL.updates := TO_NUMBER(:GLOBAL.inserts) + 1;
        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        
        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        DEFAULT_VALUE('N', 'GLOBAL.changes_to_commit');
        IF      :FLOBAL.changes_to_commit = 'Y' THEN
                :GLOBAL.changes_to_commit := 'N';
        INSERT INTO LOG_FILE
        (user_id, form_name, update_date, inserts, updates, deletes)
        VALUES
        (USER, :SYSTEM.CURRENT_FORM, SYSDATE, :GLOBAL.inserts,
        :GLOBAL.updates, :GLOBAL.deletes);
        ERASE ('global.updates');
        ERASE ('global.deletes');
        ERASE ('global.inserts');
        END IF;
        POST-COMMIT
        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


Observati folosirea lui GLOBAL.changes_to_commit in acest exemplu. Acesta este necesar intrucat Pre-Commit se activeaza numai cand exista schimbari de efectuat, pe cand Post-Commit se activeaza INTOTDEAUNA cand se incearca un commit.

Exemple Commit Trigger (2)

Validarea stergerilor

Cand doriti sa preveniti stergerea inregistrarilor in anumite circumstante, va trebui sa validati stergerea in doua locuri :



Observati ca PRE-DELETE trigger nu executa functia Delete_Record. Delete_Record este o procedura intr-un package restrictionat.


ATRIBUTELE CURSORULUI


                                valoarea                valoarea
        Atribut         `if SQL found/acted'       if SQL found/acted
                              pe 0 linii             pe inca o linie

        SQL%NOTFOUND            TRUE                    FALSE

        SQL%FOUND               FALSE                   TRUE

        SQL%ROWCOUNTO           number of rows found/affected



Scrierea DML-urilor in triggere

In legatura cu sintaxa unei comenzi DML intr-un trigger nu apare nimic neobisnuit.

Doar amintim :



Cum testam rezultatul unei operatii DML ?

Ori de cate ori SQL*Forms executa pentru prima oara un trigger, asociaza o zona de lucru numita `cursor' cu ficare instructiune SQL. Intrucat cursorul este asociat implicit, se numeste cursor implicit.
Dupa executia unei comenzi SQL puteti testa rezultatul interogand atributele cursorului implicit (vezi tabelul pentru numele atributelor)

Observatie: testati atributele cursorului imlicit in sectiunea executabila a blocului, NU in cea de exceptii. Actionand pe zero sau mai mult de o coloana NU provoaca o exceptie.

        Exemplul 1:
        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        DELETE FORM emplist WHERE empno = :emp.empno;
        IF SQL%FOUND THEN
                INSERT INTO emp_history (empno, ename, hiredate, leaving_date)
                       VALUES (:emp.empno, :emp.ename, :emp.hiredate, SYSDATE);
        END IF
        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        
        Exemplul 2:
        
        Acest trigger nu reuseste operatia de actualizare daca ORDID curent nu
        e gasit in tabela ORD.

        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        UPDATE orders
                SET shipdate = SYSDATE
                WHERE ordid = :ord.ordid;
        IF SQL%NOTFOUND
                THEN MESSAGE ('Cannot find an order of that number');
                        RAISE FORM_TRIGGER_FAILURE;
        END IF;
        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

Ce este ROWID ?

                                     ROWID

                 -------------------------------------------------------
                |                                                       |
                |       0 0 0 4 B 2 9 8  .  0 0 0 9  .  0 0 0 1         |
                |      |---------------|   |-------|   |-------|        |
                |           Block             Row         File          |
                |                                                       |
                 -------------------------------------------------------



Folosirea lui ROWID in SQL*Forms

Cand creati un bloc intr-o forma, SQL*Forms adauga un camo invizibil si neactualizabil numit ROWID. Cand o inregistrare este readusa in spatiul de lucru, valoarea lui ROWID este readusa si ea. Inregistrarile recent create nu corespund nici unei linii si, de aceea, au ROWID nul.

SQL*Forms foloseste ROWID pentru a gestiona tranzactiile in bocurile din SQL*Forms si tabelele asociate cu ele. Din acest motiv, in majoritatea cazurilor nu este necesar sa va preocupe ROWID.


Cand folosim ROWID in SQL*Forms ?



Fie o forma pentru tabela ORD care mentine o un fisier cu istoria oricaror schimbari in oricare comanda. De fiecare data cand este actualizata ORD, continutrile originale ale liniilor actualizate vor fi stocate intr-o tabela numita ORDER_HISTORY.

        Exemplu:

                PRE-UPDATE/PRE-DELETE on ORD Block
                - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                INSERT INTO order_history
                (ordid, orderdate, commplan, custid, shipdate, total)
                SELECT ordid, orderdate, commplan, custid, shipdate, total
                FROM    ord
                WHERE ROWID = : ord.ROWID;
                - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -


De fiecare data cand o linie din ORD este actualizata sau stearsa, triggerul adauga o linie la ORDER_HISTORY corespunzand unei linii din ORD al carei ROWID este egal cu cel din blocul curent.

Transaction Trigger. Recomandari

  1. Revenirea se face la ultimul punct de salvare; Daca reuseste, Commit executa toata tranzactia.

  2. Doar tranzactiile trigger pot executa DML.

  3. Pentru a testa rezultatul unei comenzi DML, folositi atributele cursorului implicit.
               De exemplu:
    
                    IF SQL%ROWCOUNT > 5  THEN
    

    Asigurati-va ca testati atributele cursorului implicit in sectiunea executabila a blocului, NU in sectiunea de exceptii.

  4. ROWID poate fi folosit pentru a referi, din baza de date, o linie care corespunde cu cea procesata curent. Daca utilizatorului i se permite sa modifice cheia primara a unei inregistrari, ROWID este singura cale de a identifica ce inregistrare a fost modificata. Un utilizator nu poate modifica campul ROWID.

  5. In general, e nerecomandabil sa modificati campurile bazei de date in timpul evenimentului Commit. De exemplu cand actualizati tabela ITEM, nu modificati campul TOTAL in blocul ORD.

  6. Pre si Post-Commit se activeaza doar o singura data pentru o tranzactie.

    Pre-Commit Se activeasa numai atunci cand sunt schimbari de facut, pe cand Post-Commit se activeaza DE FIECARE DATA cand se incearca un commit.

  7. On-Insert, On-Delete si On-Update (**really do pre-empt SQL*Forms**) Daca atunci cand folositi aceste triggere doriti sa inserati, actualizati sau stergeti linia curenta, va trebui sa specificati dvs. explicit aceasta.

  8. Pe un sistem multiutilizator, scrieti validarea stergerii in doua locuri (Key-Delete si Pre-Delete) pentru a fi siguri ca utilizatorului nu i se permite sa execute o stergere invalida.


Comenzi valide in functie de tipul triggerului

Dupa ce am vazut varietatea de tipuri de triggere si diversitatea codului triggerelor, sa vedem care instructiuni apartin carui tip de trigger. Regulile sunt aceleasi, odata ce ati invatat sa identificati ce proceduri package sunt limitate la key-triggers. Tabelul de mai jos ar trebui sa clarifice regulile.

                Tipul comenzii                  Tipul Triggerului
                -------------------             -------------------------
                SQL:
                        SELECT                  oricare

                        DDL                     nici unul!

                        DML                     tranzaction triggers


                PL/SQL:
                        PL?SQL standard         oricare

                        proceduri package       key triggers
                        limitate                ON-NEW-FIELD-INSTANCE

                        proceduri package
                        nerestrictionate


REZUMAT (trigger): Toate triggerele V3

        Triggere eveniment

        Domeniu   Nume
        -------   ---------------------                         --------
        Camp      PRE-FIELD, POST-FIELD                                 |
        (Field)   POST-CHANGE                                           |
                  ON-VALIDATE-FIELD          -----------------------    |
                  ON-NEW-FIELD-INSTANCE ==> |si procedurile package |   |
                  ON-ERROR                  |    restrictionate     |   |
                  ON-MESSAGE                 -----------------------    |
        .....................................................           |
                                                                        |
        Bloc      PRE-QUERRY, POST-QUERRY                               |
                  ON-LOCK                           ----                |
                  PRE-DELETE, PRE-INSERT, PRE-UPDATE    |               |
                  ON-DELETE, ON-INSERT, ON-UPDATE       |-> AND DML     |
                  POST-DELETE, POST-INSERT, POST-UODATE |               |
                  PRE-RECORD, PRE-BLOCK             ----                |
                                                                        |
                  POST-RECORD, POST-BLOCK                -------------------
                  ON-VALIDATE-RECORD                    | PL/SQL, SELECT si |
                  ON-DATABASE-RECORD                    | proceduri pkg     |
                  ON-REMOVE-RECORD                      | nerestrictionate  |
                  ON-NEW-ERCORD                          -------------------
                  ON-CLEAR-BLOCK                                        |
        .....................................................           |
        Forma     PRE-FORM, POST-FORM                                   |
                  PRE-COMMIT, POST-COMMIT   ==> AND DML         --------


        Triggere Program
        ================

        Domeniu         Nume
        -------         ----------------
        Camp            toate KEY-triggerele                    --------
        .....................................................           |
                                                                        |
        Bloc            toate KEY triggerele                            |
                                                         -------------------
                                                        | PL/SQL, SELECT si |
                                                        | TOATE procedurile |
                                                        | package           |
                                                         -------------------
                                                                        |
        .....................................................           |
        Forma           toate KEY-triggerele                    --------


Cap. 20 Exercitii

Generare de numere de secventa & `Zavorarea (**Non-base Tables**)

Acest exercitiu este realizat pentru a va arata cum se folosesc tabelele cu numere de secventa pentru a crea identificatori unici pentru inregistrarile inserate in baza de date.

  1. Exista o tabela cu numere de secventa si se numeste SEQNOS (structura si continutul ei le gasiti in Anexa D); Folositi-o pentru a genera o valoare noua pentru CUSTID cand este inserat un nou client. Incrementati de fiecare data CUSTID cu 1. Utilizatorul nu trebuie sa poata modifica campul CISTID.

    Linia in tabela `seqnos' (cu numere de secventa) corespunzatoare lui CUS mentine un `maxseqno' de 111 (i.e. a fost construita presupunand ca valoarea maxima pentru CUSTID curent este 111. Daca ati adaugat/ /sters clienti veti avea nevoie sa-i modificati valoarea prin intrarea in SQL*Plus (acelasi nume de utilizator si parola) si sa modificati inregistrarea CUS.

  2. Pentru fiecare articol de linie introdus intr-o comanda, generati un numar unic de linie. Din nou, ar trebui sa aiba un increment de 1. Folositi coloana MAXLINE din tabela ORDER. Faceti ITEM.ITEMID inaccesibil (asa cum va fi generat articolul) si deselectati atributul REQUIRED.

    In exercitiul anterior ati inserat/sters inregistrari fara sa ajustati valoarea lui MAXLINE in tabela ORD. Aceasta va afecta numerele generate pentru identificatorii de articol. Daca asa stau lucrurile, intrati in SQL*Plus (acelasi nume de utilizator si parola), varificati si modificati datele daca este necesar.

    Daca aveti timp:

    ================
  3. Oricand un articol de linie este fie inserat, fie actualizat sau sters, calculati o noua ordine totala si afisati campul ORDERTOT al blocului ORD. Calculul trebuie facut la momentul in care are loc COMMIT. Retineti ca coloana ORDERTOT va trebui actualizata in tabela order. Pentru a economisi cod si a mari eficienta, mentineti codul intr-o procedura apelata de triggerele POST-UPDATE, INSERT si DELETE.

Cap 20 Solutii

        1a. PRE-INSERT in blocul CUS
                - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                SELECT maxseqno + 1, rowid
                INTO  :cus.custid, :cus.scr_rowid
                FROM  seqnos
                where   table_name = 'CUS'
                for update of maxseqno;
                - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        b. POST-INSERT in blocul CUS
                - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                UPDATE seqnos
                SET maxseqno = :cus.custid
                WHERE rowid = cus.scr_rowid;

        Pentru actualizarea lui `ordid'

        2a. PRE-INSERT in blocul ITEM
                - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                SELECT NVL(MAXLINE, 0) + 1, rowid
                INTO :item.itemid, :item.scr_rowid
                FROM ord
                WHERE ordid = :ord.ordid
                for update of ordid

        b. POST-INSERT in blocul ITEM
                - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                UPADTE ord
                SET maxline = :item.itenid
                WHERE rowid = :item.scr_rowid;


        Daca aveti timp :

        3a. Procedura la nivel de forma UPD_ORD_TOT
                - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                BEGIN
                SELECT nvl(sum(itemtot), 0)
                INTO :ord.total
                FROM    item
                WHERE ordid = :ord.ordid;


                UPDATE ord
                SET total = :ord.total
                WHERE ordid = :ord.ordid;
                END;

        b. POST-UPADTE, POST-DELETE in blocul ITEM
                - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                upd_ord_tot;

        c. POST-INSERT in blocul ITEM
                - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                UPADTE ord
                SET maxline = :item.itemid
                WHERE rowid = :item.scr_rowid;
                upd_ord_tot;