How can I solve max_stack_depth? - sql

I'm super new with PGADMIN and I have a problem.
I have to create a trigger that updates the password to '123456' and the reset mark to 'Y' every time a change is detected in the mail or in the username of a table in my database.
My code is:
CREATE OR REPLACE FUNCTION password_reset()
RETURNS trigger AS $$
BEGIN
UPDATE web_content.tb_user SET user_password = '123456'
WHERE user_email = NEW.user_email OR user_name = NEW.user_name;
UPDATE web_content.tb_user SET password_reset = 'Y'
WHERE user_email = NEW.user_email OR user_name = NEW.user_name;
RETURN NEW;
END
$$ LANGUAGE plpgsql;
CREATE TRIGGER TR_update BEFORE update on web_content.tb_user
for each row
execute procedure password_reset();
When I try to make an UPDATE on my table the error error max_stack_depth appears. I don't know how to solve it.
Can anyone help me, please?
Thanks in advance

Don't update the table in the trigger function. This generates an infinite loop where the update statement of the function fires the trigger again, and eventually raise the error you are getting.
Instead, you can set the new value directly in the function, before the new row is updated in the table. If you want to fire the trigger only when some specific columns are modified, you can use a when clause in the trigger definition.
create or replace function password_reset()
returns trigger as $$
begin
new.user_password = '123456';
new.password_reset = 'Y';
return new;
end
$$ language plpgsql;
create trigger tr_update before update on web_content.tb_user
for each row
when (old.email is distinct from new.email or old.username is distinct from new.username)
execute procedure password_reset();

Related

PostgeSQL trigger before insert unique value

Is there any variant to create a trigger before insert and if the value is a value that exists already in table, just update it. I know about 'ON DUBLICATE KEY' or a 'ON CONFLICT' in PostgreSQL but I need a trigger just because it's a task in my university.
I tried to create it, but I get just an error about duplicate keys.
CREATE or replace FUNCTION trigger_function()
RETURNS TRIGGER
LANGUAGE PLPGSQL
AS $$
BEGIN
IF new.name in (select name from "Test")
then
update "Test" set intt = new.intt where name = new.name;
end if ;
return new;
END;
$$
CREATE TRIGGER trigger_name
BEFORE insert
ON "Test"
for each row
EXECUTE PROCEDURE trigger_function();
Is it possible to create such trigger?
Read the docs plpgsql trigger function:
Row-level triggers fired BEFORE can return null to signal the trigger manager to skip the rest of the operation for this row (i.e., subsequent triggers are not fired, and the INSERT/UPDATE/DELETE does not occur for this row).
So RETURN NULL after the UPDATE statement inside the if andRETURN NEW when the if is false. Then the INSERT will happen if the name is unique.

Trigger postgreSQL

So. I tried made a trigger for updating quality medicament( i take quality from delivery.quality and put in medicaments.quality)
create or replace function addedmed()
returns trigger
language plpgsql
as
$$
begin
update medicaments set medicaments.quality = delivery.quality + medicaments.quality
where medicaments.id_med = delivery.id_med_del;
end;
$$;
and then - i try insert data to delivery
insert into delivery(id_del,id_provider,date_of_get,id_worker_del,id_med_del,quality)
values (default, 3 , current_timestamp ,1 ,6 ,10);
and then i have a exception -
ЗАПРОС: update medicaments set medicaments.quality = delivery.quality + medicaments.quality
where medicaments.id_med = delivery.id_med_del
КОНТЕКСТ: PL/pgSQL function addedmed() line 3 at SQL statement
so, pls help me, because i dont know how resolve it
This is not valid trigger function code. If you want to refer to the row being inserted in delivery, then use pseudo-table new, not delivery.
create or replace function addedmed()
returns trigger
language plpgsql
as $$
begin
update medicaments set quality = quality + new.quality where id_med = new.id_med_del;
return new;
end;
$$;
Note that the trigger returns the new record. You can then actually create the trigger as follows:
create trigger trg_addedmed
before insert on delivery
for each row
execute addedmed()
;
I defined a before insert trigger, you can change that to after insert if you prefer (in that case you can return null instead of new).

syntax Error in PostgreSQL when I try to create Trigger

