DESPRE CODUL FLEXIBIL

Scopul acestui capitol

Formele SQL au o multitudine de trasaturi ca, de exemplu, variabilele sis- tem si functiile impachetate care dau mai multa flexibilitate codarii progra- marii. Folosirea acestor proprietati permite scrierea de proceduri generice care pot fi folosite sub orice forma intr-o aplicatie. Acest capitol contine informatii despre:


VARIABILE SISTEM



Variabile sistem

Formele SQL pun la dispozitia programatorului mai multe variabile sistem care ofera informatii despre forma sau obiectele SQL din forme in timpul se- siunii RUNForm. In general, te poti referii la valoarea unei variabile sistem pentru a controla felul in care se comporta o aplicatie.

Variabilele sistem sunt folositoare mai ales:

Formele SQL pastreaza valorile pe baza formelor. Adica valorile tuturor va- riabilelor sistem corespund chiar formei curente.

O lista completa a numelor variabilelor sistem este in pagina urmatoare. SYSTEM.MESSAGE_LEVEL si SYSTEM.SUPPRESS_WORKING sunt singurele variabile ale caror valori pot fi schimbate. Valoarea lui STSTEM.MESSAGE_LEVEL determina ce mesaje informationale, de avertizare sau eroare va trimite SQL*Forms operato- rului.

SYSTEM.SUPPRESS_WORKING permite ca mesajul "in lucru" sa nu fie afisat.

CE CONTIN VARIBILELE SISTEM

Foloseste rularea pas cu pas pentru a te uita la variabilele sistem

   ____________________________________________________________________
  |          ______________________________________________            |
  |         |                                              |           |
  |         |            Debug mode option                 |           |
  |         |______________________________________________|           |
  |         |  Display Global Variables                    |           |
  |         |  Display System Variables                    |           |
  |         |  Display Page Zero Fields                    |           |
  |         |  Continue with Debug Messages                |           |
  |         |  Continue without Debug Messages             |           |
  |         |  Exit Runform                                |           |
  |         |______________________________________________|           |
  |                                                                    |
  |____________________________________________________________________|
   Fig 16.1: Debug Mode Options Screen


  Numele si valoarea variabilelor sistem
   ______________________________________________________________________
  |  ___________________________________________________________________ |
  | |                                                                  | |
  | |               System Variable Name and Values                    | |
  | |------------------------------------------------------------------| |
  | ||  Trigger_Block          |  Item                                 | |
  | ||  Trigger_Field          |  Item.Actualprice                     | |
  | ||  Current_Form           |  UNIT17                               | |
  | ||  Current_Block          |  Item                                 | |
  | ||  Trigger_Record         |  2                                    | |
  | ||  Curent_Field           |  Actualprice                          | |
  | ||  Current_Value          |  2.8                                  | |
  | ||  Cursor_Block           |  Item                                 | |
  | ||  Cursor_Record          |  2                                    | |
  | ||  Cursor_Field           |  Item.Actualprice                     | |
  | ||  Cursor_Value           |  2.8                                  | |
  | ||  Message_Level          |  0                                    | |
  | ||  Last_Query             |  Select ordid, itemid, prodid, actualp| |
  | ||  Record_Status          |  Query                                | |
  | ||  Last_Record            |  False                                | |
  | ||  Block_Status           |  Query                                | |
  | ||-----------------------------------------------------------------| |
  | |    Please acknowledge screen     Ok                              | |
  | |__________________________________________________________________| |
  |                                                                      |
  |______________________________________________________________________|
   ______________________________________________________________________
  |                                                                      |
  |  __________________________________________________________________  |
  | |                                                                  | |
  | | |  Form_Status            |  Query                               | |
  | | |  Suppress_Working       |  False                               | |
  | |__________________________________________________________________| |
  |                                                                      |
  |______________________________________________________________________|
     Fig 16.2: System  Variables


Ce contin variabilele sistem ?

Poate cel mai bun mod de a invata despre variabilele sistem este sa privesti valorile lor cand o forma este in lucru. Procedura BREAK ne ofera aceasta po- sibilitate atunci cand este executata in modul Debug.

