Postgresql Triggers: switch from after to before the trigger dont fire - postgresql

i have this simple plpgsql function:
CREATE FUNCTION "update_times" () RETURNS trigger AS '
BEGIN
NEW.update_time = NOW();
RETURN NEW;
END;'
LANGUAGE "plpgsql";
--The trigger:
CREATE TRIGGER test_update_time BEFORE UPDATE ON contact FOR EACH ROW EXECUTE PROCEDURE update_times();
and this works well, but only with BEFORE triggers...
I prefern to fire the trigger after the update, so i changed the function and the trigger itself as:
CREATE FUNCTION "update_times_after" () RETURNS trigger AS '
BEGIN
OLD.update_time = NOW();
RETURN OLD;
END;'
LANGUAGE "plpgsql";
--The trigger:
CREATE TRIGGER test_update_time_after AFTER UPDATE ON contact FOR EACH ROW EXECUTE PROCEDURE update_times_after();
But the AFTER trigger dont work (the trigger dont fire or the function fail).
What i am doing wrong?

After trigger is run when the data is already saved to table. So no modification (especially on OLD.!) doesn't make any sense.
If you want to change the data that is save to disk, you have to do it BEFORE it is saved.

Related

UPDATE ANOTHER COLUMN IN AFTER UPDATE TRIGGER

I have a table with three columns: id, date and dateDekete
I try to execute an update on the column dateDelete after an update on another column (column date) using a AFTER UPDATE TRIGGER.
The code that I use to create my trigger is the following:
CREATE OR REPLACE FUNCTION update_delete_date_allocation()
RETURNS trigger LANGUAGE plpgsql AS $body$
BEGIN
NEW."dateDelete" := NEW.date + 1;
RETURN NEW;
END;
$body$;
CREATE TRIGGER delete_date_allocation_trg
AFTER INSERT OR UPDATE ON client.client_portfolio_allocation
FOR EACH ROW
EXECUTE PROCEDURE update_delete_date_allocation();
Although the code executes fine with no error message, the latter column that I try to update does not change.
I was wondering if it's possible to do this. AND if so, what should I change in my code?
I am using Postgres 11.5.
you can't change the new record in an AFTER trigger, you need to declare your trigger as a BEFORE trigger:
CREATE TRIGGER delete_date_allocation_trg
BEFORE INSERT OR UPDATE ON client.client_portfolio_allocation
FOR EACH ROW
EXECUTE PROCEDURE update_delete_date_allocation();

Postgres triggers and producers (column "new" of relation does not exist)

I am trying to create a trigger and procedure to update a last_changed_timestamp column upon UPDATE and INSERT.
I can register the function and trigger just fine, but when I try to update a record I receive the error.
CREATE OR REPLACE FUNCTION update_my_table_last_changed_timestamp()
RETURNS trigger AS
$BODY$
BEGIN
UPDATE my_table SET NEW.last_changed_timestamp = NOW();
RETURN NEW;
END;
$BODY$
LANGUAGE plpgsql;
CREATE TRIGGER trigger_update_my_table_last_changed_timestamp
BEFORE UPDATE
ON my_table
FOR EACH ROW
EXECUTE PROCEDURE update_my_table_last_changed_timestamp();
column "new" of relation "my_table" does not exist
I also do not fully understand how update_my_table_last_changed_timestamp knows which row it's suppose to update, nor if there were parameters passed to it, how the I would get those variables from the trigger to the procedure.
Modify the NEW record, there is no need to update.
BEGIN
NEW.last_changed_timestamp = NOW();
RETURN NEW;
END;
Read in the documentation: Overview of Trigger Behavior
If you still want to access a (other )table in the update trigger.
You can add to beginning of your trigger body the following:
EXECUTE format('SET search_path TO %I', TG_TABLE_SCHEMA);
For some reason with the update trigger it can happen that you're not on the correct search_path (i believe some old psql version have this)

PostgreSql Trigger does not work when called 'insert'

The code below is my code to create trigger function to change column "pass".
create or replace function change_pass()
returns trigger as
$$
begin
NEW.pass := 'XXXXXXXXX';
return NEW;
end
$$
language plpgsql;
create trigger change_pass
AFTER insert or update on "D_ACCOUNT"
for each row execute procedure change_pass();
When i called insert, i did not see any changes in my data.
Can anyone explain to me where i was wrong?
You need a BEFORE trigger to change values in the NEW record:
create trigger change_pass
BEFORE insert or update on "D_ACCOUNT"
for each row execute procedure change_pass();

Trigger update another table

I have been trying to write a trigger function that updates the rows in the child table when the parent is changed for a while now.
I have read Trigger procedure documentation but i have not really grasped how to build the functions.
This is what I have tried that does not work...
CREATE FUNCTION myschema.update_child() RETURNS trigger AS
$BODY$
BEGIN
UPDATE myschema.child
set new.number = parent.number
FROM myschema.parent
WHERE id = "id";
RETURN NEW;
END
$BODY$
LANGUAGE plpgsql
Then the trigger
CREATE TRIGGER update_child_after_update
AFTER INSERT OR UPDATE OR DELETE
ON myschema.child
FOR EACH ROW
EXECUTE PROCEDURE myschema.update_child();
Does anyone have some tips to give?
Best regards
You don't need to use the parent table in the body of the trigger function, because the values from the parent table are available in the function in the special variable OLD and NEW. In this case you only need NEW.
If you need the trigger only on update, than define a update-only trigger:
CREATE or replace FUNCTION update_child() RETURNS trigger AS
$BODY$
BEGIN
UPDATE child
set number = NEW.number
WHERE id = NEW.id;
RETURN NEW;
END
$BODY$
LANGUAGE plpgsql;
CREATE TRIGGER update_child_after_update
AFTER UPDATE
ON parent
FOR EACH ROW
EXECUTE PROCEDURE update_child();

How I can "atomically" replace function that is executed by trigger?

Here is code I have used to create FUNCTION and TRIGGER.
CREATE OR REPLACE FUNCTION inc_post_loves() RETURNS TRIGGER AS
$BODY$
BEGIN;
...
END;
$BODY$
language plpgsql;
CREATE TRIGGER on_post_love_create
AFTER INSERT ON "PostLoves"
FOR EACH ROW EXECUTE PROCEDURE inc_post_loves()
Now I would like to modify FUNCTION inc_post_loves().
If I will execute CREATE OR REPLACE FUNCTION inc_post_loves()... again, do I have guarantee that previously created trigger won't be deleted (like cascade) and it wont fail during replacing function?