Regole attive per basi di dati

I DBMS che supportano la programmazione basata su regole possono creare basi di dati che sono dette basi di dati attive. Le istruzioni, chiamate regole attive oppure triggers, sono interpretare dal componente processore delle regole del DBMS.

lezione
lezione
Regole attive per basi di dati
Tipo di risorsa Tipo: lezione
Materia di appartenenza Materia: Basi di dati 2
Avanzamento Avanzamento: lezione completa al 100%

I trigger possono essere inseriti dall'amministratore di sistema (trigger esterni) oppure fare parte del funzionamento del DBMS (trigger interni). Si pensi ad esempio alle azioni per garantire l'integrità referenziale (come ON DELETE CASCADE, ecc.): esse sono trigger (non visibili all'utente) creati dal DBMS.


Le regole seguono il paradigma ECA:

  • Evento: regola di reazione a un determinato evento (ad esempio un'istruzione SQL come INSERT, UPDATE, ecc.). Quando l'evento ha luogo il trigger è chiamato attivato;
  • Condizione: condizione da valutare, se essa è vera il trigger passa nello stato di valutato;
  • Action: azione da eseguire (istruzione o procedura in SQL) se la condizione è verificata, successivamente il trigger sarà nello stato di eseguito.

Regole relazionali

modifica

Le regole relazionali possono avere due modalità:

  • immediata: la valutazione avviene immediatamente all'attivazione del trigger. Si può distinguere a sua volta:
    • opzione before: prima che l'operazione che lo ha generato abbia effetto;
    • opzione after: dopo che l'operazione che lo ha generato ha eseguito le operazioni sulla base di dati.
  • differita: la valutazione avviene alla fine della transazione, a seguito del comando COMMIT.

e due livelli di granularità:

  • row-level: l'attivazione avviene per ogni tupla coinvolta nell'evento;
  • statement-level: l'attivazione avviene per ogni primitiva SQL.

NOTA: se nessuna tupla è coinvolta nel comando SQL, i trigger row-level non verranno eseguiti, mentre quelli statement-level sì.

Trigger in SQL

modifica

Sintassi SQL:

CREATE TRIGGER nometrigger
    {BEFORE | AFTER} {INSERT|DELETE|...} 
    ON tabella
    [ REFERENCING reference ]
    [ FOR EACH {ROW | STATEMENT} ]
    [ WHEN (condizione) ]
    azione;

Se più trigger sono presenti sulla stessa relazione verranno eseguiti prima i trigger BEFORE, eseguita la query e successivamente i trigger AFTER. Se esistono più trigger BEFORE o AFTER, l'ordine di esecuzione non è definito dallo standard SQL:1999, ma dipende dall'implementazione del DBMS.

E' possibile che un trigger attivi un altro trigger in cascata, ed è così possibile creare -con le dovute precauzioni- trigger ricorsivi.

Proprietà delle regole attive

modifica

E' importante assicurare alcune proprietà di base per i trigger, in modo tale che la loro esecuzione non produca effetti indesiderati sulla base di dati e sul sistema che lo esegue. Le classiche proprietà sono:

  • terminazione: per qualsiasi stato iniziale ogni sequenza di possibili trigger deve sempre portare a uno stato finale di terminazione, cioè non è ammesso in nessun caso che l'esecuzione non termini;
  • confluenza: l'ordine di esecuzione dei trigger deve essere indipendente, cioè devono produrre lo stesso effetto sulla base di dati per qualsiasi ordine di esecuzione;
  • osservabilità deterministica: se l'esecuzione è confluente e tutte le azioni osservabili dei trigger (non solo quelle svolte sulla base di dati, ma anche quelle ritornate all'utente) sono indipendenti dall'ordine di esecuzione.

Il rispetto di queste regole è auspicabile ma non sempre possibile: l'amministratore può scegliere di non garantire l'osservabilità o la confluenza in caso. La terminazione invece, è ovviamente un requisito indispensabile.

Per grandi applicazioni anche garantendo le proprietà sopra citate, l'introduzione di trigger aumenta esponenzialmente la complessità della progettazione della base di dati: non è sempre facile capire l'interazione reciproca tra i trigger, cosa che può comportare comportamenti imprevisti. Per facilitare questo lavoro, in alcuni DBMS i trigger possono essere divisi in moduli indipendenti ognuno con una specifica funzione.

Verifica della terminazione con il grafo di attivazione

modifica

Si può dimostrare che la proprietà di terminazione è soddisfatta (ma non viceversa) attraverso il grafo di attivazione. Questo metodo risulta quindi condizione sufficiente alla terminabilità di un insieme di trigger.

Si traccia un grafo con i seguenti elementi:

  • un nodo   per ogni trigger
  • un arco da   a   se il trigger   contiene nel suo codice una chiamata al trigger   (indipendentemente dal flusso di esecuzione). Si noti che i trigger possono essere lo stesso in caso di chiamate ricorsive (anche questi vanno indicati con autoanelli nel grafo)

Allora se il grafo è aciclico, i trigger soddisfano la proprietà di terminazione. Nota: ovviamente se è presente almeno un autoanello la proprietà non può essere dimostrata con questo procedimento.

Se invece il grafo è ciclico, nulla si può dire.

Caratteristiche evolute

modifica

Alcuni DBMS permettono la creazione di trigger non standard con lo scopo di aumentare la potenza delle regole attive:

  • eventi temporali: probabilmente i più usati, permettono di eseguire trigger a determinati orari o intervalli (ogni giorno alle 15:00, ogni 5 del mese, ecc.)
  • eventi di sistema: esecuzione all'avvio del sistema, allo spegnimento, ecc.
  • eventi esterni: provenienti da altre applicazioni

Altri trigger possono avere modalità di esecuzione differente:

  • immediata: trigger normale in cui l'esecuzione avviene subito dopo l'attivazione;
  • differita: l'esecuzione è rimandata alla fine della transazione;
  • distaccata: l'esecuzione avviene in una nuova transazione.

Esempio di trigger row-level

modifica
CREATE TRIGGER TransazioniCheck
    AFTER INSERT ON Depositi
    FOR EACH ROW 
    WHEN valida=1
    UPDATE ContoCorrente SET saldo = saldo + new.ammontare WHERE codice=new.conto;

Esempio di trigger statement-level

modifica

After Mode

modifica
CREATE TRIGGER Cestino
    AFTER DELETE ON Prodotti
    REFERENCING old table AS VecchiProdotti
    INSERT INTO ProdottiEliminati (SELECT * FROM VecchiProdotti WHERE id NOT IN (SELECT id FROM Prodotti));

Before Mode

modifica
CREATE TRIGGER ControllaLimiti
    AFTER Update ON Valori
    FOR EACH ROW
    WHEN new.valore > 100
    SET new.valore = 100

Bibliografia

modifica