-- create sample tablecreatetabletest_delete ( id int);insert into test_delete (id ) values (1),(2),(3);select*from test_delete;-- creating functioncreate or replacefunctionfn_generic_cancel_op()returns triggerlanguage plpgsqlas$$beginif TG_WHEN ='AFTER'THEN raise exception 'you are not allowed to % rows in %.%', tg_op,tg_table_schema,tg_table_name;endif; raise notice '% on rows in %.% wont happen', tg_op, tg_table_schema, tg_table_name;returnnull; end;$$-- creating trigger : AFTERCREATETRIGGERtrg_disallow_deleteAFTERDELETEON test_deleteFOR EACH ROWEXECUTEPROCEDURE fn_generic_cancel_op();deletefrom test_delete where id =1;-- creating trigger : BEFORECREATETRIGGERtrg_disallow_delete_beforeBEFOREDELETEON test_deleteFOR EACH ROWEXECUTEPROCEDURE fn_generic_cancel_op();deletefrom test_delete where id =1;-- checkingselect*from test_delete;
Disallow truncating
CREATETRIGGERtrg_disallow_truncate_afterAFTERTRUNCATEON test_deleteFOR EACH STATEMENTEXECUTEPROCEDURE fn_generic_cancel_op();CREATETRIGGERtrg_disallow_truncate_beforEBEFORETRUNCATEON test_deleteFOR EACH STATEMENTEXECUTEPROCEDURE fn_generic_cancel_op();
Creating Audit Trigger
To log data changes to tables in a consistent and transparent manner.
Please not that new OLD are not null for DELETE and INSERT triggers.
CREATE OR REPLACEFUNCTIONfn_audit_trigger()RETURNS TRIGGER LANGUAGE PLPGSQLAS$$BEGINDECLARE old_row json=NULL; new_row json=NULL;BEGINIF TG_OP IN ('UPDATE','DELETE') THEN old_row = row_to_json(OLD);ENDIF;IF TG_OP IN ('INSERT','UPDATE') THEN new_row = row_to_json(NEW);ENDIF;INSERT INTO audit_log ( username, add_time, table_name, operation, row_before, row_after )values ( session_user,NOW(), TG_TABLE_SCHEMA ||'.'|| TG_TABLE_NAME, TG_OP, old_row, new_row );RETURN NEW;END; END;$$-- bind triggerCREATETRIGGERtrg_audit_triggerAFTERINSERTORUPDATEORDELETEONauditFOR EACH ROWEXECUTEPROCEDURE fn_audit_trigger();-- Queriesinsert intoaudit(id) values (1),(2),(3);updateauditset id ='100'where id =1;deletefromauditwhere id =2;select*fromaudit;select*from audit_log;
Creating Conditional Triggers
Created by using generic WHEN clause.
With a WHEN clause, you can write some conditions except a subquery
-- sample tableCREATETABLEmytask ( task_id SERIALPRIMARY KEY, task text);-- trigger functionCREATE OR REPLACEFUNCTIONfn_cancel_with_message()RETURNS TRIGGER LANGUAGE PLPGSQLAS$$BEGIN RAISE EXCEPTION '%', TG_ARGV[0];RETURNNULL;END;$$-- function binding to triggerCREATETRIGGERtrg_no_updateBEFOREINSERTORUPDATEORDELETEORTRUNCATEON mytaskFOR EACH STATEMENTWHEN( EXTRACT ('DOW'FROM CURRENT_TIMESTAMP) =5-- 5 means fridayAND CURRENT_TIME >'12:00')EXECUTEPROCEDURE fn_cancel_with_message('NO UPDATE ARE ALLOWED');-- QueriesINSERT INTO mytask (task) values ('task 1'), ('task 2'), ('task 3');
Disallow updating Primary Key of table
createtablepg_table( id serialprimary key, t text);insert into pg_table(t) values ('t1'),('t2');createtriggerdisallow_pk_changeafterupdate of idon pg_tablefor each rowexecuteprocedure fn_generic_cancel_op();update pg_table set id =10where id =1;
Event Triggers
Event triggers are data-specific and not bind or attached to a table
Unlike regular triggers they capture system level DLL events
Event triggers can be BEFORE or AFTER triggers
Trigger function can be written in any language except SQL
Event triggers are disabled in the single user mode and can only be created by a superuser
Syntax : CREATE EVENT TRIGGER trg_name
Before creating an event trigger, we must have a function that the trigger will execute
The function must return a specifi type called EVENT_TRIGGER
This function need not (and may not) return a valuel the return type serivces merely as s signal that the function is to be invoked as an event trigger.
Can we create conditional event trigger ? Yes, using the when clause
Event trigger cannot be executed in an aborted transaction
Event trigger events
when
explaination
ddl_command_start
This event occurs jsut BEFORE a CREATE, ALTER, or DROP DLL command is executed
ddl_command_end
This event occurs just AFTER a create, alter, or drop command has finished executing
table_rewrite
This event occurs just before a table is re written by some action of the commands ALTER TABLE and ALTER TYPE.
sql_drop
This evetn occurs just before the ddl_command_end eevent for the commands that frop database objects
Event trigger variables
TG_TAG : this variable contains the 'TAG' or the command for which the trigger is executed.
TG_EVENT : This variable contains the event name, which can be ddl_command_start, ddl_comman_end, and sql_drop.
Creating an auditing event trigger
CREATETABLEaudit_dll ( audit_ddl_id SERIALPRIMARY KEY, username TEXT, ddl_event TEXT, ddl_command TEXT, ddl_add_time TIMESTAMPTZ);CREATE OR REPLACEFUNCTIONfn_event_audit_ddl()RETURNS EVENT_TRIGGERLANGUAGE PLPGSQLSECURITY DEFINER AS$$BEGININSERT INTO public.audit_dll (username, ddl_event, ddl_command, ddl_add_time)VALUES (session_user, TG_EVENT, TG_TAG, NOW()); RAISE NOTICE 'DDL activity is created';END;$$-- without conditioncreateevent trigger trg_event_audit_ddl_no_condon ddl_command_startexecuteprocedure fn_event_audit_ddl();-- with conditioncreateevent trigger trg_event_audit_ddlon ddl_command_startwhen TAG IN ('CREATE TABLE')executeprocedure fn_event_audit_ddl();
Dont allow anyone to create table between time
CREATE OR REPLACEFUNCTIONfn_event_abort_create_table_func()RETURNS EVENT_TRIGGERLANGUAGE PLPGSQLSECURITY DEFINERAS$$DECLARE current_hour int= EXTRACT ('HOUR'FROMNOW());BEGINIF current_hour between4and16then RAISE EXCEPTION 'tables are not allowed to be created during 9-4';ENDIF;END;$$CREATEEVENT TRIGGER trg_event_create_table_functionON ddl_command_start WHEN TAG IN ('CREATE TABLE')EXECUTEPROCEDURE fn_event_abort_create_table_func();