ΚΕΡΑΜΟΠΟΥΛΟΣ ΕΥΚΛΕΙΔΗΣ
Μία διαδικασία την οποία δηλώνει ο Διαχειριστής της Βάσης Δεδομένων και η οποία ενεργοποιείται αυτόματα από το ΣΔΒΔ κάθε φορά που συμβαίνουν μεταβολές ορισμένου τύπου στα δεδομένα ονομάζεται έναυσμα. Δρ. Κεραμόπουλος Ευκλείδης 2
Μία Βάση Δεδομένων η δήλωση της οποίας συνδυάζεται με δηλώσεις εναυσμάτων ονομάζεται ενεργή βάση δεδομένων. Δρ. Κεραμόπουλος Ευκλείδης 3
Στην περιγραφή ενός εναύσματος υπάρχουν τρία διακριτά μέρη: Γεγονός: μία μεταβολή στη βάση δεδομένων η οποία ενεργοποιεί το έναυσμα. Συνθήκη: ένα αίτημα ή ένας έλεγχος που εκτελείται με την ενεργοποίηση του εναύσματος. Ενέργεια: μία διαδικασία η οποία εκτελείται όταν ισχύει η συνθήκη και ενεργοποιείται το έναυσμα. Το όνομα ενός εναύσματος στο σχήμα της βάσης θα πρέπει να είναι μοναδικό. Να μην υπάρχει άλλο έναυσμα με το ίδιο όνομα. Δρ. Κεραμόπουλος Ευκλείδης 4
DML φράσεις (DELETE, INSERT, UPDATE) DDL φράσεις (CREATE, ALTER, DROP) Λειτουργίες Βάσης Δεδομένων (LOGON, LOGOFF) Δρ. Κεραμόπουλος Ευκλείδης 5
Before Εκτελείται πριν συμβούν μεταβολές στη βάση. Παράδειγμα: Για ένα έναυσμα το οποίο αρχικοποιεί μία μεταβλητή η οποία αριθμεί το πλήθος των κατάλληλων προς εισαγωγή εγγραφών, η εκτέλεση του πρέπει να προηγείται. After Εκτελείται αφού συμβούν μεταβολές στη βάση. Παράδειγμα: Για ένα έναυσμα το οποίο αυξάνει τον αντίστοιχο μετρητή κάθε φορά που καταχωρείται μία εγγραφή, η εκτέλεση του είναι πιο λογικό να έπεται. Δρ. Κεραμόπουλος Ευκλείδης 6
1. Δεν πρέπει να περιλαμβάνει δυναμικές παραμέτρους. 2. Δεν πρέπει να εκτελεί εντολές create, alter, ή drop για τον πίνακα που είναι ορισμένο το έναυσμα. 3. Δεν πρέπει να δημιουργεί ή να αφαιρεί ένα index για τον πίνακα που είναι ορισμένο το έναυσμα. 4. Δεν πρέπει να δημιουργεί ή να αφαιρεί ένα έναυσμα για τον πίνακα που είναι ορισμένο το έναυσμα. Δρ. Κεραμόπουλος Ευκλείδης 7
CREATE TRIGGER όνομα-trigger { INSERT DELETE UPDATE } [ OF όνομα_στήλης [, όνομα_στήλης]* ] ON όνομα_πίνακα REFERENCING FOR EACH ROW / FOR EACH STATEMENT MODE DB2ROW / DB2SQL WHEN (συνθήκη) BEGIN Σώμα του trigger END REFERENCING REFERENCING OLD AS ΟΝΟΜΑ_ΠΑΛΙΑΣ_ΕΓΓΡΑΦΗΣ REFERENCING NEW AS ΟΝΟΜΑ_NEΑΣ_ΕΓΓΡΑΦΗΣ FOR EACH ROW Το έναυσμα ενεργοποιείται για κάθε μία εγγραφή που ενημερώνεται FOR EACH STATEMENT WHEN (ΠΡΟΕΠΙΛΟΓΗ) Το έναυσμα ενεργοποιείται μία φορά για την εντολή γεγονός που ενεργοποιεί το έναυσμα. Συνήθως συνοδεύεται και από το WHEN Δρ. Κεραμόπουλος Ευκλείδης 9
CREATE TRIGGER SAILORS1 AFTER INSERT ON SAILORS REFERENCING NEW AS N FOR EACH ROW MODE DB2SQL UPDATE SAILORS SET AGE_UPDATED = CURRENT TIMESTAMP WHERE SID = N.SID TIMESTAMP Είναι η χρονοσφραγίδα. Περιέχει την τιμή της ημερομηνίας και της ώρας μαζί. π.χ. 2009-03-31 13:15:180 ΕΠΕΞΗΓΗΣΗ Μετά από κάθε εισαγωγή στον πίνακα sailors ενημερώνει το πεδίο age_updated με τη στιγμή της εισαγωγής. Η ενημέρωση γίνεται μόνη στη γραμμή που εισάγεται και αυτό εξασφαλίζεται στο WHERE όπου το Ν.sid αναφέρεται στη νέα γραμμή που εισάγεται. Δρ. Κεραμόπουλος Ευκλείδης 10
CREATE TRIGGER SAILORS1 AFTER UPDATE OF sid, age, rating ON SAILORS REFERENCING NEW AS N FOR EACH ROW MODE DB2SQL UPDATE SAILORS SET AGE_UPDATED = CURRENT TIMESTAMP WHERE SID = N.SID ΕΠΕΞΗΓΗΣΗ Μετά από κάθε ενημέρωση των πεδίων sid, age, rating του πίνακα sailors ενημερώνει το πεδίο age_updated με τη στιγμή της εισαγωγής. Η ενημέρωση γίνεται μόνο στη γραμμή που εισάγεται και αυτό εξασφαλίζεται στο WHERE όπου το Ν.sid αναφέρεται στη νέα γραμμή που εισάγεται. Δρ. Κεραμόπουλος Ευκλείδης 11
CREATE TRIGGER SALARY_TRACK AFTER UPDATE OF SALARY ON EMPLOYEE REFERENCING NEW ROW AS NROW OLD ROW AS OROW FOR EACH ROW MODE DB2SQL WHEN (NROW.SALARY > OROW.SALARY) BEGIN INSERT INTO SALARY_CTL (EMPNO, NEW_SALARY, OLD_SALARY, UPDATE_TIMESTAMP) VALUES (NROW.EMPNO, NROW.SALARY, OROW.SALARY, CURRENT TIMESTAMP); END ΕΠΕΞΗΓΗΣΗ Μετά από ενημέρωση του πεδίου sailors στον πίνακα employee γεμίζει τον πίνακα salary_ctl με τις κατάλληλες τιμές. Δρ. Κεραμόπουλος Ευκλείδης 12
CREATE FUNCTION functionname() RETURNS trigger AS $$ begin σώμα end; $$ LANGUAGE 'plpgsql CREATE TRIGGER triggername Before after insert delete update on tablename For each row execute procedure functionname(); Δρ. Κεραμόπουλος Ευκλείδης 14
CREATE FUNCTION funcβ() RETURNS trigger AS $$ begin new.updated:=now(); return new; end; $$ LANGUAGE 'plpgsql Η μέθοδος now() παίρνει την τιμή του χρόνου αντίστοιχα με τον τύπο που έχει δηλωθεί η στήλη στην οποία θα δώσει τιμή. Π.χ. Time Date Timestamp CREATE TRIGGER trignameb Before insert on A For each row execute procedure funcb(); Δρ. Κεραμόπουλος Ευκλείδης 15
CREATE OR REPLACE FUNCTION funca() RETURNS trigger AS $$ declare curtime timestamp; begin curtime := \'now\'; UPDATE A SET updated = curtime WHERE x = new.x and y = new.y; return new; end; $$ LANGUAGE 'plpgsql CREATE TRIGGER trignamea after insert on A For each row execute procedure funca(); Δρ. Κεραμόπουλος Ευκλείδης 16
Η γλώσσα PL/pgSQL μπορεί να χρησιμοποιηθεί για να ορίσει trigger procedures. Μία trigger procedure δημιουργείται με την εντολή CREATE FUNCTION, δηλώνοντας την ως συνάρτηση χωρίς παραμέτρους που επιστρέφει τύπο έναυσμα. Μία συνάρτηση trigger πρέπει να επιστρέφει NULL ή μία εγγραφή/γραμμή της δομής του πίνακα για τον οποίο ενεργοποιήθηκε ο trigger. Οι παράμετροι σε μία trigger procedure περνάνε με τα TG_ARGV. Δρ. Κεραμόπουλος Ευκλείδης 17
Όταν καλείται μία PL/pgSQL συνάρτηση ως trigger, διάφορες ειδικές μεταβλητές δημιουργούνται αυτόματα. NEW type RECORD Αυτή η μεταβλητή κρατάει τη νέα γραμμή που προκύπτει από εντολή INSERT/UPDATE σε row-επιπέδου triggers. Η τιμή της μεταβλητής είναι NULL σε statement-επιπέδου triggers και για την εντολή DELETE. OLD type RECORD Αυτή η μεταβλητή κρατάει τη παλιά γραμμή πριν αλλάξει από μία εντολή UPDATE/DELETE σε row-επιπέδου triggers. Η τιμή της μεταβλητής είναι NULL σε statement-επιπέδου triggers και για την εντολή INSERT. Δρ. Κεραμόπουλος Ευκλείδης 18
TG_NAME Αυτή η μεταβλητή περιέχει το όνομα του trigger που μόλις ενεργοποιήθηκε. TG_WHEN Περιέχει την τιμή BEFORE ή AFTER όπως έχει δηλωθεί στον trigger. TG_LEVEL Περιέχει την τιμή ROW or STATEMENT όπως έχει δηλωθεί στον trigger. TG_OP Περιέχει την τιμή INSERT, UPDATE, DELETE, όπως έχει δηλωθεί στον trigger. TG_RELID Περιέχει το object ID του πίνακα για τον οποίο ενεργοποιήθηκε ο trigger. TG_TABLE_NAME Περιέχει το όνομα του πίνακα για τον οποίο ενεργοποιήθηκε ο trigger. TG_TABLE_SCHEMA Περιέχει το όνομα του σχήματος που ανήκει ο πίνακας για τον οποίο ενεργοποιήθηκε ο trigger. Δρ. Κεραμόπουλος Ευκλείδης 19
CREATE FUNCTION upgraderating() RETURNS TRIGGER AS $$ DECLARE sid_per_day INTEGER; BEGIN SELECT COUNT(*) INTO sid_per_day FROM Reserves WHERE sid = NEW.sid and day1 = NEW.day1; IF sid_per_day > 3 THEN UPDATE Sailors SET rating=rating +1 WHERE sid = NEW.sid; END IF; RETURN NULL; END; $$ LANGUAGE plpgsql; CREATE TRIGGER upgraderatingtrigger AFTER INSERT ON Reserves FOR EACH ROW EXECUTE PROCEDURE upgraderating(); Δρ. Κεραμόπουλος Ευκλείδης 21
Εκτελώ κατάλληλες εντολές για να ενεργοποιήσω τον trigger insert into reserves values (22,103, date('1998-10-10')); insert into reserves values (22,104, date('1998-10-10')); Παρατηρώ ότι το rating του sailor 22 αυξήθηκε. Δρ. Κεραμόπουλος Ευκλείδης 22
CREATE TABLE emp ( empid integer NOT NULL primary key, empname varchar(20), salary integer, last_date timestamp, last_user varchar(20) ); Δρ. Κεραμόπουλος Ευκλείδης 24
CREATE FUNCTION emp_stamp () RETURNS TRIGGER AS $$ BEGIN -- Έλεγξε αν εισάγονται τιμές για τα πεδία empname και salary IF NEW.empname ISNULL THEN RAISE EXCEPTION ''empname cannot be NULL value''; END IF; IF NEW.salary ISNULL THEN RAISE EXCEPTION ''% cannot have NULL salary'', NEW.empname; END IF; -- Έλεγξε αν δίνεται αρνητικός μισθός IF NEW.salary < 0 THEN RAISE EXCEPTION ''% cannot have a negative salary'', NEW.empname; END IF; -- Καταχώρησε ποιος έκανε την αλλαγή στον μισθό NEW.last_date := ''now''; NEW.last_user := current_user; RETURN NEW; END; $$ LANGUAGE 'plpgsql'; Δρ. Κεραμόπουλος Ευκλείδης 25
CREATE TRIGGER emp_stamp BEFORE INSERT OR UPDATE ON emp FOR EACH ROW EXECUTE PROCEDURE emp_stamp(); insert into emp(empid, salary) values (1, 100); ERROR: empname cannot be NULL value SQL state: P0001 insert into emp(empid, empname) values (2, 'George'); ERROR: George cannot have NULL salary SQL state: P0001 insert into emp(empid, empname,salary) values (3, 'George', -100); ERROR: George cannot have a negative salary SQL state: P0001 insert into emp(empid, empname,salary) values (4, 'George', 100); Query returned successfully: 1 rows affected, 0 ms execution time. Δρ. Κεραμόπουλος Ευκλείδης 26
CREATE TABLE emp2 ( empname varchar(20) NOT NULL primary key, salary integer ); CREATE TABLE emp_audit ( operation char(1) NOT NULL, stamp timestamp NOT NULL primary key, userid varchar(20) NOT NULL, empname varchar(20) NOT NULL, salary integer ); O πίνακας Log File Δρ. Κεραμόπουλος Ευκλείδης 28
CREATE OR REPLACE FUNCTION process_emp_audit() RETURNS TRIGGER AS $$ BEGIN IF (TG_OP = 'DELETE') THEN INSERT INTO emp_audit SELECT 'D', now(), user, OLD.*; RETURN OLD; ELSIF (TG_OP = 'UPDATE') THEN INSERT INTO emp_audit SELECT 'U', now(), user, NEW.*; RETURN NEW; ELSIF (TG_OP = 'INSERT') THEN INSERT INTO emp_audit SELECT 'I', now(), user, NEW.*; RETURN NEW; END IF; RETURN NULL; END; $$ LANGUAGE plpgsql; Δρ. Κεραμόπουλος Ευκλείδης 29
CREATE TRIGGER emp_audit AFTER INSERT OR UPDATE OR DELETE ON emp2 FOR EACH ROW EXECUTE PROCEDURE process_emp_audit(); Δρ. Κεραμόπουλος Ευκλείδης 30
insert into emp2(empname, salary) values ('John', 10000); insert into emp2(empname, salary) values ('Maria', 10000); delete from emp2 where empname = Maria'; update emp2 set salary = salary * 1.1 where empname = 'John'; Δρ. Κεραμόπουλος Ευκλείδης 31
Δρ. Κεραμόπουλος Ευκλείδης 32
CREATE OR REPLACE FUNCTION check_shipment_addition () RETURNS TRIGGER AS $$ DECLARE id_number INTEGER; book_isbn TEXT; BEGIN SELECT id INTO id_number FROM customers WHERE id = NEW.customer_id; IF NOT FOUND THEN RAISE EXCEPTION ''Invalid customer ID number.''; END IF; SELECT isbn INTO book_isbn FROM editions WHERE isbn = NEW.isbn; IF NOT FOUND THEN RAISE EXCEPTION ''Invalid ISBN.''; END IF; IF TG_OP = ''INSERT'' THEN UPDATE stock SET stock = stock -1 WHERE isbn = NEW.isbn; END IF; RETURN NULL; END; $$ LANGUAGE 'plpgsql'; Δρ. Κεραμόπουλος Ευκλείδης 34
CREATE TRIGGER check_shipment BEFORE INSERT OR UPDATE ON shipments FOR EACH ROW EXECUTE PROCEDURE check_shipment_addition(); Δρ. Κεραμόπουλος Ευκλείδης 35
Και τα εναύσματα και οι περιορισμοί χρησιμοποιούνται για τον ίδιο λόγο. Να διατηρείται η ακεραιότητα των δεδομένων Ο περιορισμός δεν επεξεργάζεται δεδομένα και εξασφαλίζει την ακεραιότητα των δεδομένων από οποιαδήποτε επεξεργασία. Το έναυσμα πρέπει να ενεργοποιηθεί για να προστατέψει τα δεδομένα. Από τη άλλη πλευρά είναι πιο ευέλικτο. Δρ. Κεραμόπουλος Ευκλείδης 36
ΕΠΟΜΕΝΗ ΕΝΟΤΗΤΑ