PostgreSQL trigger not executing after update [duplicate] - sql

Here is my trigger function
CREATE OR REPLACE FUNCTION test_table_insert()
RETURNS TRIGGER
AS $$
BEGIN
IF NEW.id IS NULL THEN
RAISE EXCEPTION 'id is null';
END IF;
UPDATE e_sub_agreement SET ro_id = NEW.id WHERE id = NEW.id;
RETURN NEW;
END;
$$
LANGUAGE plpgsql;
CREATE TRIGGER test_table_insert AFTER INSERT ON e_sub_agreement FOR EACH ROW EXECUTE PROCEDURE test_table_insert();
The problem is that it doesn't update table e_sub_agreement. I checked NEW value and everything is good. It returns with the new id. If I change where statement id = "some existing id in table", then it works. It changes ro_id to the new id. How is it possible? My guess is that data has not been inserted into table and trigger function can't find row with the given id. But it's not how trigger's after insert function works. What's the magic?

An AFTER trigger can not change anything. Running an additional UPDATE is also quite inefficient. Change this to a BEFORE trigger and assign the value you want:
CREATE OR REPLACE FUNCTION test_table_insert()
RETURNS TRIGGER
AS $$
BEGIN
IF NEW.id IS NULL THEN
RAISE EXCEPTION 'id is null';
END IF;
NEW.ro_id := NEW.id;
RETURN NEW;
END;
$$
LANGUAGE plpgsql;
CREATE TRIGGER test_table_insert
BEFORE INSERT ON e_sub_agreement
FOR EACH ROW EXECUTE PROCEDURE test_table_insert();
Note that the NOT NULL check is better done by defining the column as NOT NULL.

Related

Update columns for the first user inserted

I'm trying to create a trigger and a function to update some columns (roles and is_verified) for the first user created. Here is my function :
CREATE OR REPLACE FUNCTION public.first_user()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
DECLARE
begin
if(select count(*) from public.user = 1) then
update new set new.is_verified = true and new.roles = ["ROLE_USER", "ROLE_ADMIN"]
end if;
return new;
end;
$function$
;
and my trigger :
create trigger first_user
before insert
on
public.user for each row execute function first_user()
I'm working on Dbeaver and Dbeaver won't persist my function because of a syntax error near the "=". Any idea ?
Quite a few things are wrong in your trigger function. Here it is revised w/o changing your business logic.
However this will affect the second user, not the first. Probably you shall compare the count to 0. Then the condition shall be if not exists (select from public.user) then
CREATE OR REPLACE FUNCTION public.first_user()
RETURNS trigger LANGUAGE plpgsql AS
$function$
begin
if ((select count(*) from public.user) = 1) then
-- probably if not exists (select from public.user) then
new.is_verified := true;
new.roles := array['ROLE_USER', 'ROLE_ADMIN'];
end if;
return new;
end;
$function$;

How to check for value of field in a trigger

I'm trying to check for a field missing during an UPDATE statement. I was thinking something like this
CREATE OR REPLACE FUNCTION UPDATED_BY_TRIGGER()
RETURNS TRIGGER AS
$BODY$
BEGIN
IF NEW."updated_by" IS NULL THEN
RAISE EXCEPTION 'updated_by is missing in UPDATE to %', TG_TABLE_NAME;
END IF;
RETURN NEW;
END;
$BODY$ LANGUAGE PLPGSQL;
Here's the catch: the value in the DB for the field is already not NULL (because it has a NOT NULL constraint), so I can't use NEW."updated_by". I am able to run UPDATE statements that don't change the value of updated_by right now. I want to raise an exception when this happens.

How to send current schema and affected table with notification function/trigger?

