Josef Troch (troch@mail.ru)
5.5.2002 (poslední změna 5.5.2002)

TBE - Trigger By Example

TBE (Trigger By Example) je grafické uživatelské rozhraní a jazyk pro definování triggerů vycházející ze systému QBE (Query By Example). Hlavní snahou jeho autorů bylo zjednodušit psaní triggerů pro méně zkušené uživatele. TBE rovněž odděluje uživatele od systému triggerů v pod TBE ležící databází, a proto je použitelné jako univerzální rozhraní pro psaní triggerů - může triggery překládat do libovolného jazyka, který je podporuje.

Úvod

Triggery umožňují automaticky reagovat na události, které nastávají na datech, vyhodnocením podmínky závisející na datech a v případě kladného výsledku následným spuštěním nějaké reakce. Triggery jsou užitečnou funkcionalitou v databázi, a tak byly implementovány většinou výrobců databází. Jedním z důvodů bránících dalšímu rozšíření používání triggerů je nedostatek nástrojů, které by pomohly uživateli vytvářet komplexní triggery jednoduchým způsobem.
Systém QBE (Query By Example) je velmi populární v podstatě již od svého vzniku a dnes je používán v řadě moderních databázových produktů. Je založen na doménovém relačním kalkulu a bylo dokázáno, že vyjadřovací síla QBE je stejná jako u SQL (které je založeno na n-ticovém relačním kalkulu). Narozdíl od SQL, kde uživatel musí přesně dodržovat strukturu příkazů / dotazů, v QBE může uživatel napsat libovolný výraz do libovolné položky - jen tento výraz musí být syntakticky korektní. Tyto položky jsou svázány s příslušnými sloupci kostry tabulky (table skeleton), a tak uživatel může pokládat pouze přípustné dotazy.
TBE používá upravené QBE jako rozhraní pro psaní triggerů. Protože většina v praxi používaných triggerů je složitými kombinacemi SQL výrazů, použití QBE jako uživatelského rozhraní je užitečné, neboť způsobí, že uživatel může zadávat pouze přípustné (korektní) triggery. Hlavní myšlenkou TBE je použít deklarativní QBE pro psaní procedurálních triggerů.

SQL3 triggery

V SQL3 jsou triggery často nazývány event-condition-action rules (událost-podmínka-akce) či ECA rules z prostého důvodu - sestávají totiž ze tří základních částí události (event), podmínky (condition) a akce (action). V době, kdy vyšel článek o TBE, který je zdrojem pro tento referát (viz zdroje a odkazy), nebylo SQL3 stále ještě standartizováno, a proto všechny informace o SQL3 v onom článku i v tomto referátu vychází z ANSI X3H2 SQL3 working draft-u.

Definice triggeru v SQL3 má tuto strukturu:
CREATE TRIGGER <jmeno_triggeru>
       {AFTER | BEFORE} <trigger_event> ON <jmeno_tabulky>
       [REFERENCING <references>]
       [FOR EACH {ROW | STATEMENT}]
       [WHEN <SQL_statements>]
       <SQL_procedure_statements>
