PostgreSQL'de trigger oluşturmak iki adımdır: önce RETURNS trigger tipinde, argümansız bir trigger fonksiyonu yazarsınız (genellikle PL/pgSQL ile), sonra CREATE TRIGGER ad BEFORE|AFTER|INSTEAD OF olay ON tablo FOR EACH ROW|STATEMENT EXECUTE FUNCTION fonksiyon() komutuyla onu bir tabloya ya da view'e bağlarsınız. Satır düzeyindeki trigger fonksiyonu içinde değişen satıra NEW ve OLD değişkenleriyle, işlemin türüne TG_OP ile erişirsiniz.
Bu yazıda trigger türlerini ve zamanlamayı, BEFORE trigger ile veri doğrulama ve düzeltme, AFTER trigger ile denetim (audit) tablosu, transition table ile komut düzeyinde özet, view üzerinde INSTEAD OF trigger, WHEN koşulu, UPDATE OF, trigger argümanları, sıralama kuralları ve kısaca event trigger konularını çalışan örneklerle ele alıyoruz. PL/pgSQL dilinin kendisi PL/pgSQL temelleri yazısında; seri PostgreSQL öğrenme rehberinde toplanıyor.
Trigger türleri: ne zaman ve kaç kez?

Kılavuz bir trigger'ı, belirli bir işlem yapıldığında veritabanının bir fonksiyonu kendiliğinden çalıştırması için yapılan tanım olarak açıklar. Trigger'lar tablolara (bölümlenmiş olsun ya da olmasın), view'lere ve yabancı tablolara bağlanabilir. İki eksende sınıflandırılırlar:
- Zaman:
BEFORE(işlemden önce, kısıtlar denetlenmeden),AFTER(işlem ve kısıt denetimi tamamlandıktan sonra) veyaINSTEAD OF(işlemin yerine, yalnızca view'lerde). - Düzey:
FOR EACH ROWdeğişen her satır için bir kez;FOR EACH STATEMENTkomut başına bir kez. Hiçbiri yazılmazsaFOR EACH STATEMENTvarsayılır. Sıfır satır değiştiren bir komut bile komut düzeyindeki trigger'ları çalıştırır.
Olay olarak INSERT, UPDATE (isteğe bağlı sütun listesiyle), DELETE ve TRUNCATE kullanılabilir; birden çok olay OR ile birleştirilir. TRUNCATE trigger'ları yalnızca komut düzeyinde olabilir. SELECT satır değiştirmediği için SELECT trigger'ı yoktur. MERGE için de ayrı trigger tanımlanmaz; MERGE yaptığı işlemlere göre INSERT, UPDATE ve DELETE trigger'larını çalıştırır.
| Zaman | Olay | Satır düzeyi | Komut düzeyi |
|---|---|---|---|
| BEFORE | INSERT/UPDATE/DELETE | Tablolar ve yabancı tablolar | Tablolar, view'ler, yabancı tablolar |
| BEFORE | TRUNCATE | Yok | Tablolar ve yabancı tablolar |
| AFTER | INSERT/UPDATE/DELETE | Tablolar ve yabancı tablolar | Tablolar, view'ler, yabancı tablolar |
| AFTER | TRUNCATE | Yok | Tablolar ve yabancı tablolar |
| INSTEAD OF | INSERT/UPDATE/DELETE | View'ler | Yok |
Bir trigger her zaman onu tetikleyen komutla aynı transaction içinde çalışır; komut veya trigger hata verirse ikisinin etkileri birlikte geri alınır. Trigger fonksiyonu ise trigger'dan önce tanımlanmış olmalı, argümansız olmalı ve trigger tipini döndürmelidir. Kılavuza göre trigger fonksiyonu düz SQL fonksiyon diliyle yazılamaz; PL/pgSQL gibi prosedürel bir dil ya da C kullanılır. Aynı fonksiyon birden çok trigger tarafından paylaşılabilir.
Trigger fonksiyonundaki özel değişkenler
PL/pgSQL fonksiyonu trigger olarak çağrıldığında en dış blokta şu değişkenler kendiliğinden tanımlanır:
| Değişken | İçerik |
|---|---|
| NEW | INSERT/UPDATE için yeni satır (satır düzeyi); komut düzeyinde ve DELETE'te NULL |
| OLD | UPDATE/DELETE için eski satır (satır düzeyi); komut düzeyinde ve INSERT'te NULL |
| TG_OP | INSERT, UPDATE, DELETE veya TRUNCATE |
| TG_WHEN | BEFORE, AFTER veya INSTEAD OF |
| TG_LEVEL | ROW veya STATEMENT |
| TG_NAME | Çalışan trigger'ın adı |
| TG_TABLE_NAME, TG_TABLE_SCHEMA | Trigger'ı tetikleyen tablo ve şeması |
| TG_NARGS, TG_ARGV | CREATE TRIGGER içinde verilen argüman sayısı ve dizisi (0'dan başlar) |
TG_RELNAME da hâlâ vardır ama kılavuz onu kullanımdan kalkmış sayar ve TG_TABLE_NAME kullanmanızı önerir. TG_ARGV dizisinde geçersiz bir indeks NULL döndürür.
Dönüş değeri kuralları
Trigger fonksiyonu ya NULL ya da tetiklendiği tablonun yapısında bir satır döndürmelidir. Dönüş değerinin anlamı trigger türüne göre değişir ve en çok hata buradan çıkar:
- BEFORE ROW:
NULLdöndürürse o satır için işlem atlanır (sonraki trigger'lar da çalışmaz).NEWdöndürürse işlem bu satırla devam eder;NEWüzerinde yaptığınız değişiklikler yazılacak satırı değiştirir.DELETEiçin genel kalıpOLDdöndürmektir; çünküDELETE'teNEWzatenNULL'dır ve onu döndürmek silmeyi atlar. - AFTER ROW ve tüm komut düzeyi trigger'lar: dönüş değeri yok sayılır,
NULLdöndürmek yeterlidir. Yine de hata yükselterek tüm işlemi iptal edebilirler. - INSTEAD OF: değişikliği gerçekten yaptıysa
NEW(silmedeOLD) döndürmeli;NULLdöndürürse satır yapılmamış sayılır ve etkilenen satır sayısına eklenmez.
BEFORE trigger: doğrulama ve satırı düzeltme

Kılavuz, satır düzeyindeki BEFORE trigger'ları eklenecek veya güncellenecek veriyi denetlemek ya da değiştirmek için tipik araç olarak tanımlar; örneğin bir zaman damgası sütununu doldurmak veya satırdaki iki alanın tutarlılığını kontrol etmek. Aşağıdaki trigger ürün adını kırpıp baş harflerini büyütüyor, fiyatı doğruluyor ve güncellenme zamanını yazıyor:
CREATE TABLE urun (
id integer GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
ad text NOT NULL,
fiyat numeric(10,2) NOT NULL,
guncellenme timestamptz
);
CREATE FUNCTION urun_hazirla() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
NEW.ad := initcap(btrim(NEW.ad));
IF NEW.fiyat <= 0 THEN
RAISE EXCEPTION 'Fiyat pozitif olmalı (ürün: %)', NEW.ad;
END IF;
NEW.guncellenme := now();
RETURN NEW;
END
$$;
CREATE TRIGGER urun_hazirla
BEFORE INSERT OR UPDATE ON urun
FOR EACH ROW EXECUTE FUNCTION urun_hazirla();
INSERT INTO urun (ad, fiyat) VALUES (' bakır cezve ', 540), ('çay tabağı', 30);
SELECT id, ad, fiyat, guncellenme IS NOT NULL AS damgali FROM urun ORDER BY id;
INSERT INTO urun (ad, fiyat) VALUES ('hatalı ürün', 0); id | ad | fiyat | damgali
----+-------------+--------+---------
1 | Bakır Cezve | 540.00 | t
2 | Çay Tabağı | 30.00 | t
(2 rows)
ERROR: Fiyat pozitif olmalı (ürün: Hatalı Ürün)
CONTEXT: PL/pgSQL function urun_hazirla() line 5 at RAISEBaştaki ve sondaki boşluklar silindi, adlar düzeltildi ve damga yazıldı. Sıfır fiyatlı satır RAISE EXCEPTION ile reddedildi; aynı komuttaki diğer satırlar da geri alınır, çünkü trigger komutla aynı transaction'dadır. Bu örnekteki ad dönüşümü kümenin varsayılan sıralama kuralına (burada builtin C.UTF-8) göre yapıldı; Türkçe harflerin büyük/küçük dönüşümünde collation farkları collation ve Türkçe sıralama yazısında.
Üretilen sütunlarla ilgili bir ayrıntı: saklanan (stored) üretilen sütunlar BEFORE trigger'lardan sonra, AFTER trigger'lardan önce hesaplanır. Bu yüzden BEFORE trigger'da NEW içindeki üretilen değer henüz güncel değildir ve ona yapılan değişiklikler yok sayılır. Sanal (virtual) üretilen sütunlar trigger çalışırken hiç hesaplanmaz. PostgreSQL 18'de sanal üretilen sütunların varsayılan olduğu düşünülürse, trigger içinde üretilen sütuna güvenmeyin; konu CREATE TABLE ve ALTER TABLE yazısında.
AFTER trigger: denetim (audit) tablosu
Satır düzeyindeki AFTER trigger'lar, kılavuza göre değişiklikleri başka tablolara yaymak ya da başka tablolarla tutarlılık denetimi yapmak için en uygun yerdir; çünkü AFTER trigger satırın son hâlini gördüğünden emin olabilir, oysa bir BEFORE trigger'dan sonra başka BEFORE trigger'lar çalışıp satırı değiştirebilir. Aşağıdaki genel amaçlı fonksiyon her değişikliği eski ve yeni satırın JSON hâliyle bir denetim tablosuna yazıyor; TG_TABLE_NAME sayesinde aynı fonksiyon başka tablolarda da kullanılabilir.
CREATE TABLE denetim (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
tablo text NOT NULL,
islem text NOT NULL,
kullanici text NOT NULL DEFAULT current_user,
eski jsonb,
yeni jsonb
);
CREATE FUNCTION denetim_yaz() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
IF TG_OP = 'DELETE' THEN
INSERT INTO denetim (tablo, islem, eski)
VALUES (TG_TABLE_NAME, TG_OP, to_jsonb(OLD));
ELSIF TG_OP = 'UPDATE' THEN
INSERT INTO denetim (tablo, islem, eski, yeni)
VALUES (TG_TABLE_NAME, TG_OP, to_jsonb(OLD), to_jsonb(NEW));
ELSE
INSERT INTO denetim (tablo, islem, yeni)
VALUES (TG_TABLE_NAME, TG_OP, to_jsonb(NEW));
END IF;
RETURN NULL; -- AFTER trigger: dönüş değeri yok sayılır
END
$$;
CREATE TRIGGER urun_denetim
AFTER INSERT OR UPDATE OR DELETE ON urun
FOR EACH ROW EXECUTE FUNCTION denetim_yaz();
UPDATE urun SET fiyat = 35 WHERE ad = 'Çay Tabağı';
DELETE FROM urun WHERE ad = 'Bakır Cezve';
SELECT id, tablo, islem, eski->>'fiyat' AS eski_fiyat, yeni->>'fiyat' AS yeni_fiyat
FROM denetim ORDER BY id; id | tablo | islem | eski_fiyat | yeni_fiyat
----+-------+--------+------------+------------
1 | urun | UPDATE | 30.00 | 35.00
2 | urun | DELETE | 540.00 |
(2 rows)UPDATE satırında eski ve yeni fiyat, DELETE satırında yalnızca eski fiyat var. to_jsonb(OLD) satırın tamamını tek bir JSON değeri olarak saklar; sorgulama ayrıntıları JSONB kullanımı yazısında. Kılavuz bir performans notu da düşer: BEFORE ya da AFTER seçmek için özel bir nedeniniz yoksa BEFORE daha verimlidir, çünkü işlem bilgisinin komut sonuna kadar saklanması gerekmez. Denetim kaydı gibi satırın kesin son hâline ihtiyaç duyan işler için ise AFTER doğru seçimdir.
Rol ile ilgili bir PostgreSQL 18 değişikliği burada önemlidir. Sürüm notlarına göre AFTER trigger'lar artık trigger olayının kuyruğa alındığı andaki rol ile çalışır; önceden, trigger'ın çalıştığı andaki rol (örneğin COMMIT anı) kullanılıyordu. Kılavuzun genel kuralı da aynıdır: trigger fonksiyonu SECURITY DEFINER değilse, olayı kuyruğa alan rolün yetkileriyle çalışır. Denetim tablosundaki current_user değeri bu kurala göre belirlenir. Sürüm ayrıntıları PostgreSQL 18 yenilikleri yazısında.
Transition table: komut düzeyinde tüm satırları görmek
Komut düzeyindeki trigger'lar varsayılan olarak tek tek satırları göremez. AFTER trigger'larda REFERENCING NEW TABLE AS ad veya OLD TABLE AS ad yazarak komutun eklediği, güncellediği veya sildiği tüm satırları içeren salt okunur geçiş tabloları (transition relation) isteyebilirsiniz. Bu özellik yalnızca sıradan tablolardaki AFTER trigger'larda kullanılabilir; UPDATE OF sütun listesiyle ve birden çok olayla birlikte kullanılamaz.
CREATE FUNCTION toplu_ozet() RETURNS trigger
LANGUAGE plpgsql
AS $$
DECLARE
adet integer;
ortalama numeric;
BEGIN
SELECT count(*), round(avg(fiyat), 2) INTO adet, ortalama FROM yeni_satirlar;
RAISE NOTICE '% komutu % satır ekledi, ortalama fiyat %', TG_OP, adet, ortalama;
RETURN NULL;
END
$$;
CREATE TRIGGER urun_toplu_ozet
AFTER INSERT ON urun
REFERENCING NEW TABLE AS yeni_satirlar
FOR EACH STATEMENT EXECUTE FUNCTION toplu_ozet();
INSERT INTO urun (ad, fiyat)
SELECT 'ürün ' || i, i * 10 FROM generate_series(1, 4) AS i;
INSERT INTO urun (ad, fiyat) SELECT ad, fiyat FROM urun WHERE false;NOTICE: INSERT komutu 4 satır ekledi, ortalama fiyat 25.00
INSERT 0 4
NOTICE: INSERT komutu 0 satır ekledi, ortalama fiyat <NULL>
INSERT 0 0Trigger dört satırlık ekleme için bir kez çalıştı ve geçiş tablosundan özet çıkardı. İkinci INSERT hiç satır eklemediği hâlde trigger yine çalıştı; kılavuzun dediği gibi komut düzeyindeki trigger'lar sıfır satırda da tetiklenir. RAISE, NULL değeri <NULL> olarak yazdı. Binlerce satırlık toplu işlemlerde her satır için ayrı ayrı denetim kaydı yazmak yerine böyle bir komut düzeyi trigger ile tek seferde işlem yapmak daha az çağrı demektir.
INSTEAD OF trigger ile view'i güncellenebilir yapmak
Birden fazla tabloyu birleştiren ya da gruplama yapan bir view otomatik olarak güncellenemez. INSTEAD OF trigger, view'e gelen komutu yakalayıp alttaki tablolara uygun değişikliği yapma görevini üstlenir. Bu trigger'lar yalnızca view'lerde ve yalnızca satır düzeyinde tanımlanabilir ve WHEN koşulu desteklemez.
CREATE TABLE stok (urun_id integer PRIMARY KEY, adet integer NOT NULL);
INSERT INTO stok SELECT id, 10 FROM urun;
CREATE VIEW urun_stok AS
SELECT u.id, u.ad, u.fiyat, s.adet
FROM urun u JOIN stok s ON s.urun_id = u.id;
UPDATE urun_stok SET adet = 0 WHERE id = 2;
CREATE FUNCTION urun_stok_guncelle() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
UPDATE urun SET fiyat = NEW.fiyat WHERE id = OLD.id;
UPDATE stok SET adet = NEW.adet WHERE urun_id = OLD.id;
RETURN NEW;
END
$$;
CREATE TRIGGER urun_stok_guncelle
INSTEAD OF UPDATE ON urun_stok
FOR EACH ROW EXECUTE FUNCTION urun_stok_guncelle();
UPDATE urun_stok SET adet = 0, fiyat = 32.50 WHERE id = 2;
SELECT * FROM urun_stok WHERE id = 2;ERROR: cannot update view "urun_stok"
DETAIL: Views that do not select from a single table or view are not automatically updatable.
HINT: To enable updating the view, provide an INSTEAD OF UPDATE trigger or an unconditional ON UPDATE DO INSTEAD rule.
CREATE FUNCTION
CREATE TRIGGER
UPDATE 1
id | ad | fiyat | adet
----+------------+-------+------
2 | Çay Tabağı | 32.50 | 0
(1 row)Trigger yokken PostgreSQL view'i güncelleyemedi ve ipucu satırında INSTEAD OF UPDATE trigger önerdi. Trigger eklendikten sonra aynı komut iki tabloyu birden güncelledi. Fonksiyon NEW döndürdüğü için komut "UPDATE 1" bildirdi; NULL döndürseydi "UPDATE 0" görürdük. View tarafındaki kurallar view ve materialized view yazısında anlatılıyor.
WHEN, UPDATE OF, argümanlar ve trigger yönetimi
WHEN (koşul) trigger'ın çalışıp çalışmayacağını belirler; satır düzeyinde koşul OLD.sutun ve NEW.sutun değerlerine bakabilir, ancak alt sorgu içeremez. BEFORE trigger'da WHEN kullanmak, aynı koşulu fonksiyonun başında denetlemekten pek farklı değildir. AFTER trigger'da ise fark büyüktür: koşul doğru değilse olay kuyruğa hiç alınmaz ve satır komut sonunda yeniden okunmaz; kılavuz bunun çok satır değiştiren komutlarda belirgin hız kazandırabileceğini belirtir. UPDATE OF sutun ise trigger'ı yalnızca o sütun UPDATE komutunun SET listesinde geçtiğinde çalıştırır.
CREATE FUNCTION fiyat_degisim_notu() RETURNS trigger
LANGUAGE plpgsql
AS $$
BEGIN
RAISE NOTICE '[%] % fiyatı: % -> % (argüman: %)',
TG_NAME, NEW.ad, OLD.fiyat, NEW.fiyat, TG_ARGV[0];
RETURN NULL;
END
$$;
CREATE TRIGGER fiyat_izle
AFTER UPDATE OF fiyat ON urun
FOR EACH ROW
WHEN (OLD.fiyat IS DISTINCT FROM NEW.fiyat)
EXECUTE FUNCTION fiyat_degisim_notu('kampanya');
UPDATE urun SET ad = 'Çay Tabağı Altılı' WHERE id = 2;
UPDATE urun SET fiyat = fiyat WHERE id = 2;
UPDATE urun SET fiyat = 29.90 WHERE id = 2;
SELECT tgname, tgenabled FROM pg_trigger
WHERE tgrelid = 'urun'::regclass AND NOT tgisinternal ORDER BY tgname;
ALTER TABLE urun DISABLE TRIGGER fiyat_izle;
UPDATE urun SET fiyat = 31 WHERE id = 2;
ALTER TABLE urun ENABLE TRIGGER fiyat_izle;UPDATE 1
UPDATE 1
NOTICE: [fiyat_izle] Çay Tabağı Altılı fiyatı: 32.50 -> 29.90 (argüman: kampanya)
UPDATE 1
tgname | tgenabled
-----------------+-----------
fiyat_izle | O
urun_denetim | O
urun_hazirla | O
urun_toplu_ozet | O
(4 rows)
ALTER TABLE
UPDATE 1
ALTER TABLEİlk güncelleme fiyata dokunmadığı için UPDATE OF fiyat trigger'ı tetiklemedi. İkincisi fiyatı SET listesine yazdı ama değeri değiştirmedi; bu kez WHEN koşulu engelledi. Yalnızca üçüncü güncelleme bildirim üretti; TG_ARGV[0] de CREATE TRIGGER içinde verilen 'kampanya' metnini getirdi. Kılavuza göre trigger argümanları metin sabitleridir; sayı yazsanız bile metne çevrilir.
pg_trigger kataloğu trigger'ları listeler; tgenabled sütunundaki O trigger'ın etkin olduğunu gösterir. ALTER TABLE ... DISABLE TRIGGER ile geçici olarak kapatılan trigger son güncellemede bildirim üretmedi. psql'de \d urun komutu da tablonun trigger'larını gösterir. Silmek için DROP TRIGGER ad ON tablo, tanımı değiştirmek için CREATE OR REPLACE TRIGGER kullanılır. Trigger oluşturmak için tabloda TRIGGER yetkisi ve fonksiyonda EXECUTE yetkisi gerekir.
Aynı olay için birden çok trigger varsa, kılavuza göre trigger adlarının alfabetik sırasıyla çalışırlar. BEFORE ve INSTEAD OF trigger'larda her trigger'ın döndürdüğü satır bir sonrakinin girdisi olur; biri NULL döndürürse o satır için işlem bırakılır ve sonraki trigger'lar çalışmaz. Sırayı garanti etmek istiyorsanız adları buna göre seçin. Satır düzeyindeki AFTER trigger'lar komutun sonunda, komut düzeyindeki AFTER trigger'lardan önce çalışır.
Veri görünürlüğü ve zincirleme trigger'lar
Trigger fonksiyonu kendi tablosunu sorguluyorsa görünürlük kurallarını bilmeniz gerekir. Komut düzeyindeki BEFORE trigger komutun hiçbir değişikliğini görmez, AFTER trigger hepsini görür. Satır düzeyindeki BEFORE trigger, tetikleyen değişikliği henüz göremez ama aynı komutun daha önce işlediği satırların değişikliklerini görür; satırların işlenme sırası öngörülemediği için bu dikkat ister. Satır düzeyindeki AFTER trigger çalıştığında komutun tüm değişiklikleri tamamlanmıştır. Bu kurallar yalnızca fonksiyon VOLATILE ise geçerlidir; STABLE veya IMMUTABLE fonksiyonlar çağıran komutun değişikliklerini hiç görmez.
Trigger içinden çalıştırılan SQL komutları başka trigger'ları, hatta aynı trigger'ı yeniden tetikleyebilir. Kılavuz, zincirleme düzeyi için doğrudan bir sınır olmadığını ve sonsuz özyinelemeden kaçınmanın trigger yazarının sorumluluğu olduğunu vurgular. Benzer şekilde, yabancı anahtarın ON DELETE CASCADE gibi eylemleri sıradan UPDATE/DELETE komutlarıyla yapılır ve hedef tablodaki trigger'ları çalıştırır; bu trigger'lar işlemi engellerse veya değiştirirse referans bütünlüğü bozulabilir.
Bölümlenmiş tablolarda ise şunu bilin: üst tabloya satır düzeyinde trigger tanımlamak, her bölümde aynı trigger'ın bir kopyasını oluşturur; sonradan eklenen bölümler de bu kopyayı alır. Üst tabloya yönelik bir komut yalnızca üst tablonun komut düzeyi trigger'larını çalıştırır. Bölümleme için tablo partitioning yazısına bakın.
Event trigger: DDL olaylarına tepki
Sıradan trigger'lar veri değişikliğine bağlıdır; event trigger ise veritabanı düzeyindeki olaylara bağlanır. Desteklenen olaylar login, ddl_command_start, ddl_command_end, table_rewrite ve sql_drop'tur. Fonksiyonu RETURNS event_trigger ile tanımlanır ve event trigger'ı yalnızca süper kullanıcılar oluşturabilir. Kısa bir örnek:
CREATE FUNCTION ddl_bildir() RETURNS event_trigger
LANGUAGE plpgsql
AS $$
DECLARE
k record;
BEGIN
FOR k IN SELECT * FROM pg_event_trigger_ddl_commands() LOOP
RAISE NOTICE 'DDL: % (%)', k.command_tag, k.object_identity;
END LOOP;
END
$$;
CREATE EVENT TRIGGER ddl_bildir ON ddl_command_end
EXECUTE FUNCTION ddl_bildir();
CREATE TABLE kampanya (id integer);
DROP EVENT TRIGGER ddl_bildir;CREATE FUNCTION
CREATE EVENT TRIGGER
NOTICE: DDL: CREATE TABLE (public.kampanya)
CREATE TABLE
DROP EVENT TRIGGERSık yapılan hatalar

En sık görülen iki hatayı küçük bir tabloda deneyelim: NULL döndüren bir BEFORE trigger ve RETURN yazılmamış bir trigger fonksiyonu.
CREATE TABLE deneme (a int);
CREATE FUNCTION f_null() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN RETURN NULL; END $$;
CREATE TRIGGER t_null BEFORE INSERT ON deneme FOR EACH ROW EXECUTE FUNCTION f_null();
INSERT INTO deneme VALUES (1);
DROP TRIGGER t_null ON deneme;
CREATE FUNCTION f_yok() RETURNS trigger LANGUAGE plpgsql AS $$ BEGIN NEW.a := 2; END $$;
CREATE TRIGGER t_yok BEFORE INSERT ON deneme FOR EACH ROW EXECUTE FUNCTION f_yok();
INSERT INTO deneme VALUES (1);
DROP TABLE deneme;CREATE TABLE
CREATE FUNCTION
CREATE TRIGGER
INSERT 0 0
DROP TRIGGER
CREATE FUNCTION
CREATE TRIGGER
ERROR: control reached end of trigger procedure without RETURN
CONTEXT: PL/pgSQL function f_yok()
DROP TABLEİlk INSERT hata vermedi ama "INSERT 0 0" bildirdi: satır sessizce atlandı. İkinci fonksiyon NEW üzerinde değişiklik yaptı ama döndürmeyi unuttu ve çalışma anı hatası aldı. Diğer tipik hatalar:
- BEFORE trigger'da RETURN NEW unutmak: PL/pgSQL fonksiyonu
RETURNolmadan bitemez;NULLdöndürmek ise satırı sessizce atlar ve komut "INSERT 0 0" gibi bir sonuç verir. - DELETE trigger'da NEW döndürmek:
NEWNULL olduğundan silme atlanır;OLDdöndürün. - Trigger'ı LANGUAGE SQL ile yazmaya çalışmak: desteklenmez.
- Trigger fonksiyonuna parametre tanımlamak: fonksiyon argümansız olmalı, değerler
TG_ARGVile gelir. - Kendi tablosunu güncelleyen trigger: aynı trigger'ı yeniden tetikleyip sonsuz döngüye girebilir.
- Sıra varsaymak: aynı olaydaki trigger'lar ada göre alfabetik çalışır, oluşturma sırasına göre değil.
- Her şeyi trigger'a yüklemek: gizli iş mantığı hata ayıklamayı zorlaştırır; basit kurallar için kısıt, toplu işler için komut düzeyi trigger düşünün.
Sık Sorulan Sorular
EXECUTE FUNCTION mı, EXECUTE PROCEDURE mı?
CREATE TRIGGER içinde ikisi eşdeğerdir ama çağrılan şey her durumda bir fonksiyon olmalıdır, procedure değil. Kılavuz PROCEDURE sözcüğünü tarihsel ve kullanımdan kalkmış olarak niteler; EXECUTE FUNCTION yazın.
Bir trigger'ı transaction sonuna erteleyebilir miyim?
Evet, CREATE CONSTRAINT TRIGGER ile. Constraint trigger'lar AFTER ROW olmalıdır ve DEFERRABLE INITIALLY DEFERRED ile transaction sonunda çalışabilir; zamanlamaları SET CONSTRAINTS ile değiştirilebilir.
UPSERT trigger'ları nasıl çalıştırır?
INSERT ... ON CONFLICT DO UPDATE satır düzeyinde önce BEFORE INSERT, gerekirse ardından BEFORE UPDATE trigger'larını çalıştırabilir. Komut düzeyinde ise kılavuz sırayı şöyle verir: BEFORE INSERT, BEFORE UPDATE, AFTER UPDATE, AFTER INSERT. Ayrıntı için UPSERT ve MERGE.
Trigger'daki hatayı nasıl yakalarım?
Trigger fonksiyonu içinde EXCEPTION bloğu kullanabilirsiniz; yakalanmayan hata tetikleyen komutu iptal eder. Ayrıntılar PL/pgSQL hata yakalama yazısında.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: PostgreSQL öğrenme rehberi · PL/pgSQL temelleri · View ve materialized view · PL/pgSQL hata yakalama · JSONB kullanımı