Databázové systémy 9. přednáška
Procedury Jsou pojmenovaným blokem PL/SQL kódu (i posloupnost SQL příkazů ohraničena BEGIN END je PL/SQL kód) Založí se příkazem CREATE OR REPLACE PROCEDURE jméno (parametry) AS pl/sql kód Nesmíte zapomenout, že PL/SQL kód končí středníkem (BEGIN END;)
Parametry procedur Existují tři typy parametrů: Vstupní (znáte jako tzv. volané hodnotou) Výstupní (nemají odraz v běžných jazycích) vstupně výstupní (tzv. volané odkazem) Rozlišují se modifikátorem mezi jménem a typem parametru (IN, OUT, IN OUT) Implicitně platí IN Druhý modifikátor NOCOPY způsobí okamžitou viditelnost změn OUT parametrů
Oprávnění procedur Existují dva typy procedur: tzv. invoker-rights (pracují pod právy volajícího toho, kdo proceduru spustil) tzv. definer-rights (pracují pod právy toho, kdo procedur definoval implicitní model) Rozlišení se provádí po definici parametrů jako klauzule AUTHID model Modely: CURRENT_USER, DEFINER
Dodatky k procedurám Při definici PL/SQL kódu v proceduře se obvykle neuvádí klauzule DECLARE, proměnné je možné deklarovat přímo po specifikaci AS Místo AS lze užít také IS (synonymum) Vyvolává se buď pomocí anonymního PL/SQL kódu nebo příkazem EXECUTE jméno (skutečné parametry);
Výstup informací z procedury Pomocí výstupních a vstupně výstupních parametrů Existuje balík funkcí DBMS_OUTPUT umožňující výstup informací do konzole Výstupní příkazy DBMS_OUTPUT.PUT(řetězec); DBMS_OUTPUT.PUT_LINE(řetězec);
Úkol 1 Vytvořte proceduru, která změní minimální plat na hodnotu předanou parametrem všem pracovním pozicím, které mají minimální plat nižší než je tato částka, avšak minimální plat nesmí být vyšší než maximální. V případě, že nebude provedena žádná změna vyvolejte vlastní chybovou hlášku s číslem -20017. V případě, že nějaká změna proběhne, v rámci procedury se vypíše počet ovlivněných záznamů. Proceduru volejte z nepojmenovaného bloku a případnou výjimku zpracujte v části EXCEPTION.
Uživatelské funkce Vytváří se obdobně jako PL/SQL procedury Funkce vrací skalární hodnotu Lze je volat z SQL i z PL/SQL Není možné směrovat výstup do DBMS_OUTPUT výstupního bufferu Nelze provádět DML a DDL operace Nelze použít příkazy COMMIT a ROLLBACK Při volaní v SQL nelze užít OUT a IN OUT parametry
Funkce odlišnosti od procedur Odlišné klíčové slovo FUNCTION Výsledek funkce je hodnota specifikuje se jako klauzule RETURN typ za závorkou s definicí parametrů Hodnotu je třeba vrátit pomocí příkazu RETURN hodnota;
Vytvoření funkce
Úkol 2 Vytvořte funkci faktoriál, která vrátí hodnotu faktoriálu nezáporného celého čísla. Bude-li zadáno záporné číslo, vyhodí funkce výjimky -20584: Záporné číslo. Bude-li zadáno desetinné číslo funkce vyhodí výjimku -20585: Desetinné číslo.
Použití return Návratovou hodnotu lze přiřadit i v části výjimek
Úkol 3 Přepracujte předchozí funkci tak, aby v případě špatného vstupu vrátila hodnotu NULL.
Deterministické funkce Označením jako DETERMINISTIC (po klauzuli RETURN typ) lze funkci prohlásit za deterministickou Taková funkce pro stejné parametry vrací stejný výsledek Pouze takovéto funkce, mohou být součástí indexů Z deterministických funkcí nelze volat nedeterministické funkce.
Otázka Kdy může být funkce nedeterministická? Uveďte prosím nějaký příklad deterministické a nedeterministické funkce z běžně využívaných funkcí poskytovaných databázovým systémem.
Uživatelské agregované funkce Jednoparametrové funkce pracující nad více řádky dotazu (a vracející pouze jednu hodnotu) mohou byt definovány jako agregované funkce Užití v GROUP BY Pomocí další klauzule AGGRAGATE USING jméno typového balíku; je možné propojit funkci na typový balík realizující vlastní agregaci)
Vytvoření agregované funkce Nejprve je nutné vytvořit vlastní objektový datový typ, který obsahuje následující metody: ODCIAggregateInitialize() ODCIAggregateIterate() ODCIAggregateMerge() ODCIAggregateTerminate() Pak je možné tento typ použít pro vytvoření agregační funkce.
Můj průměr create or replace type MujPrumerImpl as object ( soucet NUMBER, pocet NUMBER, static function ODCIAggregateInitialize (sctx IN OUT MujPrumerImpl) return number, member function ODCIAggregateIterate (self IN OUT MujPrumerImpl,value IN number) return number, member function ODCIAggregateTerminate (self IN MujPrumerImpl,returnValue OUT number, flags IN number) return number, member function ODCIAggregateMerge (self IN OUT MujPrumerImpl, ctx2 IN MujPrumerImpl) return number );
ODCIAggregateInitialize() Inicializuje agregační kontext a instanci typu objektu implementace. Tu navrátí jako výstupní parametr. Funkce je implementována jako statická metoda. Účelem této statické metody je vrátit nově inicializovanou instanci daného typu. Pro běžné případy bývá inicializována na hodnotu NULL. V případě úspěšné inicializace vrací funkce ODCIConst.Success, jinak vrací ODCIConst.Error
ODCIAggregateInitialize() static function ODCIAggregateInitialize (sctx IN OUT MujPrumerImpl) return number is begin sctx := MujPrumerImpl(0, 0); return ODCIConst.Success; end;
ODCIAggregateIterate() Prochází vstupními řádky a zpracovává vstupní hodnoty, aktualizuje a následně se vrací kontext agregace. Funkce je vyvolána pro každou hodnotu, včetně hodnoty NULL.. Jedná se o povinnou rutinu a je implementována jako member metodu. Má dva parametry svoji instanci a vstupní hodnotu, která má být zpracována.
ODCIAggregateIterate() member function ODCIAggregateIterate (self IN OUT MujPrumerImpl, value IN number) return number is begin self.soucet := self.soucet + value; self.pocet := self.pocet + 1; return ODCIConst.Success; end;
ODCIAggregateMerge() Sloučí dva agregační kontexty do instance jednoho objektu v průběhu buď sériového nebo paralelního vyhodnocení uživatelem definované agregace.. Jedná se o povinnou rutinu a je implementována jako member metodu. Má dva parametry oba jsou instancí daného typu.
ODCIAggregateMerge() member function ODCIAggregateMerge (self IN OUT MujPrumerImpl, ctx2 IN MujPrumerImpl) return number is begin self.soucet := self.soucet +ctx2.soucet; self.pocet := self.pocet + ctx2.pocet; return ODCIConst.Success; end;
ODCIAggregateTerminate() Vypočítává výsledek celkového výpočtu a provádí všechny potřebné úkony, jako je například uvolnění paměti. Je vyvolán systémem jako poslední krok agregačního výpočtu. Jedná se o povinnou rutinu a je implementována jako member metodu. Má tři parametry instanci daného typu, návratovou hodnotu a bitový vektor s příznaky (podrobnosti v dokumentaci).
ODCIAggregateTerminate() member function ODCIAggregateTerminate (self IN MujPrumerImpl, returnvalue OUT number, flags IN number) return number is begin if self.pocet = 0 then returnvalue := null; else returnvalue := self.soucet/self.pocet; end if; return ODCIConst.Success; end;
create or replace type body MujPrumerImpl is static function ODCIAggregateInitialize(sctx IN OUT MujPrumerImpl) return number is begin sctx := MujPrumerImpl(0, 0); return ODCIConst.Success; end; member function ODCIAggregateIterate(self IN OUT MujPrumerImpl, value IN number) return number is begin self.soucet := self.soucet + value; self.pocet := self.pocet + 1; return ODCIConst.Success; end; member function ODCIAggregateMerge(self IN OUT MujPrumerImpl, ctx2 IN MujPrumerImpl) return number is begin self.soucet := self.soucet +ctx2.soucet ; self.pocet := self.pocet + ctx2.pocet; return ODCIConst.Success; end; member function ODCIAggregateTerminate(self IN MujPrumerImpl, returnvalue OUT number, flags IN number) return number is begin if self.pocet=0 then returnvalue := null; else returnvalue := self.soucet/self.pocet; end if; return ODCIConst.Success; end; end;
Vytvoření funkce CREATE FUNCTION prumer (input NUMBER) RETURN NUMBER [PARALLEL_ENABLE] AGGREGATE USING MujPrumerImpl;
Zdroj: http://www.codeproject.com/kb/database/customoraaggregate/merge_small.jpg
Spouště (triggery) Jedná se o PL/SQL objekty spouštěné vyvoláním příslušné události v DB Vyvolání může způsobit DML událost, DDL operace nebo speciální DB událost Vyvolat trigger můžeme před, po nebo místo provedení operace Je možné omezit vyvolání podmínkou
Typy DML triggerů DML aktivované triggery: při rušení řádků (DELETE) při vkládání řádků (INSERT) při modifikaci určitých sloupců (UPDATE OF) Způsob vyvolání triggeru: jednou při celé operaci pro každý řádek (FOR EACH ROW) vstupující do zpracování operace Okamžik kdy trigger proběhne BEFORE AFTER INSTEAD OF Možnost kombinací operaci (slučování OR)
Zápis DML triggeru CREATE OR REPLACE TRIGGER jméno BEFORE AFTER INSTEAD OF DELETE INSERT UPDATE OF cols ON tabulka [ způsob odkazování ] [ FOR EACH ROW ] [ WHEN ( podmínka ) ] pl/sql kód
Způsob odkazování Definuje, jak budou přístupné původní a nové záznamy (vstupující do DML operací) :new, :old, :parent Existuje klauzule REFERENCING [ OLD AS jméno ] [ NEW AS jméno ] [ PARENT AS jméno ]
Způsob vyvolávání triggerů Pro BEFORE a AFTER je trigger chápán jako tzv. statement trigger a vyvolán je pouze jedenkrát (není li klauzuli FOR EACH ROW explicitně stanoveno jinak) V případě INSTEAD OF triggeru je trigger implicitně chápán jako řádkový trigger, protože zde statement trigger nemá prakticky žádný význam
DDL triggery Jsou vyvolány při provedení DDL příkazu Mohou být BEFORE, AFTER Mohou být omezeny podmínkou (WHEN) Definují se dvěma způsoby: jméno události ON DATABASE jméno události ON jméno schématu Existuje řada definovaných událostí, např.: CREATE, ALTER, DROP, RENAME, GRANT, COMMENT, AUDIT
Triggery databázových událostí Pracují stejně jako DDL triggery, pouze je jiná množina povolených událostí Typicky se jedná o zásadní události v celé databázové instanci, např. STARTUP, SHUTDOWN, LOGON, LOGOFF, SERVERERROR, SUSPEND apod. Uvnitř DDL a databázových triggerů nelze provádět jiné DDL operace Velmi specifické použití
Omezení triggerů BEFORE a AFTER triggery nelze specifikovat nad pohledy V BEFORE triggerech není možné zapisovat do :old záznamů AFTER triggerech nelze zapisovat ani do :old, ani do :new záznamů INSTEAD OF triggery pracující jen s pohledy, mohou číst :old i :new, ale nemohou zapisovat ani do jednoho Nelze kombinovat INSTEAD OF a UPDATE Nelze definovat trigger nad LOB atributem
Rozlišení operací v triggeru Trigger může být volán různými operacemi (např. INSERT OR DELETE) V průběhu triggeru je třeba rozlišit, která operace se provádí Existují logické proměnné INSERTING, DELETING a UPDATING použitelné v rozhodovaní Je třeba užívat řízení výjimek, protože chyba v triggeru ukončí obvykle celou nadřazenou transakci
Emulace AUTOINCREMENT Některé SQL databázové systémy používají modifikátor typu AUTOINCREMENT pro definici číslování primárních klíčů Je možné toto chovaní emulovat umístěním BEFORE INSERT triggeru, který vyčte novou hodnotu ze sekvence a modifikuje :new.id na tuto hodnotu
Úkol 4 Vytvořte trigger (spoušť), která zajistí, aby bylo možná změnit plat zaměstnance maximálně o 20 %. V případě, že by někdo chtěl plat změnit o více než 20 %. Trigger vyvolá výjimku.
Programové balíky Programový balík je sdružením řady funkcí a procedur s vlastním jmenným prostorem a vlastním persistentním prostorem pro proměnné v rámci jedné session To umožňuje uchovávat hodnoty v rámci session pro řadu procedur a funkcí Ne náhodná analogie s objekty
Komponenty PL/SQL balíku
Tvorba balíků Dvě časti veřejné deklarace a tělo programového balíku CREATE PACKAGE balík AS kód; CREATE PACKAGE BODY balík AS kód; Uvnitř deklarací pouze plné hlavičky funkcí a procedur určených pro volání mimo balík V těle ostatní deklarace proměnných, definice příslušných veřejných objektů a také další privátní podprogramy Přístup pomocí tečkové notace
Syntaxe tvorby specifikace Ve specifikaci deklarujte všechny veřejné prvky balíčku. Klauzule OR REPLACE zajistí přepis případné předchozí verze specifikace balíku. Proměnná deklarované ve specifikaci jsou inicializovány na hodnotu NULL, není-li jim přiřazena jiná hodnota. Všechny prvky deklarované ve specifikaci jsou viditelné pro všechny uživatele, kteří mají přidělena práva k tomuto balíku.
Syntaxe tvorby specifikace pokračování CREATE [OR REPLACE] PACKAGE package_name IS AS public type and variable declarations public subprogram specifications END [package_name]; package_name určuje jméno a musí být unikátní mezi všemi objekty public type and variable declarations deklarace veřejných proměnných, konstant, kurzorů, výjimek, uživatelských typů a subtypů. public subprogram specifications deklarace halviček procedur a funkcí v balíku
Příklad specifikace balíku 1 CREATE OR REPLACE PACKAGE check_emp_pkg IS g_max_length_of_service CONSTANT NUMBER := 100; PROCEDURE chk_hiredate (p_date IN employees.hire_date%type); PROCEDURE chk_dept_mgr (p_empid IN employees.employee_id%type, p_mgr IN employees.manager_id%type); END check_emp_pkg;
Příklad specifikace balíku 2 CREATE OR REPLACE PACKAGE manage_jobs_pkg IS g_todays_date DATE := SYSDATE; CURSOR jobs_curs IS SELECT employee_id, job_id FROM employees ORDER BY employee_id; PROCEDURE update_job (p_emp_id IN employees.employee_id%type); PROCEDURE fetch_emps (p_job_id IN employees.job_id%type, p_emp_id OUT employees.employee_id%type); END manage_jobs_pkg;
Syntaxe tvorby těla balíku Tělo balíku obsahuje detailní kód všech podprogramů deklarovaných ve specifikaci a privátní proměnné. CREATE [OR REPLACE] PACKAGE BODY package_name IS AS private type and variable declarations subprogram bodies [BEGIN initialization statements] END [package_name];
Syntaxe tvorby těla balíku pokračování package_name určuje jméno balíčku, musí se shodovat se jménem ve specifikaci. subprogram bodies kompletní implementace těl všech podprogramů (veřejných i skrytých) private type and variable declarations deklarace neveřejných proměnných, konstant, kurzorů, výjimek, uživatelských typů a subtypů.
Příklad tvorby těla CREATE OR REPLACE PACKAGE BODY check_emp_pkg IS PROCEDURE chk_hiredate (p_date IN employees.hire_date%type) IS BEGIN IF MONTHS_BETWEEN(SYSDATE, p_date) > g_max_length_of_service * 12 THEN RAISE_APPLICATION_ERROR(-20200, 'Invalid Hiredate'); END IF; END chk_hiredate; PROCEDURE chk_dept_mgr (p_empid IN employees.employee_id%type, p_mgr IN employees.manager_id%type) IS BEGIN... END chk_dept_mgr; END check_emp_pkg;
Úkol 5 Vytvořte balík matika_pgk, který bude obsahovat veřejné konstatnty pi (Ludolfovo číslo) a e (Eulerovo číslo). Dále funkce faktorial, obvodtrojuhelnika a enax.
Externí procedury a funkce Je možné definovat PL/SQL procedury a funkce, které jsou ve skutečnosti pouze volanými externích funkcí v jiných programovacích jazycích Místo PL/SQL kódu se za AS uvede LANGUAGE JAVA NAME třída ; LANGUAGE C NAME jméno LIBRARY sdílená knihovna ; Přesahuje rámec této přednášky
Dynamické SQL Co když je text příkazu jazyka SQL není v okamžiku vytváření procedury znám? Jak může server takovýto případ zpracovat? Nemůže!
Dynamické SQL pokračování Je vytvořeno uloženo jako řetězec v rámci podprogramu. Je SQL výraz s různými údaji o sloupcích, různými podmínkami nebo s proměnnými. Umožňuje použití DDL a dalších jinak nepovolených operací v rámci PL/SQL. Je prováděno pomocí příkazu EXECUTE IMMEDIATE nebo pomocí balíku DBMS_SQL
Použití EXECUTE IMMEDIATE INTO je určeno pro jednořádkové dotazy USING určuje parametry vstupující do příkazu
EXECUTE IMMEDIATE příklad
Datový slovník Je část databáze, která obsahuje tzv. systémové informace. Mezi tyto informace patří především: informace o struktuře databází informace o objektech uložených v databázi (tabulky, pohledy, indexy atd.) informace o uživatelích a jejich oprávněních
Datový slovník v Oracle Je uchováván v systémových tabulkách, které jsou určeny jen ke čtení. Struktura datového slovníku se skládá ze dvou částí: základních tabulek uživatelům přístupným pohledům
Účel datového slovníku Přistup k datovému slovníku za účelem najít informace o uživatelích, schématu objektů a skladovacích strukturách. Upravit datový slovník pokaždé, když je použit příkaz z Data Definition Language (DDL). Každý uživatel může datový slovník použít pro zjišťování potřebných informací.
Použití datového slovníku Pohledy datového slovníku slouží jako reference pro všechny uživatele databáze. Některé pohledy jsou přístupné všem uživatelům a jiné jsou určeny pouze pro databázové administrátory. Datový slovník sestává z množiny pohledů. V mnoha případech, sada se skládá ze tří pohledů, které obsahují podobné informace a liší od sebe jejich předponami: USER (co je v uživatelově schématu) ALL (k čemu má uživatel přístup) DBA (co je ve všech uživatelských schématech)
Pohledy datového slovníku _CATALOG _COL_COMMENTS _INDEXES _OBJECTS _ TAB_COLUMNS _ TAB_COMMENTS _ TABLES _ USERS