Veri Tabanı Yönetim Sistemleri 2 Ders 7 Paket ve Tetikleyiciler Yrd. Doç. Dr. Altan MESUT Trakya Üniversitesi Bilgisayar Mühendisliği Bölümü
Paket (Package) Birbiriyle ilişkili olan prosedürlerin, fonksiyonların, değişkenlerin ve diğer yapıların bir bütün haline getirildiği ve veritabanında saklandığı yapıdır. Bir global değişkenin tanımlanıp paket içindeki herhangi bir prosedürde kullanılabilmesi gibi ekstra özellikler sağlar. Ayrıca paketler bir bütün halinde bir kerede parse edilip, derlenip, belleğe yüklendiği için performans artışı da sağlar. Paketlerde tanımlama (specification) ve gövde (body) olmak üzere iki kısım bulunur. Gerektiğinde tanımlama kısmına dokunulmadan sadece gövde kısmı tekrar derlenebilir. Paketi kullanan ve sadece tanımlama kısmını görebilen (encapsulation) uygulamaların tekrar derlenmesine gerek yoktur. Paketler hakkında detaylı bilgi için: Database Programming with PL/SQL, Section 10
Paket Örneği CREATE PACKAGE emp_actions AS -- package specification PROCEDURE hire_employee (empno NUMBER, ename CHAR,...); PROCEDURE fire_employee (emp_id NUMBER); END emp_actions; CREATE PACKAGE BODY emp_actions AS -- package body PROCEDURE hire_employee (empno NUMBER, ename CHAR,...) IS BEGIN INSERT INTO emp VALUES (empno, ename,...); END hire_employee; PROCEDURE fire_employee (emp_id NUMBER) IS BEGIN DELETE FROM emp WHERE empno = emp_id; END fire_employee; END emp_actions; Eğer değişken, prosedür veya fonksiyon tanımlarından önce Public sözcüğü kullanılırsa bu yapılar paketin dışından da çağrılabilir/kullanılabilir.
Aşırı Yükleme (Overloading) NYP dersinden hatırlayacağınız aşırı yükleme kavramı PL/SQL’de de vardır. Yani aynı paket içinde aynı isimde fonksiyonların veya prosedürlerin kullanılabilmesi mümkündür. Parametrelerin sayısının veya veri türlerinin farklı olması gerektiğini biliyoruz. Burada dikkat edilecek olan NUMBER ile INTEGER, VARCHAR2 ile CHAR aynı tür olarak kabul edilir. CREATE OR REPLACE PACKAGE emp_pkg IS PROCEDURE find_emp -- 1 (p_employee_id IN NUMBER, p_last_name OUT VARCHAR2); PROCEDURE find_emp -- 2 (p_job_id IN VARCHAR2, p_last_name OUT VARCHAR2); PROCEDURE find_emp -- 3 (p_hiredate IN DATE, p_last_name OUT VARCHAR2); END emp_pkg;
STANDARD Paketi Oracle’da tanımlı olan TO_CHAR, TO_DATE, UPPER, … gibi tüm hazır fonksiyonlar STANDARD paketinde bulunur. Eğer Oracle STANDARD paketinde bulunan bir fonksiyon ile aynı isimde bir fonksiyon yaratırsanız, kendi fonksiyonunuzu kullanmak için öncesinde kendi şemanızın ismini vermeniz gerekir: BEGIN v_deger := şema_adı.UPPER(parametre); END;
Forward Declaration C dilinde olduğu gibi paket gövdesinde yazdığınız bir belirleyicinin (değişken, prosedür veya fonksiyon ismi) kullanılabilmesi için önceden tanımlanmış olması gerekir.
Tetikleyici (Trigger) Sisteme bir kullanıcının bağlanması, bir tablo yaratılması veya tanımında değişiklik yapılması, tablo veya görüntü üzerinde bir DML ifadesinin değişiklik yapması gibi belirli bir olay ile bağdaştırılan PL/SQL bloğudur. Bağdaştırılan olay gerçekleştiğinde bu blok otomatik olarak tetiklenir (C#, VB gibi olay güdümlü dillerde olduğu gibi). Prosedür ve fonksiyonlar gibi tetikleyiciler de veri tabanında saklanır. Detaylı bilgi için: Database Programming with PL/SQL, Section 13
DML Tetikleyici Veri tabanında bir DML işlemi gerçekleştiğinde otomatik olarak verilen PL/SQL bloğunu çalıştıran tetikleyici türüdür. Bir olaydan (insert, delete ya da update ifadelerin belirtilen tabloda oluşması) ve bir hareketten (ilgili prosedür) oluşur. Örneğin; personel tablosundan bir kaydın silinmesi olayı gerçekleştiğinde, eski_personel tablosuna personelin numarasını ve işten ayrılma tarihini belirtmek için o anki tarihi kaydeden bir prosedür yazılması ile bir tetikleyici oluşturulabilir.
DML Tetikleyici Yaratma Tetikleme Zamanı: – BEFORE / AFTER: DML ifadesinden önce / sonra tetiklenmesi – INSTEAD OF: DML’in yerine bloğu çalıştırır, DML gerçekleşmez Olay: INSERT, DELETE veya UPDATE [of Sütun Adı] olabilir FOR EACH ROW: Etkilenen her satır için bloğu tekrar çalıştırır WHEN: Belirli bir koşul oluştuğunda bloğu çalıştırır CREATE [or REPLACE] TRIGGER Trigger Adı Tetikleme Zamanı Olay1 [OR Olay2 OR Olay3] ON Tablo veya Görüntü Adı [FOR EACH ROW] [WHEN Koşul] BEGIN PL/SQL Bloğu END;
DML İfade Bazlı Tetikleyici Örneği CREATE TRIGGER HaftaSonundaEngelleme BEFORE INSERT OR DELETE OR UPDATE ON Personel BEGIN IF TO_CHAR(SYSDATE,'DY') IN ('SAT','SUN') THEN RAISE_APPLICATION_ERROR(-20500, 'Personel tablosunda sadece çalışma' || ' saatlerinde değişiklik yapılabilir'); END IF; END;
DML Satır Bazlı Tetikleyici Örneği Etkilenen her satır için aşağıdaki blok tekrar çalışacak (satır bazlı tetikleyici) Ledger tablosuna ekleme yapılmadan önce yeni değerler, güncelleme yapılmadan önce ise eski değerler LedgerAudit tablosuna eklenir.
DML Tetikleyiciler Hakkında Notlar Eski ve yeni değerleri ifade eden :OLD ve :NEW sadece satır bazlı tetikleyiciler ile kullanılır. Ekleme işleminde sadece yeni değer, silme işleminde sadece eski değer, güncelleme işleminde ise ikisi birden vardır. :OLD ve :NEW yerine :eski ve :yeni gibi farklı isimler kullanılması istenirse FOR EACH ROW öncesinde aşağıdaki gibi bir ifade yazılır: – REFERENCING OLD AS eski NEW AS yeni Bir DML ifadesi tarafından değiştirilmekte olan bir tablo üzerinde satır tetikleyiciler sorgu veya değişiklik yapamaz (ifade tetikleyiciler yapabilir). – Derleme sırasında hata vermese de tetiklendiği anda "table … is mutating, trigger/function may not see it" hatasını verir.
DDL Tetikleyici DDL ifadelerinden biri yürütüldüğünde tetiklenen türdür. Tetikleme Zamanı: BEFORE, AFTER veya INSTEAD OF olabilir. Olay: CREATE, DROP veya ALTER olabilir. ON SCHEMA sadece kendi şemanızdaki, ON DATABASE ise tüm şemalardaki nesneler üzerindeki DDL işlemlerinde tetiklenir. CREATE [or REPLACE] TRIGGER Trigger Adı Tetikleme Zamanı Olay1 [OR Olay2 OR Olay3] ON {DATABASE|SCHEMA} BEGIN PL/SQL Bloğu END;
DDL Tetikleyici Örnekleri CREATE TRIGGER log_create_trigg AFTER CREATE ON SCHEMA BEGIN INSERT INTO log_table VALUES (USER, SYSDATE); END; CREATE TRIGGER prevent_drop_trigg BEFORE DROP ON SCHEMA BEGIN RAISE_APPLICATION_ERROR (-20203, 'Attempted drop – failed'); END; Bir veritabanı nesnesi yaratıldıktan sonra log tablosuna bilgi ekler Bir veritabanı nesnesi silinmek istendiğinde engel olur
Veritabanı Olay Tetikleyicileri Bir kullanıcının veritabanına bağlanması veya çıkış yapması, veritabanının açılması veya kapanması, belirli bir exception çağrılması gibi durumlarda da tetiklenen türdür. Yaratılması DDL Tetikleyici ile benzerdir. – ON SCHEMA yazılması sadece kendi oturumunuzdaki olaylarda, ON DATABASE yazılması ise tüm oturumlardaki olaylarda tetiklenmesini sağlar.
LOGON ve LOGOFF Tetikleyici Örnekleri CREATE TRIGGER logon_trigg AFTER LOGON ON DATABASE BEGIN INSERT INTO log_table(user_id,log_date,action) VALUES (USER, SYSDATE, 'Bağlandı'); END; CREATE TRIGGER logoff_trigg BEFORE LOGOFF ON SCHEMA BEGIN INSERT INTO log_table(user_id,log_date,action) VALUES (USER, SYSDATE, 'Çıkış Yaptı'); END; Sisteme bağlanan her kişi için ID’si, bağlanma tarihi ve ilgili mesajı log tablosuna kaydeder Sistemden çıkan her kişi için ID’si, bağlanma tarihi ve ilgili mesajı log tablosuna kaydeder
SERVERERROR Tetikleyici Örneği CREATE TRIGGER servererror_trig AFTER SERVERERROR ON SCHEMA BEGIN IF (IS_SERVERERROR (942)) THEN INSERT INTO error_log_table... END IF; END;
Tetikleyicilerin Durumunu Değiştirme Tetikleyiciyi devre dışı bırakmak için DISABLE, tekrar aktif hale getirmek için ENABLE kullanımı: ALTER TRIGGER trigger_adı DISABLE | ENABLE; Bir tabloya ait tüm tetikleyicilerin aynı anda devre dışı bırakılması: ALTER TABLE tablo_adı DISABLE ALL TRIGGERS; Tetikleyicinin tekrar derlenmesi: ALTER TRIGGER trigger_adı COMPILE;
Tetikleyiciler Hakkında Notlar Tetikleyici yaratabilmek için sadece CREATE TRIGGER sistem yetkisine sahip olmak yeterli değildir. Tetikleyicinin ilişkili olduğu tablo üzerinde ALTER yetkisine de sahip olunmalıdır. Yaratılan tetikleyiciler hakkında detaylı bilgi için USER_TRIGGERS veri sözlüğü görüntüsü kullanılabilir. Tetikleyici içinde COMMIT veya ROLLBACK yapılamaz (prosedürlerde yapılabiliyordu) CHECK constraint ile kolaylıkla sağlanabilecek maaşın 1000’den fazla olması gibi bir kısıtlama için tetikleyici kullanılırsa daha yavaş çalışır. Fakat bir personelin maaşının azaltılamamasını sağlamak için tetikleyici gerekir
Personelin maaşının eski maaşından ve 1000’den az olamamasını sağlayan tetikleyici CREATE OR REPLACE TRIGGER check_salary BEFORE UPDATE OF salary ON employees FOR EACH ROW WHEN (NEW.salary < OLD.salary OR NEW.salary < 1000) BEGIN RAISE_APPLICATION_ERROR (-20508, 'Do not decrease salary.'); END;