02 PL/pgSQL
Obsah článku:
- 1. PL/pgSQL
- 1.1. Doporučenia pre návrh vložených procedúr v jazyku PL/pgSQL
- 1.2. Inštalácia PL/pgSQL
- 1.3. Štruktúra funkcie v PL/pgSQL
- 1.4. Príklad funkcie v PL/pgSQL
- 1.5. Komentáre v PL/pgSQL
- 1.6. Deklarácia premenných v PL/pgSQL
- 1.7. Deklarácia parametrov funkcie
- 1.8. Deklarácia atribútu %TYPE
- 1.9. Údajový typ záznam a riadok tabuľky
- 1.10. Výrazy
- 1.11. Príkaz priradenia
- 1.12. Zavolanie funkcie a jej návratová hodnota
- 1.13. Výraz RETURN
- 1.14. Chyby a výnimky
- 1.15. Vetvenie programu a cykly
- 1.16. IF-THEN
- 1.17. IF-THEN-ELSE
- 1.18. IF-THEN-ELSIF
- 1.19. CASE
- 1.20. Cyklus LOOP
- 1.21. Cyklus WHILE
- 1.22. Cyklus FOR
- 1.23. Zdroje:
PL/pgSQL
V PostgreSQL môžeme PL/pgSQL použiť k implementácií vlastných agregačných aj normálnych funkcií, operátorov, k implementácií procedúr, triggerov. Autori PL/pgSQL sa zjavne inšpirovali staršími verziami programovacieho jazyka PL/SQL, čo je jazyk pre vývoj uložených procedúr firmy Oracle. Nie je tak príliš náročné konvertovať vložené procedúry z ORACLE do PostgreSQL a naopak. PL/SQL je veľmi osekaná ADA rozšírená o SQL. Syntax PL/pgSQL a PL/SQL je veľmi podobná – zásadne sa líši implementácia. PL/pgSQL je veľmi jednoduchý interpret abstraktného syntaktického stromu, ktorý beží v rovnakom procese, v ktorom prebieha spracovanie SQL príkazu. Procedúry PL/SQL bežia vo svojom vlastnom procese, pričom PL/SQL je prekladané do strojového kódu. Každý prístup má svoje výhody a nevýhody – a má samozrejme aj inú motiváciu a iné historické pozadie. PL/pgSQL je úzko integrovaný s PostgreSQL – má zanedbateľnú réžiu, pre prístup k dátam nie je nutné používať interprocess(medzi procesmi) komunikáciu, jednoducho sa udržuje, jednoducho sa rozširuje, jednoducho sa učí. Silou PL/SQL je jeho bohatosť a fakt, že je prekladaný do strojového kódu. Predsa len PL/SQL je menej osekaná ADA než PL/pgSQL a aj vďaka tomu je univerzálnejší než PL/pgSQL a taktiež náročnejší na naučenie. PL/pgSQL je založený na jednoduchom prekladači (interpreter) – tak jednoduchom, že neimplementuje ani základné aritmetické a logické operácie – každý výraz sa prevádza na SELECT, ktorý spracováva executor. PL/pgSQL obsahuje iba implementáciu premenných a riadiace konštrukcie (IF, LOOP, RETURN, :=, ..). Našťastie jednoduchšie dotazy, ktoré odpovedajú výrazom – t. j. neobsahujú odkaz na tabuľky, dokáže interpret PL/pgSQL spúšťať rádovo efektívnejšie než typické dotazy – t. j. dotazy do tabuliek. Z tejto implementácie vychádza aj efektívne použitie PL/pgSQL. Je to úžasné lepidlo pre SQL príkazy. Na druhú stranu, PL/pgSQL sa vôbec nehodí pre numerické úlohy, ktoré vyžadujú veľký počet aritmetických operácií. PL/pgSQL sa nehodí pre náročnejšie operácie, kde se intenzívne modifikujú reťazce alebo polia. Každá úprava reťazca alebo poľa znamená vytvorenie upravenej kópie pôvodných dát, ktorou sú pôvodné dáta nahradené. Tento prístup je v prípade väčšieho objemu alebo väčšieho počtu operácií neefektívny.
V PL/pgSQL sa spojili dva programovacie jazyky – dva interpretované programovacie jazyky – PL/pgSQL a SQL. Pri prvom použití funkcie (v rámci session) sa kód PL/pgSQL prevedie do syntaktického stromu (Abstract Syntax Tree), pri prvom použití SQL príkazu sa generuje prevádzací plán SQL príkazu. Parser PL/pgSQL (rovnako ako PostgreSQL) je postavený nad GNU Bisonom. Získaný syntaktický strom a vytvorené spúšťajúce plány sa používajú opakovane pokiaľ nedôjde k zmene kódu funkcie alebo k ukončení session.
Doporučenia pre návrh vložených procedúr v jazyku PL/pgSQL
Na internete je možné nájsť mnoho doporučení pre písanie vložených procedúr v PL/SQL firmy Oracle. Implementácia PL/pgSQL je iná a totiž nie všetky doporučenia sú relevantné pre PostgreSQL. V PL, rovnako ako v iných programovacích jazykoch, je možné napísať nečitateľný a zle udržiavateľný, poprípade neefektívny kód. Riziko, že Váš kód bude nevyhovujúci, znížime, pokiaľ sa budeme držať následujúcich doporučení:
- Kód píšeme v klasickom (programátorskom) editore a ukladáme do súboru. V súboroch môžeme lepšie udržovať komentáre, môžeme združovať funkčne blízke alebo závislé funkcie, môžeme verziovať kód. Odporúča sa nepoužívať nástroje ako je pgAdmin alebo phpPgAdmin.
- Existujú aj špeciálne IDE pre prácu s databázami napr. DataGrip od firmy JetBrains, či PgExplorer pre platformu Windows.
- Namiesto nástroja psql je tiež možné použiť PGCLI. Oproti psql má tento nástroj pomocné funkcie ako Auto Completion alebo zvýrazňovač syntaxe naviac, podporuje viacriadkové príkazy a inteligentnú históriu. Nástroj je naprogramovaný v jazyku Python.
- Je potrebné sa brániť pred kolíziou lokálnych premenných a databázových objektov:
- použitím prefixov premenných (napr. pre lokálne premenné symbol “_”)
- použitím kvalifikovaných atribútov (tabulka.stlpec) vo všetkých SQL príkazoch v procedúrach
- Premenné sa deklarujú pomocou odvodených typov - %TYPE a %ROWTYPE
V PL je potrebné používať natívne SQL všade, kde je to možné a rozumné. Pokiaľ by sa naskytla potreba príliš komplikovaného dotazu, je možné, že PL kód bude rýchlejší. Je lepšie nepoužívať dynamické SQL. Častokrát je lepšie cyklus vo funkcií nahradiť klasickým SELECTom obsahujúcim konštrukciu CASE.
123456789101112131415161718192021222324252627282930313233343536373839-- neefektívny kódIF _cena <= _cena_max THENINSERT INTO tab(id, cena) VALUES(_id, _cena);ELSEINSERT INTO tab(id, cena)VALUES(_id, _cena_max);END IF;-- efektívny kódINSERT INTO tab(id, cena)VALUES(_id, CASE WHEN _cena <= _cena_maxTHEN _cena ELSE _cena_max END);-- neefektívny kódFOR _c1, _c2 IN SELECT c1,c2 FROM tab1 LOOPIF _c1 > 20 THENINSERT INTO tab2 VALUES(20,_c2);ELSEINSERT INTO tab3 VALUES(_c1,_c2);END IF;END LOOP;-- efektívny kódINSERT INTO tab2SELECT 20,c2 FROM tab1 WHERE c1 > 20;INSERT INTO tab3SELECT c1,c2 FROM tab1 WHERE c1 <= 20;-- neefektívny kódFOR i IN array_lower(delitems,1) ..array_upper(delitems,1)LOOPDELETE FROM tabWHERE tab.id = delitems[i];END LOOP;-- efektívny kódDELETE FROM tabWHERE tab.id = ANY(delitems);Funkcia má obsahovať iba jeden príkaz RETURN - jedna cesta dovnútra, jedna cesta von.
- Vyhýbať sa redundantnému kódu - v aplikácií by sa nemal objaviť dvakrát rovnaký kód.
Je potrebné využívať funkciu Assert, prípadne jej modifikácie:
123456789101112131415161718CREATE OR REPLACE FUNCTION Assert(bool, varchar) RETURNS void AS $$BEGINIF NOT $1 OR $1 IS NULL THENIF $2 IS NOT NULL THENRAISE EXCEPTION'Assert failure: %', $2;END IF;RAISE NOTICE 'Assert. Message is null';END IF;END;$$ LANGUAGE plpgsql;CREATE OR REPLACE FUNCTION Assert_IsNotNull(anyelement, varchar)RETURNS void AS $$BEGINPERFORM Assert($1 IS NOT NULL, $2);END;$$ LANGUAGE plpgsql;Treba dodržiavať predom dohodnuté notácie pre texty výnimiek, dopredu sa dohodnúť na zozname užívateľom definovaných chyb a chybových hlásení.
- Netestovať na NULL premennú, ktorá je deklarovaná ako NOT NULL. Je na PL, aby zaistil, že tato premenná v žiadnom prípade nebude obsahovať NULL. Pre zaistenie úspešnosti dotazu netestujeme obsah premenných modifikovaných dotazom, ale vždy obsah logickej systémovej premennej FOUND.
- Nepoužívať návestie <
- Nespoliehať sa na automatické konverzie typu date a timestamp, ktoré závisia od konfigurácie. Je lepšie použiť funkcie to_char a to_date.
- Nepoužiť IF pre naplnenie logickej premennej:
is_ok := _age > 18;
- Každú premennú treba použiť iba k jednému jasnému účelu. Z kódu treba odstrániť nepoužívané premenné.
- Predvolená kategória funkcie je VOLATILE. Pokiaľ v tele funkcie nepristupujete k tabuľkám a nepoužívame funkcie typu random(), currval() atď, je lepšie použiť kategórie IMMUTABLE alebo STABLE. Doba spracovania funkcie môže byť aj o polovicu kratšia.
- Nezapuzdrovať SQL príkazy do jednoduchých funkcií.
- Obmedzovať použitie kurzorov a dočasných tabuliek.
- Je odporúčané preferovať štandardizované funkcie pred vlastnými.
- V triggeroch “tajne” neopravujeme dáta, treba posúdiť, či nebude lepšie použiť CHECK.
- Každá procedúra by mala obsahovať maximálne 50 až 60 riadkov.
- K testovaniu použiť unit testy (k overeniu identifikácie chyby, k overeniu korektnosti opravy)
- Zapuzdriť vyvolanie výnimky do vlastnej procedúry.
- Vždy vo svojom kóde použiť iba jeden z dvoch možných spôsobov (výnimky a návratový kód) signalizácie chyby.
Opakované priradenie do premennej (u typov varchar a array) zlúčiť do jedného výrazu.
12345678910111213141516171819202122232425262728293031323334--zleDECLARE v varchar;BEGINv := 'a';v := v || 'b';v := v || 'c';RETURN v;END;--dobreBEGINRETURN 'a' || 'b' || 'c';END;-- zleDECLARE s varchar := '';BEGINIF x1 IS NULL THENs := s || 'NULL,'ELSEs := s || x1;END IF;IF x2 IS NULL THENs := s || 'NULL, 'ELSEs := s || x2;END IF;...-- správneDECLARE s varchar;BEGINs := COALESCE(x1 || ',', 'NULL,')|| COALESCE(x2 || ',', 'NULL,')Funkcie obsahujúce iba jeden príkaz nepísať v PL/pgSQL, ale v SQL:
12345678910111213--zleCREATE OR REPLACE FUNCTION foo()RETURNS varchar AS $$BEGINRETURN 'a' || 'b' || 'c';END;$$ LANGUAGE plpgsql IMMUTABLE;--dobreCREATE OR REPLACE FUNCTION foo()RETURNS varchar AS $$SELECT 'a' || 'b' || 'c';$$ LANGUAGE sql;
Inštalácia PL/pgSQL
re používanie PL jazykov sa musíme uistiť, či ich máme nainštalované. PostgreSQL podporuje veľa PL jazykov a sľubuje bezproblémový proces ich inštalácie.
Pre inštaláciu PL/pgSQL, stačí spustiť nástroj príkazového riadka a spustiť príkaz:
PL/pgSQL je však už predvolene nainštalovaný v každej aj novo vytvorenej databáze. Spustenie príkazu vyššie, by malo iba vypísať že PL jazyk už je nainštalovaný.
Predpokladajme, že chceme nainštalovať tento jazyk do testovacej databázy z názvom – test_db. Spustíme teda príkaz (v príklade použitý Linux shell):
Tento príkaz však predpokladá, že užívateľ operačného systému je rovnaký ako super užívateľ (SuperUser) danej databázy. Pokiaľ nie je, musíme zadať meno super užívateľa databázy za prepínač -U. Príklad:
Štruktúra funkcie v PL/pgSQL
PL/pgSQL má blokovú štruktúru a ide o jazyk citlivý na veľké a malé písmena (ang. case sensitive). Blok obsahuje príkazy vo vnútri kľúčových slov DECLARE /BEGIN a END
Blok môže byť definovaný, následovne:
Autori popisujú PL ako jazyky blokovo orientované (všetky príkazy sú v nejakom bloku, bloky je možné do seba ľubovoľne vnárať). Blok má zmysel hlavne pri deklarovaní lokálnych premenných. Bloky sa na rozdiel od Pascalu, nepoužívajú k vymedzeniu zoznamu príkazov v konštrukciách IF, WHILE, FOR, LOOP, ale iba k vymedzeniu existencie niektorých lokálnych premenných. Nakoľko bloky hrajú veľkú rolu pri funkciách, máme dostatočné poznatky na vytvorenie funkcie. Začneme teda rozkladať štruktúru funkcie a popisovať element za elementom.
Príkaz CREATE FUNCTION používame práve pre vytvorenie funkcií. Ako prvé treba definovať meno funkcie. Ďalej definujeme jej argumenty, návratovú hodnotu a v poslednom rade sekciu deklarácií. Syntax funkcie:
Od verzie 7.2.1 môžeme použiť frázu CREATE OR REPLACE. V predchádzajúcich verziách sa musela funkcia pred jej opakovaným vytvorením daná funkcia zrušiť príkazom DROP FUNCTION. Pretože je možné funkcie preťažovať, musí sa príkazu DROP FUNCTION predať nie len názov funkcie, ale aj typy argumentov, aby podľa nich mohol PostgreSQL jednoznačne identifikovať správnu verziu funkcie k zmazaniu. Samozrejme funkciu je možné odstrániť iba pokiaľ na to máme práva. Môžeme zmazať iba užívateľské funkcie (user defined functions), teda funkcie vytvorené pomocou CREATE FUNCTION, nemažeme interné funkcie PostgreSQL. Od verzie 7.3 môžeme určiť, s akými oprávneniami sa bude funkcia vykonávať. Funkcia získa buď práva užívateľa, ktorý funkciu spúšťa (EXTERNAL SECURITY INVOKER), alebo práva vlastníka funkcie (EXTERNAL SECURITY DEFINER). Čiže volajúci – SECURITY INVOKER vlastník – SECURITY DEFINER. Pričom predvolená hodnota každej novo vytvorenej funkcie je SECURITY DEFINER. Kľúčové slovo EXTERNAL je nepovinné.
Vo vnútri bloku, deklarujeme premenné a je možné nastaviť aj predvolenú hodnotu.
Blokovú sekciu identifikujeme pomocou kľúčového slova DECLARE. Sekcia sa skladá z mena premennej, údajového typu a končí bodkočiarkou. Každá premenná, riadok alebo záznam použitý vo vnútri bloku, by mala byť deklarovaná v tejto sekcií, výnimkou je cyklus FOR.
Čo možno znázorniť nasledujúcim spôsobom:
Po definovaní mena funkcie, jej návratového typu a deklarácií premenných, sa zameriame na telo funkcie s kľúčovým slovom BEGIN.
Jeho syntax je:
Sekcia príkazov, môže obsahovať nekonečno pod blokov. Vnorený kód bloku, prečíta interpreter ako obyčajný blok a metóda jeho zápisu je rovnaká ako pri bežnom PL/pgSQL bloku. Inak povedané, sekcia začína slovom DECLARE, nasleduje slovo BEGIN a príkazy vo vnútri tela ukončuje kľúčové slovo END. Je potrebné si zapamätať že BEGIN / END, nespúšťa a ani neukončuje akúkoľvek transakciu, ale slúži na zoskupenie príkazov.
Kľúčové slovo END ukončuje blok kódu:
Hlavné telo PL/pgSQL funkcie, by malo vracať hodnotu predom definovaného typu a všetky pod bloky musia byť riadne uzavreté ešte pred ukončením hlavného bloku.
Príklad funkcie v PL/pgSQL
Vytvoríme si novú databázu:
Jednoduchú skúšobnú tabuľku:
Vložíme dáta do tabuľky:
Túto databázu budeme používať na väčšinu príkladov v teoretickej časti tejto práce.
Vytvoríme funkciu pocetZaznamov(), ktorá vráti počet zapísaných záznamov do tabuľky tst_tabulka v databáze teoria_tst.
Po úspešnom vytvorení, funkciu zavoláme, načo sa vypíše jej návratová hodnota.
Po pridaní ďalšieho testovacieho riadku do tabuľky, funkcia samozrejme vráti číslo dva a podobne. Takýmto spôsobom vytvárame funkcie v PL/pgSQL.
Komentáre v PL/pgSQL
Pre prehľadnosť kódu je odporúčané používať komentáre, tie je možné používať v PL, tak ako aj v ostatných programovacích jazykoch. Na výber je jednoriadkový komentár a komentár obsahujúci viacero riadkov.
Nasledujúci príklad funkcie v PL/pgSQL, ukazuje použitie komentárov vo vnútri funkcie. Pričom je vidieť, že komentáre zvyšujú prehľadnosť a hlavne čitateľnosť kódu.
Použitie funkcie:
Deklarácia premenných v PL/pgSQL
Premenné slúžia na ukladanie dát, aj PL/pgSQL umožňuje použitie premenných. Každá premenná je použiteľná počas doby života bloku, a musí byt deklarovaná vo vnútri bloku DECLARE. Od verzie PostgreSQL 9.0, nemôže názov premennej byť zároveň kľúčovým slovom v SQL pravdepodobne dôjde k zobrazeniu syntaktickej chyby. V predchádzajúcich verziách sa ako identifikátory premenných nemohli použiť iba kľúčové slová v PL/pgSQL. PostgreSQL čoby databáza nepozná koncept premennej, prípadne lokálnej premennej. Všetká práca s premennými je implementovaná v runtime PL/pgSQL. Každá funkcia získa pri štarte stavovú premennú, ktorá okrem iného obsahuje aj vektor všetkých premenných. Premenné sa očíslujú indexom v tomto vektore - a neskôr pri ich použití sa kopírujú do vektoru parametrov SQL príkazu.
Použitie premenných si ukážeme na kóde z funkcie pocetZaznamov():
Pričom vidíme, že pri deklarácií premennej pocet je zvolený údajový typ INTEGER. Čo znamená, že táto premenná dokáže uložiť iba dáta celočíselného typu.
Syntax deklarácie premenných:
Pridanie premennej s kľúčovým slovom CONSTANT, zabezpečí, že hodnota tejto premennej bude konštantná behom spustenia bloku. Slovo COLLATE reprezentuje pravidlá pre usporiadanie reťazcov. Dáta v konkrétnom stĺpci je možné radiť raz podľa slovenských pravidiel COLLATE “sk_sk.utf8”, a druhý raz podľa iných pravidiel (COLLATE “en_US.utf8”). Premenné je možne deklarovať s prednastavenou hodnotou. Pokiaľ táto hodnota nie je nastavená, premennej sa priradí hodnota NULL. Hodnotu je možné nastaviť už v časti DECLARE, pomocou operátora priradenia „ := “. NOT NULL používame v prípade, keď nechceme nastaviť predvolenú hodnotu premennej na NULL. V praxi sa osvedčilo takýmto premenným vždy priradiť hodnotu už pri deklarácií.
Do budúcna je dobré si zapamätať, že zakaždým spustením bloku sú vyhodnotené a priradené prednastavené hodnoty premennej. Funkcia func_deklaracia() v nasledujúcej ukážke poukazuje ako zadefinovať konštantu s predvolenou hodnotou „10“. V ukážke tiež vidíme ako deklarovať premennú s NOT NULL a textovú premennú ,do ktorej priradíme hodnotu. 1
Výpis funkcie:
Deklarácia parametrov funkcie
Funkcie dokážu prijímať a vracať hodnoty, tieto hodnoty v programovaní nazývame parametre funkcie, či argumenty. Argumenty musia byť deklarované pred ich použitím. Parametre funkcie sú označené numerickým identifikátorom $1 a $2. Tieto symboly $1 a $2 sa používajú vo význame hodnoty prvého a druhého argumentu funkcie. Pre prístup k referenčným hodnotám parametrov, použijeme numerický identifikátor alebo použijeme ALIAS (ang. Prezývka). 1
Prezývku – ALIAS priradíme parametru, následujúcim spôsobom:
Použitie v príklade:
Bežne však definujeme meno parametra už v príkaze CREATE FUNCTION:
Funkcia po jej použití, vráti:
Parametru funkcie je možné nastaviť aj typ. Poznáme tri typy parametrov: IN, OUT, INOUT. Funkcia deklarovaná s parametrom typu IN obsahuje hodnotu, ktorá bude odovzdaná funkcií. Pokiaľ nedeklarujeme typ parametra, bude ním predvolene IN. Typ OUT sa vráti ako výsledok funkcie. Obe typy sú efektívne, pokiaľ má funkcia vrátiť viacero výstupov bez deklarácie výstupu typu PostgreSQL. Parameter typu INOUT slúži obom spomínaným účelom. Ide teda parameter pre vstup a aj výstup funkcie. 2
Následujúca funkcia používa IN a OUT parametre:
Použitie funkcie:
Deklarácia atribútu %TYPE
Atribút %TYPE používame pri ukladaní hodnôt z databázového objektu, zvyčajne stĺpca tabuľky. Premenná s týmto atribútom ukladá hodnotu rovnakého údajového typu ako tá, na ktorú odkazuje. Čo je nápomocné hlavne pri budúcej zmene údajového typu stĺpca.
Deklarácia:
Naša databáza teoria_tst obsahuje stĺpec rok_narodenia v tabuľke tst_tabulka. Premennú odkazujúcu na tento stĺpec deklarujeme, takto:
Údajový typ záznam a riadok tabuľky
Premenná typu riadok sa deklaruje na používateľom definovanej tabuľke alebo pohľade použitím príkazu meno_tabulky%ROWTYPE. K jednotlivým riadkom je možné pristupovať bodkovou notáciou, napríklad – riadok.pole . Premenná deklarovaná ako typ ROWTYPE dokáže uložiť riadok z výsledku dotazu SELECT alebo FOR. Typ záznam (RECORD) je podobný ROWTYPE s výnimkou, že nemá žiadnu preddefinovanú štruktúru a dokáže akceptovať riadky z ktorejkoľvek tabuľky. Čo znamená, že je možné zmeniť štruktúru za každým pripojením na riadok. Ide o konštrukciu pre iteráciu naprieč množinou záznamov špecifikovanou príkazom SELECT či FOR.
Výrazy
Výrazy používame v procedurálnom programovaní kedykoľvek chceme priradiť hodnotu k premennej, zavolať funkciu alebo použiť podmienený výraz ako je IF a ELSE. Poradie spustenia výrazov, kontrolujeme ich organizáciou. Každý výraz je zakončený bodkočiarkou.
Príkaz priradenia
Ide o najčastejšie používaný príkaz. Priraďujeme nim premenenej svoju hodnotu.
Syntax príkazu:
Kde , cieľ môže byt čokoľvek, premenná, stĺpec, parameter funkcie, riadok, ale nie konštanta. Počas spustenia, sa zo všetkých operácii prednostne priradia hodnoty do premenných. Pokiaľ sa typ premennej a hodnota nezhodujú, PostgreSQL sa hodnotu pokúsi konvertovať alebo vypíše chybu.
Zavolanie funkcie a jej návratová hodnota
Všetky PostgreSQL funkcie vracajú hodnotu. Vytvorenú funkciu spustíme jednoducho príkazom SELECT.
Niekoľko názorných príkladov:
The SELECT identifikator_funkcie() fukcia:
1SELECT identifikator(argumenty);Priradenie prednastavenej hodnoty funkcií identifikator_funkcie():
1identifikator_premennej:=identifikator(argumenty);Príkaz SELECT a AVG(riadok) funkcia:
1SELECT AVG(tst_id) FROM tst_tabulka;Príkaz SELECT a funkcia pocetZaznamov():
1SELECT pocetZaznamov();
Výraz RETURN
Pokiaľ funkcia úspešne skončí, vyhodnotí sa hodnota výrazu, ktorá bude mať návratovú hodnotu a to takého typu ako je špecifikované v príkaze CREATE FUNCTION.
Syntax príkazu RETURN je nasledujúca:
Chyby a výnimky
Pokiaľ dôjde k chybe v syntaxe alebo výnimke, beh programu skončí chybovým hlásením. Vyvolané výnimky je však možné zachytiť. Pre odchyt takejto výnimky implementujeme do funkcie programu príkaz RAISE.
Prvým argumentom príkazu RAISE je úroveň výnimky. K dispozícii sú tri možnosti: DEBUG – zapíše sa do logu, NOTICE – oznámi sa užívateľovi, EXCEPTION – preruší sa vykonávanie funkcie. Druhým parametrom je text chybového hlásenia (text zapisujeme medzi zdvojené apostrofy). Pokiaľ sa v texte objaví symbol %, potom sa tento symbol nahradí odpovedajúcou premennou, ktorá se predá ako tretí, štvrtý, atď. argument. V PL/pgSQL nie je možné zachytiť výnimku, t. j. každá výnimka na úrovni EXCEPTION vedie k prerušeniu chodu funkcie. RAISE NOTICE sa bežne používa pre zobrazenie ladiacich hlásení, zobrazeniu obsahu premenných. V podstate je to jediný ladiaci prostriedok, ktorý je k dispozícii. RAISE DEBUG prepošle špecifikovaný text ako odlaďovaciu správu do PostgreSQL logu a klientského programu, pokiaľ je klient pripojený do databázového clustra so spustením módu debug. DEBUG je v produkčnom móde ignorovaný. RAISE EXCEPTION pošle špecifický text ako správu o chybe klientskému programu a PostreSQL logu. Tiež prerušuje prebiehajúci chod funkcie. 1
Výsledok po spustení funkcie:
Výstup DEBUG sa nezobrazil, pretože databáza neprebieha v mode debuging.
Lepším príkladom pre RAISE EXCEPTION bude následujúci príklad, ktorý kontroluje správnosť poštového smerovacie čísla.
Každej výnimke môžeme priradiť špeciálnu ERRCODE hodnotu. Jej horná hranica je P9999, hodnota symbolizuje typ danej chyby. Ide o veľmi zjednodušený postup a je odporúčané neprekrývať chybové kódy definované v PL/pgSQL(napr. P0001).
Následujúci príklad funkcie zachytáva chyby, vytvorené v predchádzajúcej funkcii:
Výsledok funkcie:
Vetvenie programu a cykly
Štruktúra podmienených výrazov a cyklov obsahuje príkazy, ktoré sa vykonajú po splnení podmienky.
Syntax pre podmienené výrazy:
Syntax pre príkaz cyklu:
IF-THEN
Najjednoduchšia forma podmieneného výrazu. Syntax príkazu IF-THEN:
Spustenie príkazov medzi blokom THEN a END závisí od splnenia booleovskej podmienky. Pokiaľ sa teda podmienka splní, pričom jej hodnota bude TRUE, príkazy sa vykonajú. Inak bude blok kódu ignorovaný.
Nasledujúci príklad, poukazuje na jeden z mnohých prípadov použitia IF-THEN:
IF-THEN-ELSE
V niektorých situáciách je potrebné zdôrazniť, ktoré príkazy se majú spustiť v prípade, že podmienka nie je splnená. V takom prípade pridáme sekciu ELSE (inak). Táto sekcia je nepovinná a nachádza sa vždy na konci výrazu IF. 1 Syntax je následujúca:
Modifikujeme funkciu pocetZaznamov(), a použijeme blok IF-THEN-ELSE.
Spustenie funkcie:
IF-THEN-ELSIF
Niektoré prípady vyžadujú viac ako dve vetvy programu, vtedy použijeme IF-THEN-ELSIF. Pokiaľ sa podmienka IF nesplní, príkazy sa ignorujú a vyhodnotí sa podmienený výraz ELSIF. Pokiaľ je pravdivý, spustia sa príkazy vo vnútri bloku.
Príkaz ELSIF najlepšie pochopíme použitím v príklade:
Výsledok pri dosiahnutí 33 bodov z testu:
Výsledok pri dosiahnutí 32 bodov z testu:
Výsledok pri dosiahnutí 34 bodov z testu:
Výsledok pokiaľ sa žiak nezúčastnil na teste:
CASE
Direktíva vždy začína kľúčovým slovom CASE, vždy končí kľúčovým slovom END a vždy má aspoň jednu WHEN-THEN časť. Podmienka CONDITION sa vyhodnotí ako booleovský výraz (pravda alebo nepravda). Pokiaľ je pravda, výsledkom celého CASE je vyraz. Pokiaľ je nepravda, skúsi sa to v ďalšej WHEN-THEN časti. Pokiaľ nie je splnená žiadna CONDITION, výsledkom je výraz za ELSE. Pokiaľ nie je ELSE vyraz definovaný, tak už ostáva ako výsledok iba NULL.1
Syntax:
Vytvoríme novú funkciu, ktorá obsahuje direktívu CASE:
Výsledok pri dosiahnutí 30 bodov z testu:
Výsledok pri dosiahnutí 30 bodov z testu:
Cyklus LOOP
Zrejme nemôže existovať programovací jazyk bez konštrukcií cyklu. PL/pgSQL nie je výnimkou, obsahuje dokonca štyri rôzne konštrukcie: cyklus FOR IN interval pre prevedenie predom známeho počtu cyklov, cyklus FOR IN SELECT pre iteráciu cez všetky riadky výsledku SQL dotazu, a cykly LOOP a WHILE pre prevedenie dopredu neznámeho počtu iterácií príkazov. Prevedenie cyklu môžeme v všetkých štyroch prípadoch prerušiť príkazom EXIT [návestie][WHEN logický_výraz].
Syntax:
Cyklus implementujeme do novej PL/pgSQL funkcie, ktorá žiada číslo ako vstupný parameter. Toto číslo budeme v cykle násobiť známkou 10. Cyklus bude bežať pokiaľ hodnota známky nebude rovná alebo väčšia ako 100. 1
Spustenie a výsledok funkcie:
Cyklus WHILE
Cyklus WHILE-END WHILE zaistí opakované spúšťanie bloku SQL príkazov v prípade, že zadaný výraz je pravdivý. V prípade, že výraz je neplatný už pri zahájení príkazu, telo cyklu sa nespustí ani raz. Tento cyklus je podobný cyklu REPEAT-UNTIL, ktorý zaistí minimálne jedno vyhodnotenie tela cyklu.
Syntax:
Ukážka obsahuje funkciu pre výpočet faktoriálu:
Spustenie funkcie:
Cyklus FOR
Ide o najčastejšie používaný druh cyklu. Tento druh cyklu pracuje vo vopred danom rozsahu hodnoty typu integer. Premennú s touto hodnotou nemusíme deklarovať v bloku DECLARE. Životnosť takejto premennej zaniká ukončením cyklu FOR. Verzia PostgreSQL 9.1 bola rozšírená o cyklus FOREACH – iteráciu nad poľom s možnosťou iterácií po riadkoch. 1
Syntax cyklu FOR:
Použitie cyklu FOR:
Spustenie funkcie:
Cyklus FOR je možné použiť spolu s DML (Data Manipulation Language) príkazom SELECT a to pomocou kľúčového slova EXECUTE.
Po spustení funkcie spolu s SELECT dotazom ako parametrom funkcie. Bude výsledok takejto funkcie počet riadkov v tabuľke.
Zdroje:
https://www.root.cz/clanky/efektivni-pouzivani-pl-pgsql/
http://postgres.cz/wiki/PL/pgSQL;