i have a table "demand_details"
on update or delete i want to store values of each row in another table "demand_details_log"
my functions is as follows
CREATE OR REPLACE FUNCTION water_blogb() RETURNS trigger AS
$BODY$
BEGIN
IF (TG_OP='UPDATE') THEN
INSERT INTO demand_details_log VALUES ('U',now(),OLD.*);
RETURN NEW;
END IF;
IF (TG_OP='DELETE') THEN
INSERT INTO demand_details_log VALUES ('D',now(),OLD.*);
RETURN OLD;
END IF;
END;
$BODY$ LANGUAGE plpgsql
my trigger is as follows
CREATE TRIGGER water_btrg_b
AFTER UPDATE OR DELETE
ON demand_details
FOR EACH ROW
EXECUTE PROCEDURE water_blogb();
MY problem is the same trigger and functions works well on other table (by changing table,trigger and function name) but not working with demand table. I tried with "RAISE NOTICE 'working...'" in both in other table trigger gets fired but in demand table its not fired at all.
As you found, triggers are not inherited. This leads to some difficulties in managing triggers in inherited table structures. You may want to read up on some of the issues involved at http://ledgersmbdev.blogspot.com/2012/08/postgresql-or-modelling-part-3-table.html and http://ledgersmbdev.blogspot.com/2012/08/or-modelling-32-setsubset-modelling.html.
Now those do not address table partitioning directly which may be what you are trying to do here. I would recommend that you build in some additional tests that you can run to check and make sure that triggers are properly installed on all subtables. I would suggest taking a look at How to find inherited tables programatically in PostgreSQL? and also the pg_trigger table so that you can build a report of child tables which do not share the triggers of their parents.
Related
I have a spatial table in a Postgres database from which I create three separate materialized views (each based on specific spatial queries). I want to create trigger functions to refresh each of the materialized views on updates, inserts, and deletes.
I have created three separate functions and triggers, but the performance (as to be expected) is horrendous. If I run a single trigger on update, insert, or delete, it performs fine. Below is a sample function and trigger I am using:
CREATE OR REPLACE FUNCTION refresh_mvw_taxa_hex5km()
RETURNS trigger
AS $BODY$
BEGIN
refresh materialized view mvw_taxa_hex5km;
return new;
END;
$BODY$ LANGUAGE plpgsql;
CREATE TRIGGER refresh_mvw_taxa_hex5km
AFTER INSERT OR UPDATE OR DELETE ON occurrence
FOR EACH STATEMENT
EXECUTE PROCEDURE refresh_mvw_taxa_hex5km();
Is there a more efficient way to do this? I considered running scheduled tasks, but I really need the refresh on changes to the table. I have read a little about "concurrently," but not sure if this is the answer.
So I found this example:
create function eager.account_insert() returns trigger
security definer
language plpgsql
as $$
begin
insert into eager.account_balances(name) values(new.name);
return new;
end;
$$;
create trigger account_insert after insert on accounts
for each row execute procedure eager.account_insert();
The thing I can't understand: function eager.account_insert() does not take any arguments, however, it operates with variable new. It returns it, but should't it return trigger?
Also, this: insert into eager.account_balances(name), this is not some certain record chosen, what it this?
The new (and old when it's an update statement) is the RECORD you're inserting or updating. You can get columns from it and do whatever you want with them. Many times BEFORE INSERT triggers check for valid values etc.
The function must return a RECORD with the same columns as the table, or NULL if the insert should not happen (usually for INSTEAD triggers).
The insert statement is just a regular insert with one column specified of the table and the value is taken from the newly inserted RECORD's column name.
The documentation explains the triggers very well.
In my PostgreSQL 9.1 database I have multiple tables and one trigger function.
Right now I am creating the trigger for each table by using that trigger function.
This methodology working fine. My boss has asked me to create the trigger commonly (only one time) by re-using that trigger function. That one trigger function should get used by all the tables in my database.
You can find an example of creating a trigger with dynamic SQL using PL/PgSQL in the Audit Trigger sample for PostgreSQL. The same approach will work with any other DDL.
See the function audit.audit_table and use of format and EXECUTE there.
That said, needing to create tables procedurally can be (but isn't always) a sign of questionable schema design.
Simple example of dynamic SQL creating a table:
CREATE OR REPLACE FUNCTION demo_dynamic_table(tablename text) RETURNS void AS $$
BEGIN
EXECUTE format('CREATE TABLE %I (id serial primary key);', tablename);
END;
$$ LANGUAGE plpgsql;
The same approach works for trigger creation, etc.
You can create PL/pgSQL procedure for table creation and move your trigger creation code inside it
For a security sensitive design, I'd like to disable DELETEs on certain tables.
The DELETE should merely set a deleted flag on a row (which would be then visible on a view, which would be used by the application layer).
As I understand a rule would generate additional queries - so a rule could not suppress the original query.
As illustration a toy example with a trigger (not yet tested):
-- data in this table should be 'undeletable'
CREATE table article (
id serial,
content text not null,
deleted boolean default false
)
-- some view that would only show articles, that are NOT deleted
...
-- toy trigger (not tested)
CREATE OR REPLACE FUNCTION suppress_article_delete()
RETURNS TRIGGER AS $sad$
BEGIN
IF (TG_OP = 'DELETE') THEN
UPDATE article SELECT id, content, TRUE;
-- NEW or NULL??
RETURN NEW;
END IF;
RETURN NULL;
END;
$sad$ LANGUAGE plpgsql;
What would be a good way to suppress a DELETE?
As I understand a rule would generate additional queries - so a rule could not suppress the original query.
Not really - it could be an INSTEAD rule:
CREATE RULE shoe_del_protect AS ON DELETE TO shoe DO INSTEAD NOTHING;
(an example on that same page of the manual).
Another way is to REVOKE delete privileges on the table in question and to create stored procedure(s) for deleting... and updating and inserting also probably.
I would like to know if a trigger on a system table of PostgreSQL can be executed when I create a table
I need to add 2 functions on each table of my database and I would like to do it dynamically
Thanks
This can be done with an event trigger:
CREATE OR REPLACE FUNCTION on_create_table_func()
RETURNS event_trigger AS $$
BEGIN
-- your code here
END
$$
LANGUAGE plpgsql;
CREATE EVENT TRIGGER
on_create_table ON ddl_command_end
WHEN TAG IN ('CREATE TABLE')
EXECUTE PROCEDURE on_create_table_func();
Note that there is no way to directly execute any query on the newly created table, or even get its name.
I don't know what you mean by "add 2 functions on each table" since functions don't belong to a specific table, but if you need to perform an operation specific for the new tables, this might not be for you.
I know it's an old question but now it has been implemented in version 9.3, or at least partially
http://www.postgresql.org/docs/9.3/static/event-trigger-definition.html
You're looking for "DDL Triggers". They're not implemented in PostgreSQL. Neither you can add triggers to system tables. Look at this forum entry:
Adding ddl audit trigger