I want to create trigger in PostgreSQL.
Logic is very simple.
I need trigger, if published_at updated and written_at is null, set published_at to written_at.
I wrote this one, but it failed. Does anybody have an idea?
CREATE function setWrittenAt() RETURNS trigger;
AS
DECLARE old_id INTEGER;
BEGIN ;
old_id = OLD.id
IF NEW.published_at IS NOT and NEW.written_at IS null
THEN
UPDATE review SET NEW.written_at = NEW.published_at where id = old_id;
END IF ;
RETURN NEW;
END;
LANGUAGE plpgsql;
CREATE TRIGGER update_written_at
AFTER UPDATE OF published_at ON review
WHEN (OLD.published_at IS DISTINCT FROM NEW.published_at)
EXECUTE PROCEDURE setWrittenAt();
Error:
Syntax error: 7 ERROR: syntax error at or near "DECLARE"
LINE 3: DECLARE old_id INTEGER;
There are multiple errors in your code:
IS NOT is not a valid expression you need IS NOT NULL.
After BEGIN and the returns clause there must be no ;
you forgot to enclose the function body as a string (which is easier to write if you use dollar quoting
you also don't need an unnecessary (additional) UPDATE if you make it a before trigger
CREATE function setwrittenat()
RETURNS trigger
AS
$$
BEGIN
IF NEW.published_at IS NOT NULL and NEW.written_at IS null THEN
NEW.written_at := = NEW.published_at; --<< simply assign the value
END IF;
RETURN NEW;
END;
$$
LANGUAGE plpgsql;
Then use a BEFORE trigger:
CREATE TRIGGER update_written_at
BEFORE UPDATE OF published_at ON review
WHEN (OLD.published_at IS DISTINCT FROM NEW.published_at)
FOR EACH ROW
EXECUTE PROCEDURE setWrittenAt();
this is based on a_horse_with_no_names answer, since it'll throw an error.
ERROR: statement trigger's WHEN condition cannot reference column values
You need to add FOR EACH ROW, else conditional triggers will not function.
If neither is specified, FOR EACH STATEMENT is the default.
Statement-level triggers can also have WHEN conditions, although the feature is not so useful for them since the condition cannot refer to any values in the table.
See here
CREATE TRIGGER update_written_at
BEFORE UPDATE OF published_at ON review
FOR EACH ROW
WHEN (OLD.published_at IS DISTINCT FROM NEW.published_at)
EXECUTE PROCEDURE setWrittenAt();
I can not comment yet, which is why I've posted this as an answer.

INSTEAD OF DELETE trigger (Postgresql)

I would like to disable the DELETE statement on a table.
What I need to do is a SET a field value instead of removing the respective record.
So far I have tried the following:
CREATE TRIGGER delete_trg
INSTEAD OF DELETE
ON schema.tbl
FOR EACH ROW
EXECUTE PROCEDURE schema.tbl_delete_fn();
My schema.tbl_delete_fn() function is as follows:
CREATE OR REPLACE FUNCTION schema.tbl_delete_fn()
RETURNS trigger AS
BEGIN
NEW.deleted := true;
RETURN NEW;
END;
So far this doesn't seem to work... any ideas?
You want a BEFORE DELETE trigger whose function returns NULL and the row variable is OLD, not NEW.
CREATE TRIGGER delete_trg
BEFORE DELETE
ON schema.tbl
FOR EACH ROW
EXECUTE PROCEDURE schema.tbl_delete_fn();
CREATE OR REPLACE FUNCTION schema.tbl_delete_fn()
RETURNS trigger AS '
BEGIN
UPDATE schema.tbl SET deleted=true WHERE ctid=OLD.ctid;
RETURN NULL;
END; ' language plpgsql;
Or...
CREATE RULE delete_rule
AS ON DELETE TO schema.tbl
DO INSTEAD NOTHING;
Pros: Clearer, no code is called for each row visited, and no SP required.
Cons: Less standard than the trigger solution.

Simple update trigger on PostgreSQL returning errors

CREATE FUNCTION update_status() RETURNS TRIGGER AS '
BEGIN
SELECT status FROM animals
IF status = "Alive"
THEN
UPDATE animals SET status = "Sold" WHERE status="Alive";
END IF;
RETURN NULL;
END; ' LANGUAGE plpgsql;
CREATE TRIGGER updatetrigger AFTER UPDATE OF id_selling ON animals EXECUTE PROCEDURE update_status();
It says I'm not using the selected attributes, and I should use Perform instead of Select. But then it doesnt recognize the IF after the perform. I'm really new to these syntax, so it might be wrong. I think its clear what I want to do (and i believe it simple for someone with experience). Can you please help me with this problem?
In standard SQL (and PostgreSQL), this is a quoted identifier (table name, column name, ...):
"Alive"
and this is a string literal:
'Alive'
You will be getting complaints about "unknown columns" because you're using the wrong quotes for your strings.
Functions are usually defined with dollar-quoting to avoid this sort of thing:
CREATE FUNCTION update_status() RETURNS TRIGGER AS $$
BEGIN
SELECT status FROM animals
IF status = 'Alive' THEN
UPDATE animals SET status = 'Sold' WHERE status = 'Alive';
END IF;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
Triggers have access to NEW and OLD to represent the previous/current state of the row and the new/updated state of the row, you should be consulting those instead of trying to SELECT to find the status:
CREATE FUNCTION update_status() RETURNS TRIGGER AS $$
BEGIN
IF NEW.status = 'Alive' THEN
UPDATE animals SET status = 'Sold' WHERE status = 'Alive';
END IF;
RETURN NULL;
END;
$$ LANGUAGE plpgsql;
You might want a little more in the WHERE clause for that UPDATE too, just WHERE status = 'Alive' seems a bit broad.