PostgreSQL trigger and stored procedure not kicking in - postgresql

My goal is to compute and persist a certain value before an update happens to a row in my table.
I created the trigger and the function, I don't get any errors but the function doesn't seem to be kicking in. Where am I going wrong?
The procedure
CREATE or REPLACE FUNCTION foo() returns trigger as
$BODY$
DECLARE
BEGIN
NEW.geomtry := st_transform(st_pointfromtext('POINT(' || NEW.af_lon || ' ' || NEW.af_lat || ')', 4326), 32643);
return NEW;
END;
$BODY$
language plpgsql;
The trigger to trigger the method before an update happens
CREATE TRIGGER foo_trigger BEFORE UPDATE ON foo_table FOR EACH ROW EXECUTE PROCEDURE foo();

You spelled "geometry" incorrectly in your stored proc. Make sure it is spelled consistently in your table and stored proc.

Related

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: Checking for NEW and OLD in a function for a trigger

I want to create a trigger which counts rows and updates a field in an other table. My current solution works for INSERT statements but failes when I DELETE a row.
My current function:
CREATE OR REPLACE FUNCTION update_table_count()
RETURNS trigger AS
$$
DECLARE updatecount INT;
BEGIN
Select count(*) into updatecount
From source_table
Where id = new.id;
Update dest_table set count=updatecount
Where id = new.id;
RETURN NEW;
END;
$$
LANGUAGE 'plpgsql';
The trigger is a pretty basic one, looking like.
CREATE TRIGGER count_trigger
AFTER INSERT OR DELETE
ON source_table
FOR EACH ROW
EXECUTE PROCEDURE update_table_count();
When I excute a DELETE statement the following error occurs:
ERROR: record "new" is not assigned yet
DETAIL: The tuple structure of a not-yet-assigned record is indeterminate.
I know one solution could be to create just one set of trigger and function for the DELETE and one for the INSERT statement. But I want to do it a bit more elegant and want to know, if there is a solution to check if NEW or OLD is present in the current context and just implement an IF ELSE block. But I dont know how to check for this context sensitive items.
Thanks for your help
The usual approach to make a trigger function do different things depending on how the trigger was fired is to check the trigger operation through TG_OP
CREATE OR REPLACE FUNCTION update_table_count()
RETURNS trigger AS
$$
DECLARE
updatecount INT;
BEGIN
if tg_op = 'UPDATE' then
select count(*) into updatecount from source_table where id = new.id;
update dest_table set count=updatecount where id = new.id;
elsif tg_op = 'DELETE' then
... do something else
end if;
RETURN NEW;
END;
$$
LANGUAGE plpgsql;
Unrelated, but: the language name is an identifier. Do not quote it using single quotes.
From PostgreSQL's documentation:
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.
OLD
Data type RECORD; variable holding the old database row for UPDATE/DELETE operations in row-level triggers. This variable is null in statement-level triggers and for INSERT operations.
So, for example, if NEW is NULL, then the trigger was invoked on DELETE.

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

PL/pgSQL: Update a table using a record

I have an insert trigger in a PostgreSQL 9.5 database which copies the row being inserted to another table:
CREATE OR REPLACE FUNCTION data_record_insert () RETURNS TRIGGER AS $x$
BEGIN
EXECUTE 'INSERT INTO data_record_backup VALUES ($1.*)' USING new;
RETURN new;
END;
$x$ LANGUAGE PLPGSQL;
However, I want to be able to use Postgres' INSERT ... ON CONFLICT upsert statement to insert rows into these tables but can't figure out how to write the trigger. It'd be something like this:
CREATE OR REPLACE FUNCTION data_record_insert () RETURNS TRIGGER AS $x$
BEGIN
EXECUTE 'INSERT INTO data_record_backup VALUES ($1.*)
ON CONFLICT (pk) DO UPDATE SET column_names($1) = $1.*' USING new;
RETURN new;
END;
$x$ LANGUAGE PLPGSQL;
But obviously that SET column_names($1) = $1.* is wrong, it's just something I made up. Is there some way to achieve this?

how do I insert from NEW or OLD into a dynamically named table within a PostgreSQL trigger

I have a number of tables with associated audit tables. The tables are named respectively X and X_aud where X is the name of the table to be audited. I have a trigger function that I call before INSERT, UPDATE or DELETE and I want to call the same function for all my tables but I can't figure out how to write my trigger function. What I've tried so far is:
CREATE OR REPLACE FUNCTION audit_maintenance() RETURNS trigger AS $$
BEGIN
IF (TG_OP = 'DELETE') THEN
EXECUTE 'INSERT INTO ' || TG_TABLE_NAME || '_aud VALUES ' || OLD.*;
RETURN OLD;
END IF;
EXECUTE 'INSERT INTO ' || TG_TABLE_NAME || '_aud VALUES ' || NEW.*;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
And various other versions with the NEW.* inside the quotes etc. But nothing seems to work. Has anyone else tried something similar and if so how did you do it
Thanks
There is an example of a couple of audit triggers available on the postgresql wiki.
pre 9.1
9.1 or above
the question has already been asked (and nicely answered). The solution is to use the EXECUTE ... USING syntax. This certainly works in 9.3 but the original answer said that it worked in 8.4 and above
EXECUTE 'INSERT INTO ' || TG_TABLE_NAME || '_aud SELECT $1.*' USING NEW;