Postgres Function Trigger Sequence Dependency Error - postgresql

I have the following functions and trigger with sequence setup:
I want to create a function and trigger that anytime I add a new row to STRATEGY_SITES table, the 'SITE_NUM' field will have the new sequential number from SITENUM_SEQ. Schema name is gismgr.
I am getting the following error:Underlying DBMS error[Error:control reached end of trigger procedure without return Context: PL/pgSQL function process_sites_edit()(gismgr.strategy_sites)::SQLSTATE=2F005][gismgr.startegy_sites]
CREATE OR REPLACE FUNCTION process_sites_edit() RETURNS TRIGGER AS $SITE_EDIT_TRIGGER$
begin
new.SITE_NUM := nextval('gismgr.SITENUM_SEQ');
end;
$SITE_EDIT_TRIGGER$ LANGUAGE 'plpgsql';
create TRIGGER SITE_EDIT_TRIGGER
before insert or update on STRATEGY_SITES for each row
EXECUTE PROCEDURE process_strategy_sites_edit();
CREATE SEQUENCE gismgr."SITENUM_SEQ" owned by gismgr.strategy_Sites.site_num
INCREMENT 1
START 19080
MINVALUE 19080
MAXVALUE 9999999999999999
CACHE 20;

This seems to be an ORACLEism which is unnecessary in Postgres. Assuming your table already exsists then just
alter table *table_name* alter column site_num default nextval('gismgr.SITENUM_SEQ')
Also make sure the insert does not mention the site_num column. If you feel you must continue with the trigger approach the your trigger function needs to specify the return value.
CREATE OR REPLACE FUNCTION process_sites_edit()
RETURNS TRIGGER AS $SITE_EDIT_TRIGGER$
begin
new.SITE_NUM := nextval('gismgr.SITENUM_SEQ');
return new;
end;
$SITE_EDIT_TRIGGER$ LANGUAGE 'plpgsql';
I would also suggest you do not want to fire the trigger on updates. That will change the site number on any/every update of a given row Are there FK referencing it - they will not be updated the update would fail. Further the procedure executed must match the function name:
create TRIGGER SITE_EDIT_TRIGGER
before insert on STRATEGY_SITES for each row
EXECUTE PROCEDURE process_sites_edit();

Related

PostgreSQL - trigger after update column

I try to create a generic trigger function which is used to update "updated_at" column value from table when it is updating it.
My trigger function:
CREATE OR REPLACE FUNCTION update_created_at_column() RETURNS TRIGGER AS $$
BEGIN
NEW.created_at = NOW();
return NEW;
END;
$$ LANGUAGE plpgsql;
Trigger assignment to the concerned table:
CREATE TRIGGER type_trigger_updated_at_column AFTER UPDATE ON "type"
FOR EACH ROW EXECUTE FUNCTION update_created_at_column();
Currently, I have no error when I execute them, but when I update a field on my table, "created_at" column is not updated.
The value can be changed only in BEFORE triggers.
The Postgres knows more types of triggers - BEFORE triggers are executed before the value is stored to table, AFTER triggers are executed when the value is visible in table. You should to use BEFORE trigger - you need to modify row before it is stored to the table.

Syntax error while creating a trigger in PostgreSQL

I created a table name Student in PostgreSQL and then I tried defining a trigger on that table but it's showing an error message in doing so.
Trigger Syntax:
CREATE TRIGGER bi_Student BEFORE INSERT ON Student as $$
FOR EACH ROW
BEGIN
raise notice 'Successfully inserted into table(%)', user;
end $$;
Table Creation Command:
create table Student(Stu_id int, Stu_Name text, Stu_Age int, Stu_address char(30));
Actually I tried to declare the execution statements directly inside the trigger only rather than calling any procedure/ function from the trigger which is working fine but I want to do in this way in PostgreSQL.
PostgreSQL doesn't support it. You need trigger function always.
As documented in the manual you need a trigger function
create function my_trigger_function()
returns trigger
as
$$
begin
raise notice 'Successfully inserted into table(%)', user;
return new; --<< important (see the manual for details)
end
$$
language plpgsql;
Not sure what you intend with the user parameter there, as that is not the table name, but the current database user. If you want to display the actual table name, you need to use TG_RELNAME instead - which is an implicit variable available in the trigger function.
And a trigger definition
CREATE TRIGGER bi_Student
BEFORE INSERT ON Student
FOR EACH ROW
execute function my_trigger_function();

Alter PostreSQL column into a GENERATED ALWAYS column

I have an already made table:
cotizacion(idCot(PK), unit_price,unit_price_taxes)
I need to convert unit_price_taxes into a generated column that is equal to unit_price*1.16. The issue is I can't find the alter table statement which will give me this. Dropping table and creating it again is not an option as this table is already deeply linked with the rest of the database and reinserting all records is not an option at this point.
I tried the following:
ALTER TABLE cotizacion
alter column unit_price_taxes set
GENERATED ALWAYS AS (unit_price*1.16) STORED;
But it's not working. Does anybody know how to get this done or if it's even possible? I would like to avoid creating a new column.
Thanks!
**EDIT:
I also tried the following trigger implementation:
CREATE OR REPLACE FUNCTION calculate_price_taxes()
RETURNS trigger
LANGUAGE plpgsql
AS $function$
declare pu money;
begin
select unit_price from cotizacion into pu
where idCot = new."idCot";
update cotizacion
set unit_price_taxes = pu * (1.16)
where idCot = new."idCot";
return new;
end;
$function$
;
And the trigger delcaration:
Create or replace trigger price_taxes
after update on cotizacion
for each row
execute procedure
calculate_price_taxes()
The most probable reason for your trigger to go into an infinite recursion is that you are running an UPDATE statement inside the trigger - which is the wrong thing to do. Create a before trigger and assign the calculated value to the new record:
create trigger update_tax()
returns trigger
as
$$
begin
new.unit_price_taxes := unit_price * 1.16;
return new;
end;
$$
language plpgsql;
create trigger update_tax_trigger()
before update or insert on cotizacion
for each row execute procedure update_tax();
The only way to "convert" that column to a generated one, is to drop it and add it again:
alter table cotizacion
drop unit_price_taxes;
alter table cotizacion
add unit_price_taxes numeric generated always as (unit_price*1.16) stored;
Note that this will rewrite the entire table which will block access to it. Adding the trigger will be less invasive.

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();

Generic function to be called from multiple triggers

I have created a function and trigger to make use that the userId is uCased. The code is as followsL
CREATE OR REPLACE FUNCTION stdUserId ()
RETURNS trigger AS $stdUserId$
BEGIN
NEW.login_id = UPPER (TRIM (NEW.login_id));
RETURN NEW;
END;
$stdUserId$ LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS usersStdUserId ON users;
CREATE TRIGGER usersStdUserId BEFORE INSERT OR UPDATE ON users
FOR EACH ROW EXECUTE PROCEDURE stdUserId (login_id);
Now I would like to alter the function to be usable with other triggers as in:
DROP TRIGGER IF EXISTS user_rolesStdUserId ON user_roles;
CREATE TRIGGER user_rolesStdUserId BEFORE INSERT OR UPDATE ON users
FOR EACH ROW EXECUTE PROCEDURE stdUserId (user_id);
I would like a generic approach as I have a number of tables to apply this function to. I would prefer to stay away from "IF table01 .. . ELSEIF table02 .. ."
Your assistance is appreciated.