●
–
volání exit(), program ukončen, nepotvrzené akce stornovány (rollback)
Vykonání daného příkazu, typicky volání funkce, break
GOTO
Skok na dané návěstí
WHENEVER – příklady ●
Při připojování k databázi:
EXEC SQL WHENEVER SQLERROR DO sqlError(“Nelze se připojit”); ●
●
sqlError je mnou definovaná funkce na zpracováí chyby
SELECTy v cyklu (pomocí kurzoru):
EXEC SQL WHENEVER NOT FOUND DO break;
Dynamické SQL ●
Většina DB aplikací zpracovává přesně specifikovanou úlohu. –
●
SQL příkazy jsou již ve zdrojovém kódu a jsou neměnné
ALE některé aplikace dopředu neví, jaký příkaz budou posílat na server. –
Např.: Jak napsat jeden příkaz, který dle vstupu vloží nového člověka buď do tabulky Zamestnanec, či do tabulky Externista?
Dynamické SQL = dynamické Embedded SQL ●
umožňuje za běhu vytvářet a vyhodnocovat SQL příkazy.
Typické použití: ●
Nejsou-li známy v době kompilace programu některé z následujících položek: – – –
Text SQL příkazu (např. klauzule) Počet nebo datové typy hostitelských proměnných Názvy databázových objektů, např. sloupce, indexy, tabulky, pohledy...
Dynamické SQL: +/●
Výhody: – –
●
univerzálnější programy dynamické sestavení SQL příkazu na základě vstupu od uživatele nebo vstupního souboru
Nevýhody: – –
větší časové nároky na zpracování složitější kód aplikace
=> použití pouze tam, kde je to nezbytně nutné
Dynamické SQL:
Požadavky na příkazy (1) ●
Textový řetězec reprezentující příkaz – –
musí být platný SQL příkaz nesmí obsahovat: ● ● ●
EXEC SQL klauzuli ukončovač příkazu “;” ALLOCATE, CLOSE, DECLARE, DESCRIBE, EXECUTE, FETCH, FREE, GET, INCLUDE, OPEN, PREPARE, SET, WHENEVER
Dynamické SQL:
Požadavky na příkazy (2) ●
Textový řetězec reprezentující příkaz –
může obsahovat placeholdery ●
● ●
fiktivní proměnné sloužící k rezervaci místa pro skutečné hostitelské proměnné nedeklarují se libovolné jméno (v následujících dvou řetězcích není rozdíl)
'DELETE FROM Zamestnanec WHERE sefId = :sefId AND job = :job' 'DELETE FROM Zamestnanec WHERE sefId = :s AND job = :j'
Dynamické SQL:
Zpracování příkazu 1. Program si vyžádá zadání textu SQL příkazu od uživatele a hodnoty hostitelských proměnných. 2. Parsování příkazu => potvrzení validity 3. Nahrazení placeholdrů hostitelskými proměnnými –
již máme adresy proměnných => můžeme s nimi pracovat
4. Vykonání příkazu
Dynamické SQL:
4 metody použití ●
Seřazeny vzestupně dle obecnosti (flexibility) => dle náročnosti
(1) Bez návratových hodnot a hostitelských proměnných (2) Bez návratových hodnot ale se známým počtem vstupních hostitelských proměnných (3) Se známým počtem vrácených sloupců a vstupních hostitelských proměnných (4) S neznámým počtem vrácených sloupců a vstupních hostitelských proměnných
Dynamické SQL:
1. metoda ●
Omezení: –
Příkaz nesmí být typu SELECT a nesmí obsahovat žádný placeholder pro vstupní hostitelské proměnné
'DELETE FROM Zamestnanec WHERE oddeleniId = 20' ●
Syntaxe:
EXEC SQL EXECUTE IMMEDIATELY { :řetězcováProměnná | řetězcovýLiterál }
●
Příkaz je parsován vždy, když je vykonáván => pomalé
Dynamické SQL:
1. metoda – příklad char dynamickyPrikaz[100]; ... while (1) { printf(“Vlož SQL příkaz: “); gets(dynamickyPrikaz); if (*dynamickyPrikaz == '\0') break; /* dynamickyPrikaz nyní obsahuje textovou reprezentaci celého SQL příkaz */ EXEC SQL EXECUTE IMMEDIATELY :dynamickyPrikaz; }
Dynamické SQL:
2. metoda ●
Omezení: – –
Příkaz nesmí být typu SELECT. Počet placeholderů pro vstupní hostitelské proměnné a jejich datové typy musí být známy v době kompilace.
'INSERT INTO Zamestnanec (jmeno, plat) VALUES (:jmeno, :plat)'
Dynamické SQL:
2. metoda – syntaxe ●
Syntaxe:
EXEC SQL PREPARE nazevPrikazu FROM { :retezcovaPromenna, retezcovyLiteral }; EXEC SQL EXECUTE nazevPrikazu [USING seznamHostitelskychPromennych];
seznamHostitelskychPromennych ve tvaru: :promenna1[:indikator1] [, promenna2[:indikator2], ...]
Dynamické SQL:
2. metoda – příklad int idZamestnance; char textPrikazu[100], podminka[40], id[10]; ... strcpy(textPrikazu, “DELETE FROM Zamestnanec WHERE id = :n AND “); printf(“Doplňte vyhledávací podmínku následujícího příkazu\n”); printf(“%s\n”, textPrikazu); gets(podminka); strcat(textPrikazu, podminka); EXEC SQL PREPARE prikaz FROM :textPrikazu; while (1) { printf(“Vlož ID zaměstnance: “); gets(id); idZamestnance = atoi(id); EXEC SQL EXECUTE prikaz USING :idZamestnance; }
Dynamické SQL:
2. metoda – PREPARE, EXECUTE ●
PREPARE –
rozparsuje a pojmenuje příkaz ●
jméno je identifikátor pro kompilátor, není hostitelská proměnná, identifikátor či “céčková” proměnná => nedeklaruje se –
●
EXECUTE –
všechny placeholdery nahradí hostitelské proměnné z klauzule USING ●
●
stejné jako pojmenování kurzoru
musí být zachováno pořadí proměnných
PREPARE pouze jednou, EXECUTE může být vícekrát s různými hostitelskými proměnnými v části USING
Dynamické SQL:
3. metoda ●
Omezení: –
–
Počet navratových sloupců SELECTu, počet placeholderů pro vstupní hostitelské proměnné a jejich datové typy musí být známy v době kompilace. Oproti 2. metodě navíc pouze návratové sloupce
'SELECT sefId, MIN(plat), MAX(plat) FROM Zamestnanec GROUP BY sefId WHERE pozice = :pozice'
Dynamické SQL:
3. metoda – syntaxe kroků ●
Syntaxe:
EXEC SQL PREPARE nazevPrikazu FROM { :retezcovaPromenna, retezcovyLiteral };
Dále použit kurzor: EXEC SQL DECLARE jmenoKurzoru CURSOR FOR nazevPrikazu; EXEC SQL OPEN jmenoKurzoru [USING seznamHostitelskychPromennych]; EXEC SQL FETCH jmenoKurzoru INTO seznamHostitelskychPromennych; EXEC SQL CLOSE jmenoKurzoru;
Dynamické SQL:
3. metoda – příklad char textDotazu[100] = “SELECT jmeno, pozice, plat FROM Zamestnanec WHERE plat < :pl”; EXEC SQL PREPARE dotaz FROM :textDotazu; EXEC SQL DECLARE kurzorZamestnancu CURSOR FOR dotaz;
DECLARE asociuje kurzor s dotazem. EXEC SQL OPEN kurzorZamestnancu USING :platovyLimit;
OPEN nahradí placeholdery v dotazu vstupními hostitelskými proměnnými, vyhodnotí dotaz a vybere patřičné řádky. EXEC SQL FETCH kurzorZamestnancu INTO :jmeno, :pozice, :plat; EXEC SQL CLOSE kurzorZamestnancu;
Dynamické SQL:
4. metoda ●
Umožňuje použít předem neznámý počet návratových sloupců a placeholderů pro vstupní hostitelské proměnné. – –
●
Pomocí deskriptorů – –
●
SELECT bez specifikace sloupců v době kompilace EXECUTE … USING bez uvedeného listu hostitelských proměnných v době kompilace DESCRIBE SELECT LIST DESCRIBE BIND VARIABLES
Každý aktivní SQL příkaz musí mít své vlastní SQLDA.
Dynamické SQL:
SQLDA (SQL Descriptor Area) ●
●
●
●
Datová struktura, kde program a Oracle udržují kompletní popis proměnných v dynamických SQL příkazech. Obsahuje počet položek a údaje o datovém typu každé položky. Položky ze SELECTu uloženy ve výstupních proměnných, vázané (bind) proměnné ve vstupních proměnných, v SQLDA jsou jejich adresy, čímž jsou zpřístupněny Oraclu Výstupní hodnoty jsou získány FETCHem a vstupní jsou zadány programem.
Dynamické SQL:
4. metoda – průběh 1. Deklarace hostitelského řetězce pro zápis dotazu 2. Deklarace select a bind SQLDA 3. Alokace paměti pro select a bind deskriptor 4. Nastavení maximálního počtu položek v deskriptorech 5. Naplnění hostitelského řetezce 6. PREPARE příkaz FROM řetězec 7. DECLARE a kurzor FOR příkaz 8. DESCRIBE vázané proměnné INTO bind deskriptor 9. Nastavení počtu míst pro proměnné na počet nalazený pomocí DESCRIBE 10. Získání hodnoty a alokace místo pro vázané proměnné nalezené pomocí DESCRIBE 11. OPEN kurzor USING bind descriptor 12. DESCRIBE seznam select položek INTO select descriptor 13. Nastavení počtu select položek na počet nalezený pomocí DESCRIBE 14. Nastavení délky a datového typu každé select položky 15. FETCH řádky z databáze INTO alokovaný buffer, na který ukazuje select descriptor 16. Zpracování vybrané hodnoty 17. Uvolnění naalokované paměti 18. CLOSE kurzor
Dynamické SQL:
4. metoda – syntaxe kroků EXEC SQL PREPARE nazevPrikazu FROM { :retezcovaPromenna, retezcovyLiteral }; EXEC SQL DECLARE jmenoKurzoru CURSOR FOR nazevPrikazu; EXEC SQL DESCRIBE BIND VARIABLES FOR nazevPrikazu INTO nazevBindDeskriptoru; EXEC SQL OPEN jmenoKurzoru [USING DESCRIPTOR nazevBindDeskriptoru]; EXEC SQL DESCRIBE [SELECT LIST FOR] nazevPrikazu INTO nazevSelectDeskriptoru; EXEC SQL FETCH jmenoKurzoru USING DESCRIPTOR nazevSelectDeskriptoru; EXEC SQL CLOSE jmenoKurzoru;
Dynamické SQL:
4. metoda – zjednodušení ●
Pokud je znám počet míst pro vázané proměnné, je možné příkaz DESCRIBE BIND VARIABLES nahradit příkazem OPEN z 3. metody:
EXEC SQL OPEN jmenoKurzoru [USING seznamHostitelskychPromennych];
●
Pokud je znám počet select položek, pak je možné příkaz DESCRIBE SELECT LIST vynechat a nahradit ho příkazem FETCH z 3. metody:
EXEC SQL FETCH jmenoKurzoru INTO seznamHostitelskychPromennych;
Dynamické SQL:
Jakou metodu použít?
Zdroje [1] Pro*C/C++ Precompiler Programmer's Guide, Release 9.2 Oracle Corporation, ©1996-2002, použité kapitoly: –
Kapitola 1, Introduction
http://download.oracle.com/docs/cd/B10500_01/appdev.920/a97269/pc_01int.htm
–
Kapitola 6, Embedded SQL http://download.oracle.com/docs/cd/B10500_01/appdev.920/a97269/pc_06sql.htm
–
Kapitola 13, Oracle Dynamic SQL
http://download.oracle.com/docs/cd/B10500_01/appdev.920/a97269/pc_13dyn.htm
[2] Semináře RNDr. Michala Kopeckého, Ph. D.: Administrace Oracle [3] Wikipedia, http://www.wikipedia.org/
Dotazy