Pentru a aparea fereastra Debug Mode Option ( vezi figura ) trebuie sa:

  1. Intri in Modul Debug
  2. Executi procedura Break de la un trigger.


Inca ceva despre variabilele sistem
<

Exemple:

VARIABILELE DE STARE ALE SISTEMULUI


        NUME               VALOARE         SEMNIFICATIE

SYSTEM.RECORD_STATUS       CHANGED      Inregistrarea  a fost  adusa din baza
                                        de date si un camp BASE TABLE din in-
                                        registrare a fost actualizat.

                           INSERT       Utilizatorul(sau un trigger) a intro-
                                        dus o valoare intr-un camp BASE TABLE
                                        a  unei  inregistrari  care nu a fost
                                        mai inainte chemata.

                           NEW          Inregistrarea  nu exista inca, altfel
                                        spus, nici un camp BASE TABLE din in-
                                        registrare  nu au fost  completate de
                                        utilizator sau de trigger.

                           QUERY        Inregistrarea  a fost  adusa din baza
                                        de  date dar nici un camp  BASE TABLE
                                        din inregistrare n-a fost  reactuali-
                                        zat.

SYSTEM.FORM_STATUS         CHANGED      forma contine cel putin o inregistra-
                                        re in starea GHANGED sau INSERT.

                           NEW          forma contine numia inregistrari NEW.

                           QUERY        forma cotine numai inregistrari QUERY.

SYSTEM.BLOCK_STATUS        CHANGED      blocul contine cel putin o inregistra-
                                        re in starea CHANGED sau INSERT.

                           NEW          blocul contine numai inregistrari NEW.

                           QUERY        blocul contine numai inregistrari
                                        QUERY.

Exemple de variabile sistem


Exemplul 1:

Sa presupunem ca vrei sa redefinesti tasta [CLEAR RECORD]astfel incat sa efectueze o ? inainte de a sterge inregistrarea.Trigger-ul urmato face acest lucru:
        KEY-CLRREC
        ------------------------------------------------------------------
        IF :SYSTEM.RECORD_STATUS = 'CHANGED'
                OR :SYSTEM.RECORD_STATUS = 'INSERT'
                THEN COMMIT_FORM;
        END IF;
        CLEAR_RECORD;
        ------------------------------------------------------------------

Exemplul 2:

Trigger-ul de mai jos suprima mesajele "in lucru" oricand operatorul executa inrogare globala din blocul DEPT.
        KEY-EXEQRT
        ------------------------------------------------------------------
        clear_dept_details;
        :system.suppress_working := 'TRUE';
        execute_query;
        query_dept_details;
        :system.suppers_working := 'FALSE';
        EXCEPTION
                when form_trigger_failure then null;
        ------------------------------------------------------------------

Exemplul 3:

Sa presupunem ca vreti sa redefiniti [PREVIOUS FIELD] din primul camp al blocului ITEM sa se transfere in ultimul camp al blocului ORD daca cursorul este plasat pe prima inregistrare. Urmatorul trigger executa aceasta functie:
        KEY-PRVFLD on ITEM.ITEMID
        ------------------------------------------------------------------
        IF :SYSTEM.CURSOR_RECORD = '1' THEN
                GO_FIELD('ORD.TOTAL');
        ELSE
                PREVIOUS_FIELD;
        END IF;
        ------------------------------------------------------------------


Folosirea lui SYSTEM.MESSAGE_LEVEL pentru a inhiba mesajele

Fiecare mesaj al formelor SQL are asociat un nivel de severitate. Cele mai putin severe mesaje ( ex: FRM-40100: La prima inregistrare ) sunt la nivelul 5, in timp ce mesajele pentru cele mai grave erori ( ex: FRM-40024: Depaseste memoria ) sunt la un nivel mai mare decit 25 si nu pot fi suprimate folosind SYSTEM.MESSAGE_LEVEL.

Pe scurt, iata o descriere a nivelelor mesajelor de severitate:

NIVEL DE SEVERITATE             DESCRIEREA MESAJULUI
-------------------             --------------------
0                               ( toate tipurile de mesaje de la alte nivele
                                de severitate )

5                               Reafirma o situatie evidenta.

10                              Indica faptul ca operatorul a facut ceva inco-
                                rect din punct de vedere procedural.

15                              Declara  ca operatorul  incearca sa execute o
                                functie pentru care nu exista forma.

20                              Indica o stare in care operatorul nu mai poa-
                                te continua o actiune pe care intentiona sa o
                                termine din cauza unei probleme cu un trigger sau
                                a unei alte situatii neobisnuite.

25                              Indica o stare care poate face forma sa execu-
                                te comanda incorect.

mai mare de 25                  Indica  un grad de severitate al mesajului la
                                care  acesta nu mai poate fi  suspendat  prin
                                intermediul variabilei SYSTEM.MESSAGE_LEVEL.

Exemple:
Urmatorul trigger interogheaza blocul EMP ori de cate ori tasta [ENTRY QUERY] este apasata din interiorul blocului DEPT. Daca nu sunt angajati in departa- mentul respectiv se va afisa un mesaj.
        KEY-ENTQRT on DEPT Block
        ------------------------------------------------------------------
        :SYSTEM.MESSAGE_LEVEL := 5;
        ENTRE_QUERY; NEXT_BLOCK; EXECUTE_QUERY;
        IF NOT FORM_SUCCESS THEN
                MESSAGE('This departament has no employees');
        END IF;
        PREVIOUS_BLOCK;
        :SYSTEM.MESSAGE_LEVEL := 0;
        ------------------------------------------------------------------

In exemplul de mai sus, SYSTEM.MESSAGE_LEVEL a primit valoarea 5 pentru a evita mesajul standard al formelor SQL: "Query retrived no records" ( Interogarea nu a gasit nici o inregistrare ).

Ori de cate ori scrii un mesaj pentru a inlocui un mesaj standard trebuie sa-i dai variabilei SYSTEM.MESSAGE_LEVEL valoarea potrivita. Altfel, operatorul tre- biue sa ia cunostinta de un mesaj inainte de al primi pe al doilea, poate unul redundant.

INTERCEPTAREA MESAJELOR FORMELOR SQL

Se pot intercepta sau chiar suspenda de tot mesajele informative sau de eroare ale formelor SQL.

SYSTEM.MESSAGE_LEVEL



SYSTEM.MESSAGE_LEVEL e folosit pentru a suspenda grupe de mesaje ale formelor SQL. Atribuiti-i o valoare intre 0 si 25 pentru a suspenda mesaje ale unui anumit nivel de securitate ( si pentru toate cele inferioare lui ). E singura variabila sistem careia ii poti da o valoare.

SYSTEM.MESSAGE_LEVEL poate lua oricare din urmatoarele nivele ale mesajelor de severitate: 0, 5, 15, 20 sau 25. Nivelele sunt ordonate crescator din punct de vedere al severitatii. In timpul secventei runform formele SQL su- prima orice mesaj cu un nivel mai mic sau egal cu nivelul inregistrat. Impli- cit valoarea este 0, adica nu se suprima nici un mesaj. Unele mesaje au nive- lele de severitate "25" si astfel nu sunt afectate de SYSTEM.MESSAGE_LEVEL.

Anexa E de la sectiunea referinte a formelor SQL, versiunea 3 contine o lista a mesajelor de eroare impreuna cu nivelele lor de gravitate asociate.


TRIGGERE PENTRU EROARE SI PENTRU MESAJE

Acestea permit intercepterea mesajelor de la formele SQL. Poti folosi functii comprimate ( ex: ERROR_TEXT ) pentru a testa mesajele pe aceste triggere fiti sigur ca utilizatorul primeste intotdeauna un mesaj al dvs. sau al formelor SQL ori de cate ori un mesaj este asteptat.

