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>
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:
Č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):
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. :
Č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:
-
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:
Příklad 5:
Událost "když je plat kteréhokoli zamětnance více než zdvojnásoben" může být
reprezentována takto:
- 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:
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:
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:
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:
- 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. .
- 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ů:
- SQL3:
CREATE TRIGGER ZdvojnasobeniPlatu AFTER UPDATE OF Sal ON emp
FOR EACH ROW
WHEN EXISTS (SELECT * FROM sal-change
WHERE Eno = NEW.Eno AND Year = CurrentYear AND Cnt >= 2)
BEGIN ATOMIC
UPDATE sal-change SET Cnt = Cnt+1
WHERE Eno = NEW.Eno AND Year = CURRENT_YEAR;
INSERT INTO log VALUES(NEW.Eno, NEW.Sal);
END
- TBE:
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.
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á.
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.
- 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.
- 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.
- 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ů