Follow Us on Twitter

Oracle 11g feature van de maand: Efficiëntere PL/SQL code schrijven

December 2007 - Naast verbeteringen in de database, heeft Oracle ook enkele verbeteringen aangebracht in PL/SQL. Sommige zaken zijn geheel nieuw en andere zaken zijn aangepast om makkelijker gebruikt te worden. In dit Whitebook worden een aantal van de belangrijkste aanpassingen besproken.

Op 6 november vond de officiële release plaats van de nieuwste versie van de Oracle database: 11g. In een serie Whitebooks vertellen de techneuten van Whitehorses u alles over de belangrijkste nieuwe features. Deze maand deel 3 over de mogelijkheid tot het schrijven efficiëntere PL/SQL code.

Naast verbeteringen in de database, heeft Oracle ook enkele verbeteringen aangebracht in PL/SQL. Sommige zaken zijn geheel nieuw en andere zaken zijn aangepast om makkelijker gebruikt te worden. In dit Whitebook worden een aantal van de belangrijkste aanpassingen besproken.

Compound Triggers

Drie vernieuwingen hebben te maken triggers. Oracle heeft een nieuw type trigger toegevoegd en twee nieuwe opties toegevoegd aan het bestaande gebruik van triggers.

Het nieuwe type trigger is de Compound Trigger. Een compound trigger is een trigger die bestaat uit een willekeurige combinatie van de bestaande triggers die afgaan op Before Statement, Before Row, After Row en After Statement.

Door het gebruik van een compound trigger zijn er veel meer mogelijkheden en is een ontwikkelaar veel flexibeler bij ingewikkelde transacties. Het is bijvoorbeeld mogelijk om variabelen te gebruiken tussen de verschillende delen van de compound trigger. Iets wat bij de conventionele triggers alleen mogelijk is via constructies met bijvoorbeeld packages en PL/SQL tables. Een eenvoudig voorbeeld kan dit goed illustreren.

We hebben een simpele tabel temp_tabel met 2 kolommen: naam en woonplaats. Volgens de regels van het bedrijf moet iedere update van woonplaats worden vastgelegd in de tabel audit_tabel samen met de username en het tijdstip, bovendien moet in de tabel audit_totals worden vastgelegd hoeveel updates de user heeft vastgelegd.

We doen hierbij voor het gemak wel de aannames dat iedere USER al een record heeft in de audit tabellen en dat er geen nieuwe inserts worden gedaan in de temp_tabel.

create or replace trigger compound_test
   for update of woonplaats
   on temp_tabel
   compound trigger
     pl_totaal number;

   before statement is
   begin
       /* Hier halen we de huidige hoeveelheid inserts op */

     select totaal
       into pl_totaal
       from audit_totaal
      where gebruiker = USER;

   end before statement;
   before each row is
   begin

     /* Hier doen we niks */
     null;

   end before each row;
   after each row is
   begin

     /* Iedere wijziging van de woonplaats moet worden vastgelegd */

     insert into audit_tabel
            (naam, oude_woonplaats, nieuwe_woonplaats, gebruiker, tijdstip)
     values (:old.naam, :old.woonplaats, :new.woonplaats, USER, sysdate);

     pl_totaal := pl_totaal + 1;

   end after each row;
   after statement is
   begin

     /* Het totaal aantal wijzigingen per gebruiker wordt bijgewerkt */

     update audit_totaal
        set totaal = pl_totaal
      where gebruiker = USER;

   end after statement;
 end compound_test;
 

We beginnen met de temp_tabel in de status zoals onderstaande figuur laat zien.

Hierna doen we enkele updates op de tabel. Allereerst verhuist Michel van Nieuwegein naar Utrecht. Daarna verplaatsen we de overige mensen naar Nieuwegein. De eerste actie zal zorgen voor 1 nieuw record in de audit_tabel en een opgehoogd totaal in audit_totaal met 1. De tweede actie moet 3 nieuwe records in de audit_tabel en een ophoging met 3 opleveren tot een totaal van 4.

De eerste update vindt plaats op de temp_tabel:

Dit levert het volgende op in de audit_tabel:

En in audit_totaal:

De 3 updates zorgen voor de onderstaande gevolgen in de volgende figuren:

Nu is dit een heel eenvoudig voorbeeld, maar het toont wel aan welke uitgebreide mogelijkheden de Compound Triggers hebben.

In eerdere versies van PL/SQL zou de variabele pl_totaal opgeslagen worden in een package variabele of tijdelijke tabel tijdens het before statement, om daarna weer opgehaald en bijgewerkt te worden in het after row statement en als laatste weer opgehaald in het after statement moment om te worden vastgelegd. Het is duidelijk dat een Compound Trigger in dit soort voorbeelden veel efficiënter is.

Ordered Execution in triggers

De tweede vernieuwing in het gebruik van triggers is de Ordered Execution. Hiermee is het mogelijk om de volgorde in het geval van meerdere triggers op één timing point zelf aan te geven. In sommige gevallen is het belangrijk om bij een DML actie een aantal triggers in een bepaalde volgorde af te vuren.

De syntax is als volgt:

create or replace trigger trigger_2
 before update
 on temp_tabel
 for each row	
 follows trigger_1
 begin
 ... trigger code ... 

Dit zorgt ervoor dat trigger_2 afgaat in het before update gedeelte nadat trigger_1 klaar is.

Disabled Triggers