In exemplul de mai jos trigger-ul afiseaza mesaje alcatuite pentru anumite tipuri de erori dar, de asemenea pune la dispozitie formelor SQL un mesaj standard implicit.

        ON-ERROR on ORD.COMMPLAN
        ------------------------------------------------------------------
        IF ERROR_CODE = 50001 OR
        ERROR_CODE = 40207 THEN      -- alpha only/range check
                MESSAGE( 'You must enter A, B or C in this field');
        ELSE
                MESSAGE( ERROR_TYPE||'-'||TO_CHAR(ERROR_CODE)||':'||
                        ERROR_TEXT);
        END IF;
        RAISE FORM_TRIGGER_FAILURE;
        ------------------------------------------------------------------
   ________________________________________________________________________
  |                                                                        |
  |                                                                        |
  |                     MAI MULTE PACHETE DE FUNCTII                       |
  |                                                                        |
  |                                                                        |
  |     * PERMITE REFERINTA INDIRECTA                                      |
  |                                                                        |
  |             NAME_IN                                                    |
  |                                                                        |
  |     * INTEROGHEAZA CARACTERISTICILE OBIECTULUI                         |
  |                                                                        |
  |             APPLICATION_CHARACTERISTIC                                 |
  |                                                                        |
  |             FORM_CHARACTERISRIC                                        |
  |                                                                        |
  |             BLOCK_CHARACTERISTIC                                       |
  |                                                                        |
  |             FIELD_CHARACTERISTIC                                       |
  |                                                                        |
  |________________________________________________________________________|

NAME_IN

Pachetul de functii NAME_IN returneaza continutul variabilei asupra careia e aplicata. Daca fixezi functia NAME_IN formele SQL evalueaza toate functiile individuale, de la cea plasata cel mai in interior pana la cea mai indepartata. Nota: functia NAME_IN da functionalitate referintelor variabilelor ( '&variablename' ) in V2.

Sintaxa:
        NAME_IN    ( nume_variabila | NAME_IN( localizare ))

        :GLOBAL.X := NAME_IN(:F);

Cauta in F variabila cu o anumita valoare pentru a o copia in X.
        __________         ___________           __________
       |          |       |           |         |          |
       |    A     |       |  hello    |-------->|  hello   |
       |__________|       |___________|         |__________|
           F                    A                   X