Kde:
<trigger_event> ::= INSERT | DELETE | UPDATE [OF <jmena_sloupcu>
<reference> ::= OLD [AS] <jmeno_puvodni_hodnoty> |
                NEW [AS] <jmeno_nove_hodnoty> |
                OLD_TABLE [AS] <jmeno_tabulky_puvodnich_hodnot> |
                NEW_TABLE [AS] <jmeno_tabulky_novych_hodnot>

Schéma příkladu

V celém tomto článku budu používat (stejně jako autoři původního článku) tento příklad:
Mějme tabulky emp a dept obsahující po řadě údaje o zaměstnancích nějakého podniku (číslo zaměstnance, jméno, číslo oddělení (kde zaměstnanec pracuje), plat) a údaje o odděleních podniku (číslo oddělení, název oddělení, zaměstnanecké číslo vedoucího). Klíče tabulek jsou podtrženy. emp.Dept a dept.MgrNo jsou cizí klíče odkazující se po řadě na hodnoty atributů dept.Dno a emp.Eno.
emp(Eno, Ename, DeptNo, Sal)

dept(Dno, Dname, MgrNo)

QBE (Query By Example)

QBE je dotazovací jazyk a vizuální uživatelské rozhraní (GUI) zároveň. V QBE se dotazy pokládají pomocí 2-rozměrných koster tabulek (skeleton tables) vyplněním jakéhosi příkladu (example - proto "by example") odpovědi do příslušných políček tabulky. Dalším druhem dvoudimenzionálního objektu v QBE je condition box (místo pro zadání podmínky) - používá se k zadání 1 či více požadovaných podmínek, které by bylo obtížné vyjádřit v kostrách tabulek (skeleton tables).
Jména proměnných v QBE odpovídají malým písmenům, před něž je vložen znak '_' (tedy např: _t ); systémové příkazy se zadávají velkými písmeny, za kterými následuje '.' (např. pro výpis odpovídající hodnoty: P.); konstanty se nezadávají v úvozovkách ani v apostrofech (narozdíl od SQL).

Příklad 1:
Vypiš zaměstnance, jejichž vedoucím je 'Tom'.

TBE (Trigger By Example)

TBE vyvinuli Dougwon Lee, Wenlei Mao a Wesley W. Chu z University of California v roce 1999.

Hlavní myšlenkou TBE (Trigger By Example) je používat QBE jako uživatelské rozhraní pro psaní triggerů. Výhodou QBE (a tedy i TBE) je to, že vyžaduje od uživatele pouze velmi málo znalostí, aby mohl s tímto systémem začít pracovat, a zároveň minimalizuje množství pojmů, které se časem musí uživatel naučit, aby porozuměl celému jazyku QBE (resp. TBE).

Problémy vyjádření procedurálních triggerů v deklarativním jazyce

Triggery v SQL3 jsou svou povahou procedurální - akce v triggerech mohou kromě klasických SELECT, INSERT, DELETE atp. obsahovat výrazy pro práci s transakcemi, s připojením k databázi atd. Taktéž pořadí mezi výrazy specifikujícími akce musí být zachováno pro zachování korektní sémantiky akce.
Na druhé straně, QBE je deklarativní jazyk. Zadává-li v něm uživatel dotaz, nemusí se starat o to, zda první řádek v kostře tabulky má být "spuštěn" před druhým či nikoliv. Tedy v QBE je pořadí řádků nepodstatné. Dalším problémem je fakt, že QBE bylo vytvořeno coby nástroj pro získávání dat (SELECT), pro modifikaci dat (INSERT, DELETE, UPDATE) a pro definici schémat a manipulaci s dotazy. Proto QBE nemůže jednoduše podporovat ostatní (procedurální) SQL výrazy - jako jsou výrazy pro práci s transakcemi a uživatelsky definované funkce.
Tyto nedostatky QBE se pokusili vyřešit autoři TBE. TBE by tedy mělo být použitelné pro zadávání procedurálních SQL3 triggerů, ale zároveň by mělo (tam, kde to lze) zachovávat deklarativnost QBE.

Jméno triggeru

Každý trigger v TBE musí mít unikátní jméno. Toto jméno uživatel zadává to specielního pole nazývaného name box:
Obrázek name box-u

Časté jsou rovněž případy, kdy je několik triggerů zapisováno dohromady - tedy jako jeden dotaz v TBE. V tomto případě uživatel logicky musí udat jednoznačné jméno pro každý z těchto triggerů zvlášť.

Jelikož jméno triggeru je pro pochopení níže uvedených příkladů TBE dotazů nepodstatné, nebude v nich pro jednoduchost uváděno.

Části triggeru: Event - Condition - Action

Jak již bylo zmíněno výše, triggery v SQL sestávají hlavně ze 3 izolovaných částí: události (event), podmínky (condition) a akce (action). V TBE každé z těchto částí odpovídá samostatná řada koster tabulek. Pro jejich rozlišení se k názvu každé tabulky (v kostře tabulky) přidává jako prefix první písmeno příslušné části - tedy E., C. nebo A. Stejným způsobem se rozšíří i condition box (pole pro zadávání podmínky).
Např. výraz pro část podmínka (condition) se zadává do kostry tabulky a condition box-u uvedeného níže (pro tabulku z výše popsaného schématu příkladu):
Příklad na condition - kostra tabulky a condition box

Typy událostí v triggerech

Události (events) v SQL3 triggerech mohou být pouze třech typů: INSERT, DELETE či UPDATE. V QBE se používají konstrukty I., D. a U. pro výše uvedené události v dotazech manipulujících s daty. TBE stejné konstrukty používá k popsání typu události triggeru.
Protože INSERT a DELETE se vždy týkají celého řádku tabulky, I. či D. se zapisuje do nejlevějšího sloupce kostry tabulky pro událost (tedy do sloupce pod jménem tabulky - neodpovídá žádnému ze sloupců tabulky v databázi). Pro UPDATE trigger, který ovlivní jen některé sloupce tabulky, se U. zapíše do odpovídajících sloupců kostry tabulky, jinak se U. zapíše taktéž do nejlevějšího sloupce tabulky.

Příklad 2:
Kostry tabulek (1) a (2) znázorňují INSERT a DELETE na tabulce dept, kostra tabulky (3) odpovídá UPDATE-u sloupců Dname a MgrNo v téže tabulce, (4) odpovídá UPDATE-u na libovolných sloupcích tabulky dept. Jelikož specifikujeme událost, jméno tabulky je vždy prefixováno E. :
Příklady na I., U., D.

Čas aktivace triggeru, granularita triggeru

U SQL3 triggerů je zaveden pojem event activation time (čas aktivace triggeru), který specifikuje, zda se trigger spouští před či po příslušné události. Čas aktivace může nabývat dvou hodnot: before (před událostí) a after (po události). Triggery v before módu se používají především pro úpravu dat přidávaných do databáze, after triggery pak pro vestavění nějaké aplikační logiky.
V TBE jsou pro tyto dva módy zavedeny konstrukty BFR. a AFT. ('.' na konci udává, že jde o vestavěné systémové konstrukty - jako v QBE).

Granularity (granularita) udává, kolikrát se trigger spouští pro jednu akci. Granularita triggeru v SQL3 může být for each row (pro každý řádek) nebo for each statement (pro každý příkaz) - což odpovídá po řadě row-level a statement-level triggerům. Triggery typu row-level jsou spouštěny při každé příslušné modifikaci (INSERT, UPDATE či DELETE) libovolného řádku odpovídající tabulky - narozdíl od statement-level triggerů, které se spouští pro každou událost (event) jen jednou, bez ohledu na počet řádků, kterých se tato událost dotkla.
(Př.: Uživatel zadá dotaz, který vymaže z tabulky 8 řádků - pokud na toto reaguje statement-level trigger, spustí se jen jednou; reaguje-li na to row-level trigger, spustí se 8-krát.)
V TBE konstrukt R. odpovídá row-level triggerům, S. statement-level triggerům.

Příklad 3:
Reprezentace triggeru s časem aktivace after a s granularitou row-level v SQL3 a v TBE.

Transition values (přechodné hodnoty)

Když nastane nějaká událost a hodnoty v tabulce se změní, trigger často potřebuje hodnoty příslušných atributů před a (nebo) po události - tyto hodnoty se nazývají transition values (přechodné hodnoty). V SQL3 se k těmto hodnotám přistupuje pomocí transition proměnných (OLD, NEW - vrací vždy řádek po resp. před jeho změnou) nebo tabulek (OLD_TABLE, NEW_TABLE - vrací sadu řádků (po resp. před změnou), kterých se změna dotkla), podle toho zda jde o row-level či statement-level trigger.
V SQL3 trigger reagující na INSERT může používat (logicky) jen NEW či NEW_TABLE, trigger reagující na DELETE jen OLD či OLD_TABLE, ale trigger reagující na UPDATE může používat obě transition proměnné či tabulky.

Autoři TBE navrhli dva způsoby pro přístup k těmto hodnotám v TBE:
  1. Pomocí nových vestavěných funkcí OLD() a NEW() pro row-level a OLD_TABLE() a NEW_TABLE() pro statement-level triggery. Obdobně jako v SQL3, je ilegální používat NEW() či NEW_TABLE() na proměnnou v triggeru reagujícím na DELETE, analogicky pro INSERT a OLD() či OLD_TABLE(). Z tohoto důvodu je používání NEW() či NEW_TABLE() na proměnnou v triggeru reagujícím na DELETE redundantní - stačí napsat místo toho přímo proměnnou (opět obdobně pro INSERT). V triggeru reagujícím na UPDATE je samozřejmě nutné tyto vestavěné funkce důsledně používat (chceme-li nějak pracovat s měněnými hodnotami).

    Příklad 4:
    Chceme-li reagovat na událost "pokaždé, když je přidáno více než 10 nových zaměstnanců", můžeme tuto událost reprezentovat takto:
    Reprezentace příslušné události v TBE

    Příklad 5:
    Událost "když je plat kteréhokoli zamětnance více než zdvojnásoben" může být reprezentována takto:
    Reprezentace příslušné události v TBE
  2. Pomocí změny koster tabulek - v závislosti na typu události, kostry tabulek se příslušně změní - mohou se objevit i další sloupce. Pro událost INSERT, klíčové slovo NEW_ se připojí před jména sloupců v kostře tabulky; pro DELETE se analogicky připojuje OLD_ . Pro UPDATE se klíčové slovo OLD_ připojí ke jménům všech sloupců, jejichž hodnoty se mění - tyto sloupce budou odpovídat hodnotám před změnou; zároveň budou do tabulky přidány sloupce s prefixem NEW_, odpovídající hodnotám po UPDATE-u (počet sloupců s prefixem NEW_ i OLD_ bude stejný).
    (Autoři rovněž uvažovali nad modifikací a případným přidáváním celých tabulek - ne sloupců. Tato myšlenka byla zavržena kvůli nevýhodám při UPDATE-u jednoho sloupce - vznikly by dvě tabulky s řadou shodných sloupců, lišící se jen v jediném - snadné pro zanesení chyby, nepřehledné.)

    Příklad 6:
    Mějme událost "když je Johnův plat zdvojnásoben, ale nezmění se oddělení, kam John přináleží". Uživatel zapíše do první z níže uvedených tabulek granularitu a čas aktivace, pak do příslušných sloupců U. pro UPDATE. Tabulka se změní v druhou z níže uvedených - objeví se 2 nové sloupce a konstrukt U. se přesune do nejlevějšího sloupce tabulky:
    Začátek přísl. příkladu - změna tabulky

    Pak uživatel vyplní příslušné hodnoty a proměnné do příslušných sloupců - např. "nezmění se oddělení" lze vyjádřit pomocí _d ve sloupci OLD_DeptNo a zároveň ve sloupci NEW_DeptNo:
    Výsledný dotaz

Autoři se nakonec rozhodli pro variantu 1. - tedy použití vestavěných funkcí. Ačkoli obě varianty mají stejnou vyjadřovací sílu, při první se nemění uživatelské rozhraní - čímž je tato metoda z hlediska uživatele vhodnější.

SQL3 dovoluje přejmenování transition proměnných a tabulek pomocí konstruktu REFERENCING. V TBE tento konstrukt není třeba, neboť transition hodnoty jsou přímo odkazovány pomocí proměnných vyplněných to koster tabulek.

Procedurální výrazy

V SQL3 existuje řada procedurálních výrazů (procedural statements) jako IF, CASE, přiřazení atp., které nelze jednoduše reprezentovat v TBE, právě kvůli jejich procedurálnímu charakteru. Vyjadřovací síla těchto výrazů přesahuje hranice deklarativního QBE. Z tohoto důvodu TBE nabízí speciální pole nazývané statement box (pole pro zadávání výrazů) - podobné condition box -u. Uživatel sem může zapsat libovolnou posloupnost SQL výrazů oddělených ';'. Protože statement box se může vyskytnout jen v části triggeru nazývané akce (action), A. se vždy připojuje k názvu tohoto pole:
statement box

Pořadí vykonávání akcí v triggeru

SQL3 dovoluje v jednom triggeru použít více výrazů pro akci, tyto jsou pak spouštěny ve stejném pořadí, ve kterém jsou zapsány. Aby se v TBE daly reprezentovat takovéto triggery, ve kterých záleží na pořadí výrazů, bylo rozhodnuto, že uvnitř jedné kostry tabulky se výrazy spouští postupně, dle toho jak jsou zapsány od shora dolů. Výrazy v různých kostrách tabulek jsou spouštěny podle pořadí, v němž jsou zobrazeny tyto tabulky.

Zadávání podmínek v TBE

Ve většině databázových jazyků pro psaní triggerů (včetně SQL3), část triggeru odpovídající události (event part) je přímo spojena s událostí, která nastala a nemůže provádět další testy (ty se provádí až v podmínkové (condition) části). Přesto existují jazyky (Ode, SAMOS, Chimera), které poskytují jakýsi filtrovací mechanismus pro testování parametrů události. Tyto filtry mohou být užitečné pro optimalizaci zpracování triggerů - jen události, které projdou těmito filtry jsou poslány modulu, který se zabývá zpracováním podmínek (condition module), což může vést ke značnému zrychlení.
Podmínky v triggerech můžeme obecně rozdělit na dva druhy:
  1. Parameter filter (PF, filtr parametrů)
    Tento typ podmínky testuje parametry události - tedy musí používat pouze transition proměnné a tabulky. Příkladem takovýchto podmínek mohou být příklady 4 a 5, tedy podmínky typu "pokaždé, když je přidáno více než 10 nových zaměstnanců" či "když je plat kteréhokoli zamětnance více než zdvojnásoben".
    V TBE je tento typ typicky representován v condition box-u s prefixem E. .
  2. General constraint (GC, obecná podmínka)
    Tento typ odpovídá libovolné obecné podmínce, která nemusí mít žádný vztah k události a transition hodnotám. Příkladem na tento typ podmínky může být třeba níže uvedený příklad 7.
    V TBE je tento typ typicky representován v condition box-u s prefixem C. .
Z výše uvedeného je tedy vidět, že autoři TBE se rozhodli poskytnout uživateli možnost mezi těmito dvěma typy podmínek rozlišovat - toto zajišťuje právě rozlišení condition box-ů na dva druhy (C. a E.). Hlavním důvodem pro toto vylepšení byla dle autorů možnost budoucí podpory jiných jazyků pro definici triggerů, než je SQL.

Poznámka: SQL3 v podstatě nemá podmínky typu PF - všechny podmínky (ať už jsou GC či PF typu) v SQL3 triggeru mohou být specifikovány až ve WHEN, tedy již ne v části odpovídající události.

Příklad 7:
Když je plat nějakého zaměstnance zvýšen v průběhu téhož kalendářního roku více než dvakrát (předpokládáme, že proměnná CURRENT_YEAR obsahuje aktuální rok), zapiš změny do tabulky log(Eno, Sal). Předpokládáme, že zde navíc existuje ještě tabulka sal-change(Eno, Cnt, Year), ve které si držíme všechny změny platů zaměstnanců: Zde podmínková část triggeru kontroluje hodnotu Cnt z tabulky sal-change aby zjistila, kolikrát se za daný rok příslušný plat zvýšil - tedy netestuje žádnou transition hodnotu. Proto tato podmínka je typu GC, nikoliv PF; a proto také condition box i první výskyt tabulky sal-change mají prefix C. .

Implementace TBE

Autoři implementovali předběžný prototyp systému TBE v JDK 1.2 . Tento prototyp poskytuje výše rozebrané uživatelské rozhraní, navíc umí překládat takto zadané triggery do SQL3 pomocí algoritmu nazvaného "tbe2triggers", který je popsán například v článku č. 2 zmíněném níže v odkazech (jde o podobný algoritmus, jako algoritmus "qbe2sql" pro překlad QBE do SQL).
Hlavní obrazovka tohoto programu sestává ze dvou částí - jedné pro vstup (zde uživatel tvoří triggery) a jedné pro výstup (sem se generuje odpovídající trigger v SQL3).
Následující obrázek zobrazuje zmíněný prototyp, v němž je zadán trigger z příkladu 7.

Obrázek okna zmíněného prototypu

Závěr

Výše bylo popsáno, jak vypadá uživatelské rozhraní a jazyk TBE. V obou níže uvedených článcích lze nalézt řadu složitějších příkladů na TBE, v druhém z nich pak i algoritmus, kterým se z triggeru v TBE dá generovat trigger v SQL3.
Výhodou TBE je jistě jednoduché uživatelské rozhraní a možnost překladu v něm zapsaných triggerů do jiného dotazovacího jazyka, který je podporuje. Na druhou stranu, alespoň podle domovské stránky projektu TBE se zdá, že veškerý výzkum ohledně TBE skončil vydáním níže uvedených článků a TBE se žádného praktického použítí za více než dva roky od poslední změny na své stránce nedočkalo, a tedy nejspíše už ani nedočká.


Zdroje a odkazy:

Zdrojem pro tento referát byl převážně první z níže uvedených článků - z něj také pochází všechny výše uvedené obrázky s vyjímkou posledního, který byl stažen z domovské stránky projektu TBE. Článek uvedený na druhém místě je obsáhlejší - obsahuje mimo jiné i popis algoritmu, kterým se z TBE generují SQL3 triggery.
  1. Dongwon Lee, Wenlei Mao, Wesley W. Chu: TBE: Trigger-By-Example , Proc. 19th Int'l Conf. on Conceptual Modeling (ER), Salt Lake City, Utah, October 2000.
  2. Dongwon Lee, Wenlei Mao, Henry Chiu, Wesley W. Chu: TBE: The Graphical Interface for Writing Trigger Rules in Active Databases, Proc. 5th IFIP 2.6 Working Conf. on Visual Database Systems (VDB), Fukuoka, Japan, May 2000.
  3. Domovská stránka projektu TBE.

Tento článek smí být používán libovolně, za předpokladu, že nebude modifikován a že takto bude učiněno se zmínkou o autorovi a odkazem na stránku http://jt.sf.cz, odkud by měla být dostupná aktuální verse tohoto článku.
Snažím se, aby informace zde uvedené byly pravdivé a pokud možno přesné, nicméně nenesu žádnou odpovědnost za to, že tomu tak opravdu je, ani za jakékoli škody, které by někomu v důsledku případných špatných či nepřesných informací z tohoto článku mohly vzniknout.



Jakékoliv dotazy či připomínky mi můžete poslat mailem.

Zpět na stránku referátů a jiných výtvorů