Een derde toevoeging bij triggers is het Disabled creëren van een trigger . Dit kan handig zijn als de programmeur een trigger wil toevoegen aan een High Availability omgeving, maar niet het risico wil lopen dat deze niet compileert door een simpele fout en zodoende de werking van een bestaande tabel verstoort, en wellicht nog veel meer.

Als een trigger als disabled wordt gebouwd, kan de programmeur eerst alle mogelijke fouten eruit halen voordat deze live wordt gezet.

create or replace trigger trigger_t
 after insert on temp_tabel
 for each row
 disable
 begin
   /* Hier de trigger code */
 end; 

Ondanks het feit dat de trigger op deze manier niet enabled is, zal hij pas compileren als er geen fouten meer in zitten.

Het CONTINUE statement

Een belangrijk element dat gek genoeg nog altijd miste in PL/SQL was de mogelijkheid om in een LOOP bepaalde situaties over te slaan. Met een if-then-else constructie was wel het een en ander te maken, maar een echt statement bestond nog niet.

Tot 11g het CONTINUE statement introduceerde. Als voorbeeld hiervan een teller van 1 tot 100 die alleen de tientallen toont:

begin
         for teller in 1..100 loop
                 continue when mod(teller,10) != 0;
                 dbms_output.put_line ('teller='||teller);
         end loop;
 end; 

De output hiervan is:

teller=10
 teller=20
 teller=30
 ... 

Loops kunnen ook een naam krijgen, waardoor het bij geneste loops zelfs mogelijk is om selectief uit een binnenste of een buitenste loop te springen.

Sequences

Voorheen was het niet mogelijk om in PL/SQL een variabele direct te vullen met de NEXTVAL van een sequence. Hiervoor moest altijd een constructie gebruikt worden met SELECT INTO FROM DUAL. Dat hoeft vanaf 11g niet meer. Hierdoor wordt de code een stuk simpeler.

Voorheen:

declare
         mijn_id number(10);
 begin
         select mijnseq.nextval
         into mijn_id
         from dual;
 end; 

Nu:

declare
         mijn_id number(10);
 begin
         mijn_id := mijnseq.nextval;
 end; 

WHEN OTHERS

Vaak maken programmeurs geen gebruik van de exception when others om onverwachte fouten afgevangen. Veelal wordt deze exception gevuld met null; en verder niets.

Oracle heeft een nieuwe warning PLW-06009 gemaakt om hiervoor te waarschuwen. De procedure zal met een null; in de when others wel compileren, maar als pl_sql_warnings aanstaat (alter session set plsql_warnings = 'enable:all') dan zal de onderstaande waarschuwing te zien zijn:

LINE/COL ERROR
 -------- -----------------------------------------------------------------
 8/7      PLW-06009: procedure "MIJNPROCEDURE" OTHERS handler does not end in
          RAISE or RAISE_APPLICATION_ERROR 

De code zal hierdoor netjes uitgevoerd worden, maar de programmeur heeft in elk geval de waarschuwing gekregen dat zijn when-others niet zal resulteren in een foutmelding aan de gebruiker.

Named Parameters in Functions

Het gebruik van Named Parameters was niet toegestaan bij Functions.

Bijvoorbeeld:

select mijnfunctie (p_parameter1=<1,p_parameter2=<1) from dual; 

Dit leverde tot en met 10g nog een error op (ORA-00907: missing right parenthesis). Vanaf 11g is het gebruik van Named Parameters bij Functions gewoon toegestaan.

Conclusie

De Oracle 11g database heeft ook in de structuur van PL/SQL een aantal verbeteringen ondergaan. Het zijn geen hele grote zaken die Oracle heeft veranderd, maar een aantal frustraties van ontwikkelaars zijn met deze versie onder handen genomen. Een goed voorbeeld daarvan zijn het toestaan van Named Parameters bij Functions, het Continue statement en het simpeler aanroepen van Sequences. Drie zaken die eigenlijk heel logisch zijn, maar tot 11g nog niet mogelijk waren.

Ook Compound Triggers en Ordered Execution zijn dingen die ik als ontwikkelaar graag zou willen gebruiken. Bij diverse projecten heb ik oplossingen gemaakt die met deze twee nieuwe mogelijkheden veel eenvoudiger en overzichtelijker zouden zijn opgelost.

Concluderend kan ik zeggen dat ik als ontwikkelaar erg blij ben met de nieuwe features in 11g PL/SQL. Het maakt het werk eenvoudiger en efficiënter.

Over de auteur

Michel van Zoest is Oracle consultant bij Whitehorses en heeft ruim 7 jaar ervaring in de IT. Hij houdt zich bezig met PL/SQL en Forms/Designer ontwikkeling en heeft zich ook gericht op integratietrajecten en Javaprojecten met ADF. Michel is tevens één van de Kapow specialisten binnen Whitehorses.

Zijn expertise heeft hij onder andere opgedaan in projecten voor klanten in de automotive industrie, de financiële wereld, het verzekeringswezen, de pensioenenbranche, logistiek, energie, marktonderzoek en bij de overheid.

Waardering:
 

Reacties

Nieuwe reactie inzenden

De inhoud van dit veld is privé en zal niet openbaar worden gemaakt.

Meer informatie over formaatmogelijkheden

CAPTCHA
Deze vraag is om te testen of u een persoon bent en om spam te voorkomen
Image CAPTCHA
Enter the characters shown in the image.