When a row is inserted or updated in a specific table (in this example it's the table called 'fpl'). How can I include the affected table and schema in the notification?
SQL as follows:
CREATE TRIGGER fpl_event
AFTER INSERT OR UPDATE ON fpl
FOR EACH ROW
EXECUTE PROCEDURE fpl_notify();
CREATE OR REPLACE FUNCTION fpl_notify()
RETURNS trigger AS $$
BEGIN
NOTIFY dbNotification, 'something got insereted in fpl!';
RETURN NULL;
END;
$$ LANGUAGE PLPGSQL;
Update:
CREATE OR REPLACE FUNCTION fpl_notify() RETURNS trigger
AS
$$
BEGIN
EXECUTE format('notify dbNotification, ''%s''', TG_TABLE_SCHEMA);
RETURN NULL;
END;
$$ LANGUAGE PLPGSQL;
read trigger special variables

prevent any update or delete from table

I have a table where I added a boolean column done
When this column is True I want to prevent any unautorized action (delete, update) on the row.
I wrote this trigger:
CREATE TRIGGER productstock_beforeupdate
BEFORE UPDATE OR DELETE
ON table
FOR EACH ROW
EXECUTE PROCEDURE trig()
CREATE OR REPLACE FUNCTION trig()
RETURNS trigger AS
$$
begin
if TG_OP='UPDATE' or TG_OP='DELETE' then
if old.done=true then
raise exception 'cant do that';
return null;
end if;
end if;
return new;
end;
$$
If autorized transaction wants to change data it will have first to disable this trigger.
This idea should work however when I try to delete a row with
done=False
it returns me "0 rows deleted" and does not perform the delete.
Any idea what is wrong with my trigger?
This is caused by the fact that for an UPDATE to go through you need to return the NEW record. However for a DELETE to go through, you need to return the OLDrecord.
Quote from the manual
Thus, if the trigger function wants the triggering action to succeed normally without altering the row value, NEW (or a value equal thereto) has to be returned [...] Note that NEW is null in DELETE triggers, so returning that is usually not sensible. The usual idiom in DELETE triggers is to return OLD.
So your trigger function should look like this:
CREATE OR REPLACE FUNCTION trig()
RETURNS trigger AS
$$
begin
-- no need to check for the action here as the trigger
-- will only fire for UPDATE or DELETE
if old.done then
raise exception 'cant do that';
return null;
end if;
if TG_OP='UPDATE' then
return new;
end if;
if TG_OP='DELETE' then
return old;
end if;
end;
$$
language plpgsql;
When the trigger allows DELETE it should return old. In case of UPDATE it returns new.
If it raises an exception it do not need to return anything.
create or replace function trig()
returns trigger language plpgsql as
$$
begin
if old.done then
raise exception 'cant do that';
end if;
if tg_op = 'DELETE' then
return old;
else
return new;
end if;
end $$;

Postgresql trigger row not affected

I have try to make a trigger on a table call product. After inserting a product i get an error, that "NEW" variable is not affected yet.
Here is the trigger and user-defind function :
CREATE OR REPLACE FUNCTION updateProduitQteInitiale() RETURNS TRIGGER AS $example_table$
BEGIN
IF (TG_OP = 'INSERT' OR TG_OP = 'UPDATE') THEN
UPDATE produit set qtestock= NEW.qteinitial where produit.pid = NEW.pid ;
return NEW ;
END IF;
RETURN NULL;
END;
$example_table$ LANGUAGE plpgsql;
And here is the trigger:
CREATE TRIGGER qteInitialTrigger AFTER INSERT OR UPDATE ON produit
FOR EACH ROW EXECUTE PROCEDURE updateProduitQteInitiale();
Is pid your primary id? Not sure what you want to do but I assume you want to set to the column qtestock value from column qteinitial (on the same row!). If I guessed it right then you can do this:
CREATE OR REPLACE FUNCTION updateProduitQteInitiale() RETURNS TRIGGER AS $example_table$
BEGIN
NEW.qtestock = NEW.qteinitial;
return NEW;
END;
$example_table$ LANGUAGE plpgsql;
CREATE TRIGGER qteInitialTrigger BEFORE INSERT OR UPDATE ON produit
FOR EACH ROW EXECUTE PROCEDURE updateProduitQteInitiale();