postgres create trigger after insert but before delete? - postgresql

I want to call a stored procedure in three different cases: after an insert, after an update and before a delete. Is it possible to combine these cases into one create trigger statement? Like so (I know, this won't work):
CREATE TRIGGER update_pntzzz3
AFTER INSERT OR UPDATE OR BEFORE DELETE ON onedee
FOR EACH ROW
EXECUTE PROCEDURE update_pntzzz3();
Right now I create a new trigger for the delete case.
CREATE TRIGGER update_pntzzz3
AFTER INSERT OR UPDATE ON onedee
FOR EACH ROW
EXECUTE PROCEDURE update_pntzzz3();
CREATE TRIGGER del_pntzzz3
BEFORE DELETE ON onedee
FOR EACH ROW
EXECUTE PROCEDURE update_pntzzz3();

Related

Postgres concurrent transactions unexpected issue

When the following transaction is run concurrently on different connections it sometimes errors with
trigger "my_trigger" for relation "my_table" already exists
What am I doing wrong?
BEGIN;
DROP TRIGGER IF EXISTS my_trigger ON my_table;
CREATE TRIGGER my_trigger
AFTER INSERT ON my_table
REFERENCING NEW TABLE AS new_table
FOR EACH STATEMENT EXECUTE PROCEDURE my_function();
COMMIT;
I am trying to set up a system where I can add triggers to notify about data changes in specific tables. If a table already has such a trigger then skip it. Otherwise CREATE all CRUD triggers. This logic needs to run sequentially in case of concurrent requests.
After trying ISOLATION LEVEL SERIALIZABLE I noticed that any conflicting transactions are failed and dropped (I would need to manually check sql status and retry). But what I want is to queue up these transactions and run afterwards one by one in the order they're sent.
At the moment I am trying to achieve this by having a my_triggers (table_name TEXT) table that has a BEFORE INSERT OR DELETE trigger. Within this trigger I do the actual table trigger upsert logic. Inserts or deletes on my_triggers are made with LOCK TABLE my_triggers IN ACCESS EXCLUSIVE MODE ... which should queue up conflicting CRUD transactions ?!
What happens is following:
BEGIN....DROP TRIGGER IF EXISTS....CREATE TRIGGER....COMMIT;
..BEGIN....DROP TRIGGER IF EXISTS....CREATE TRIGGER--------EXCEPTION.
Both transactions starts when trigger is not present.
Both succeed in drop trigger because of "IF EXISTS" statement.
First transaction starts creating a trigger. For that a SHARE ROW EXCLUSIVE lock is placed on table my_table. The lock SHARE ROW EXCLUSIVE conflicts with it self so no other transaction is allowed to create a trigger until the first one completes.
Second transaction blocks on CREATE TRIGGER.
First transaction completes.
Second transaction proceeds with CREATE TRIGGER but it already exists. Exception is raised.
What you need is adding a LOCK before DROP TRIGGER statement. This way you will ensure the trigger is dropped and not created in concurrent transaction.
BEGIN;
LOCK TABLE my_table IN SHARE ROW EXCLUSIVE MODE ;
DROP TRIGGER IF EXISTS my_trigger ON my_table;
CREATE TRIGGER my_trigger
AFTER INSERT ON my_table
REFERENCING NEW TABLE AS new_table
FOR EACH STATEMENT EXECUTE PROCEDURE my_function();
COMMIT;

How to delete all the triggers and procedures from a single table?

I am working on a problem where I need to rename the table name. The table has few triggers and procedures attach to it.
My steps to do that:
Delete all the triggers and procedures of the table name employee.
Rename table name(employee) to user using ALTER command.
Then create all the triggers and procedures according to the new table.
Database I am using is postgresql.
Below query is used to delete the single trigger on a table.
DROP TRIGGER IF EXISTS update_employee_changes on employee;
But I want to delete all the triggers and procedures related to the given table in a single query.
You don't have to drop the triggers and functions. Just use a transaction:
BEGIN;
ALTER TABLE ... RENAME TO ...;
CREATE OR REPLACE FUNCTION /* function that uses the new name */
...
COMMIT;
You only have to replace the trigger functions and other functions. Triggers, views etc. don't have to be modified.

insert values on trigger in temporal tables in postgres

So I am new to using procedures and triggers and it is really confusing me
I have used temporal tables and want to basically create a history table of records inserted,updated or deleted.
Infact I have created my history table and works fine when I use this trigger sql
DROP TRIGGER if exists versioning_trigger on mytable;
CREATE TRIGGER versioning_trigger BEFORE INSERT OR UPDATE OR DELETE ON mytable FOR EACH ROW EXECUTE PROCEDURE versioning('sys_period', 'table_history', true);
This creates records of the rows updated or deleted,precisely copies the old row record from mytable into table_history table and updates the record in mytable.But I want to insert the updated record from mytable to table_history also so that it has records of all types('current active record'and 'record before updation').Also insert some other fields in table_history when the trigger is executed.
I want to ask
How is it possible to have different trigger events(BEFORE or AFTER) together in one CREATE TRIGGER query in temporal_tables?
Is it possible to insert new field values in table_history on trigger execution? How can I accomplish this?
https://www.postgresql.org/docs/current/static/plpgsql-trigger.html
A trigger procedure is created with the CREATE FUNCTION command,
declaring it as a function with no arguments and a return type of
trigger
and also
same trigger can't fire both before and after event - just create two triggers if you really need it
https://www.postgresql.org/docs/current/static/sql-createtrigger.html
Determines whether the function is called before, after, or instead of
the event.
use NEW instead of OLD for new values
https://www.postgresql.org/docs/current/static/plpgsql-trigger.html
NEW
Data type RECORD; variable holding the new database row for
INSERT/UPDATE operations in row-level triggers. This variable is
unassigned in statement-level triggers and for DELETE operations.

Inserted row in PostgreSQL are not available in trigger function

database : postgresql
language : plpythonu
topic: trigger function
create trigger request_received_trigger
after insert on req_table
for each row
execute procedure request_received_function();
I need to do something after every insert but the inserted record dose not appear in queries that I make inside request_received_function(). Is inserted record locked inside trigger function?
trigger fires well and I can debug it
on the second insert record is show itself

How to send values from the changed row to a trigger in postgres?

I want to create a trigger, somehow like this:
CREATE TRIGGER foo
AFTER UPDATE OR INSERT ON bar
FOR EACH ROW EXECUTE PROCEDURE baz(NEW.id);
The part with NEW.id doesn't work. How can I send values from the changed row (id for instance) to the trigger-function.
The trigger function (procedure) knows NEW and OLD automatically. No need to pass those as parameters.
Read more in the chapter on Trigger Procedures in the manual:
When a PL/pgSQL function is called as a trigger, several special
variables are created automatically in the top-level block. They are:
NEW
Data type RECORD; variable holding the new database row for INSERT/UPDATE operations in row-level triggers. This variable is NULL
in statement-level triggers and for DELETE operations.