Exemple:
  1. Pentru a transfera controlul blocului specificat in campul block.choice:
       GO_BLOCK(NAME_IN('block.choice'));


  2. Pentru a testa continutul campului care e specificat in global.saved_field:
       IF NAME_IN( NAME_IN( 'golbal.saved_field'))='TKB SPORT SHOP'
              THEN NEXT_FIELD;
            END IF;
    
    In exemplul 2 functia NAME_IN din interior va fi evaluata prima.

    APPLICATION_CHARACTERISTIC

    APPLICATION_CHARACTERISTIC iti da posibilitatea de a gasi numele fisierului formei curente sau numele formei care a apelat forma curenta.

            Sintaxa:  APPLICATION_CHARACTERISTIC( calling_form | current_form )
    

    Daca APPLICATION_CHARACTERISTIC(CALLING_FORM) intoarce NULL, nu exista nici o forma care apeleaza.
    Exemplu:
            KEY-STARTUP
            ------------------------------------------------------------------
            IF APPLICATION_CHARACTERISTIC(calling_form) IS NOT NULL THEN
                    EXECUTE_QUERY;
            END IF;
    
    

    FORM_CHARACTERISTIC

    Pachetul de functii FORM_CHARACTERISTIC furnizeaza numele primului sau ultimului bloc din forma.

    Sintaza:
            FORM_CHARACTERISTIC ( 'formname',primul_block/ultimul_bloc )
    
    

    BLOCK_CHARACTERSTIC

    Pachetul de functii intoarce informatii cu privire la blocul specificat.

    Sintaxa:
            BLOCK_CHARACTERISTIC('nume_bloc',caracteristica)
    
     CARACTERISTICA         INTOARCE:
    
    BASETABLE               intoarce numele tabelului de baza sau zero
    
    ENTERABLE               intoarce FALSE sau TRUE
    
    FIRST_FIELD             intoarce numele primului camp
    
    LAST_FIELD              intoarce numele ultimului camp
    
    NEXTBLOCK               blocul urmator sau zero
    
    PREVIOUSBLOCK           numele blocului anterior sau zero
    
    RECORD_DISPLAYED        numarul de inregistrari pe care le poate afisa blocul
    
    TOP_RECORD              numele primei inregistrari vizibile din bloc
    
    
    Exemple:
    Trigger-ul de mai jos testeaza pentru a vedea daca cursorul se afla in ultimul camp al blocului ORD. Daca se afla, trimite cursorul in blocul urmator; daca nu cursorul se muta in urmatorul camp.
    
            KEY-NXTFLD
            ------------------------------------------------------------------
            IF :system.cursor_field = 'ORD.' ||
                    BLOCK_CHARACTERISTIC('ord', LAST_FIELD )
            ELSE NEXT_FIELD;
            END IF;
            ------------------------------------------------------------------
    

    FIELD_CHARACTERISTIC

    Pachetul de functii FIELD_CHARACTERISTIC iti ofera posibilitatea de a specifica una din cele 23 de caracteristici posibile si de a cere un atribut al unui anumit camp. Valoarea obtinuta ca raspuns este sub forma unui sir de caractere.

    Sintaxa:
            FIELD_CHARACTERISTIC('nume_camp', caracteristica )
    


    Urmatoarele caracteristici de camp vor da valoarea TRUE daca atributul este selectat, FALSE daca nu e selectat:


    Urmatoarele caracteristici de camp vor intoarce numere( in format caracter ):


    NEXTFIELD si PREVIOUSFIELD intorc numele campului impreuna cu numarul de secventa cel mai mare/mic ( in functie de apropiere ).
    DATATYPE intoarce un string corespunzator cu caracteristica campului DATA TYPE.

    Exemplu:
    Intr-un trigger sau proceduras-ar putea sa vreti sa aflati la ce pagina se afla cursorul:
            FIELD_CHRACTERISTIC( :SYSTEM.CURSOR_FIELD, page );
                           |  |
                           |  |
                           |  |
                         --|  |--
                          \    /
                            \/
                    ANCHOR_VIEW(     , 1, 1);
    
    
    

    CAPITOLUL 16 EXERCITII:


    1. Scrieti un trigger KEY_DOWN in blocul ITEM care sa verifice daca cursorul s-a mutat la o inregistrare goala('NEW'). Daca da, sa o mute sus automat.Aceasta va impiedica folosirea, introducand inregistrarile goale la sfarsitul stivei; pentru a introduce un nou item va trebui sa folosim [Create Record].
      Inlocuiti mesajul standard 'FRM-40400 Tranzaction complete--X records posted and committed' cu unul care sa spuna 'Inregistrarile au fost depuse in baza de date'.
      Orice alte mesaje ale formei sa fie afisate in formatul lor normal.

    2. Scrieti o procedura WEEKEND_NOT_ALLOWED in care sa se asigure ca data introdusa nu este o zi de weekend. Daca este sa se afiseze un mesaj care include numele campului unde apare gresala.
      Trebuie sa fie scrisa astfel incat sa poata verifica date din orice camp din forma( adica ar trebui sa accepte un parametru care sa-i dea numele campului ce trebuie verificat in momentul in care o apelam ) Apelati aceasta procedura dintr-un trigger ON_VALIDATE_FIELD din ORD.ORDERDATE.

      Daca aveti timp:
      1. Creaza o functie "form-level" numita PAGE_NUM care poate fi folosita pentru a intoarce numarul paginiicurente.
      2. Modifica trigger-ul KEY_MENU din blocul CUS (veziexemlpul de mai jos) astfel incat sa foloseasca numarul pagini furnizat de KEY_NUM ca prim parametru in fiecare "anchor_view" declaratie .
                KEY-MENU on CUS block
                ------------------------------------------------------------------
                default_value ('0', 'global.cpos');
                :global.cpos := to_number(:global.cpos) + 1 ;
                if :global.cpos = 1 then anchor_view(3,1,1);
                        elsif :global.cpos = 2 then anchor_view(3,40,1);
                        elsif :global.cpos = 3 then anchor_view(3,1,15);
                        elsif :global.cpos = 4 then anchor_view(3,40,15);
                              :global.cpos :=0;
                end if;
                ------------------------------------------------------------------
        


    3. Scrie un trigger care sa faca urmatoarele:
               -beep-aie cand tasta [Count Query Hits] este apasata
      
               -verifica daca atributul Automatic Hint a campului curent este
                 apasata
      
               -daca da, sa o dezactiveze
      
               -daca nu, sa o activeze
      


    4. Nu "hard code" numele campului, pentru ca acest trigger trebuie sa functioneze pentru orice camp din forma dvs.

    CAP.16: Solutii



    1.      KEY-DOWN on ITEM block
           ---------------------------------------------------------------------
           DOWN;
           IF :SYSTEM.RECORD_STATUS = 'NEW'
              THEN UP;
           END IF;
           ---------------------------------------------------------------------
      


    2.      ON-MESSAGE at FORM level
           ---------------------------------------------------------------------
           IF MESSAGE ('Your recordshave committed to the database');
           ELSE MESSAGE(MESSAGE_TYPE||'-'||TO CHAR(MESSAGE_CODE)||':'||
                                              MESSAGE_TEXT);
           END IF;
           ---------------------------------------------------------------------
      


    3. a.
           Form-Level procedure WEEKEND_NOT_ALLOWED
           ---------------------------------------------------------------------
           PROCEDURE weekend_not _allowed ( field_name IN CHAR ) IS
      
           BEGIN
                 IF TO_CHAR(TO_DATE(NAME_IN(field_name),'DD-MON-YY'), 'DY')
                    IN ('SAT', 'SUN')
                       THEN message('weekend dates not allowed in '|| field_name);
                            raise from_trigger_failure;
                 END IF;
           END;
           ---------------------------------------------------------------------
        b.
           ON-VALIDATE-FIELD on ORD.ORDERDATE
           ---------------------------------------------------------------------
           WEEKEND_NOT_ALLOWED( 'ORD.ORDERDATE')
           ---------------------------------------------------------------------
      


    4.  a.  Form-level function PAGE_NUM
           ---------------------------------------------------------------------
           function PAGE_NUM return char is
           begin
           return(field_characteristic(:system.cursor_field,page));
           end;
           ---------------------------------------------------------------------
        b.
           KEY-MENU on CUS Block
           ---------------------------------------------------------------------
           DEFAULT_VALUE ('0', 'GLOBAL.CPOS');
           :GLOBAL_CPOS := TO_NUMBER(:GLOBAL.CPOS) + 1;
           IF :GLOBAL.CPOS = 1 THEN ANCHOR_VIEW(PAGE_NUM,1,1);
              ELSIF :GLOBAL.CPOS = 2 THEN ANCHOR_VIEW(PAGE_NUM,30,1);
              ELSIF :GLOBAL.CPOS = 3 THEN ANCHOR_VIEW(PAGE_NUM,30,10);
              ELSIF :GLOBAL.CPOS = 4 THEN ANCHOR_VIEW(PAGE_NUM,1,10);
                     :GLOBAL.CPOS := 0;
              ENDIF;
           ---------------------------------------------------------------------
      


    5.      KEY-CQUERY
           ---------------------------------------------------------------------
           IF FIELD_CHARACTERISTIC (:SYSTEM.CURSOR_FIELD, AUTO_HELP) = 'TRUE'
              THEN SET_FIELD (:SYSTEM.CURSOR_FIELD, AUTO_HELP, ATTR_OFF);
           ELSE
                SET_FIELD (:SYSTEM.CURSOR_FIELD, AUTO_HELP, ATTR_ON);
           ENDIF;
           ---------------------------------------------------------------------