Postgresql [42P01] ERROR: relation does not exist during trigger function - postgresql

I am trying to write a trigger that stores previous versions of a row in a table named audit_tablename given a table named tablename.
Here is the the code...
CREATE OR REPLACE FUNCTION process_ui_audit()
RETURNS TRIGGER AS
$$
DECLARE
audit_table_name text := TG_TABLE_SCHEMA || '.audit_' || TG_TABLE_NAME;
audit_table_schema text := TG_TABLE_SCHEMA;
BEGIN
IF (TG_OP = 'UPDATE')
THEN
EXECUTE FORMAT('INSERT INTO %1$I SELECT NEXTVAL(''$1.hibernate_sequence''),now(), user, ($1).*',
audit_table_name, audit_table_schema)
USING OLD;
NEW.version = OLD.version + 1;
RETURN NEW;
ELSIF (TG_OP = 'INSERT')
THEN
NEW.version = 1;
RETURN NEW;
END IF;
END;
When I try to update a row the trigger runs and I get errors like this....
[42P01] ERROR: relation "webapp.audit_portal_user" does not exist
Where: PL/pgSQL function webapp.process_ui_audit() line 13 at EXECUTE
I am wonderin am I formatting table names incorrectly or something? The table name webapp.audit_portal_user definetly exists.

It works without specifying schema name.
Here is a simplified example:
create table portal_user(
uid int,
uname text
);
CREATE TABLE
create table audit_portal_user(
uid int,
uname text,
who text,
what text,
ts timestamp
);
CREATE TABLE
create or replace function process_ui_audit()
returns trigger as
$$
declare
audit_table_name text := 'audit_' || tg_table_name;
begin
if (tg_op = 'UPDATE')
then
execute format('insert into %I values($1.*, user, %L, now())',
audit_table_name, 'UPDATE') using new;
return null;
end if;
end;
$$
language plpgsql;
CREATE FUNCTION
create trigger audit
after update on portal_user
for each row
execute function process_ui_audit();
CREATE TRIGGER
insert into portal_user values(12, 'titi');
INSERT 0 1
select * from portal_user;
uid | uname
-----+-------
12 | titi
(1 row)
update portal_user set uname='toto' where uid=12;
UPDATE 1
select * from portal_user;
uid | uname
-----+-------
12 | toto
(1 row)
select * from audit_portal_user;
uid | uname | who | what | ts
-----+-------+----------+--------+----------------------------
12 | toto | postgres | UPDATE | 2020-06-01 10:20:36.549257
(1 row)

Related

Array error passing dynamic number of parameters to function

I'm trying to create a function to receive the name of the table in my schema already created and a several name of columns within this table (dynamic number of columns) and return a table with all the columns in a unique column with the value of each column separated by comma.
I'm trying this:
CREATE OR REPLACE PROCEDURE public.matching(IN table text, VARIADIC column_names text[])
LANGUAGE 'plpgsql'
AS $BODY$DECLARE
column_text text;
BEGIN
EXECUTE format ($$ SELECT array_to_string(%s, ' ')$$, column_names) into column_text;
EXECUTE format ($$ CREATE TABLE temp1 AS
SELECT concat(%s, ' ') FROM %s $$, column_text, table);
END;$BODY$;
This return an error:
ERROR: syntax error at or near «{»
LINE 1: SELECT array_to_string({city,address}, ' ')
which is the error?
If you simplify the generation of the dynamic SQL, things get easier:
CREATE OR REPLACE PROCEDURE public.matching(IN table_name text, VARIADIC column_names text[])
LANGUAGE plpgsql
AS
$BODY$
DECLARE
l_sql text;
BEGIN
l_sql := format($s$
create table temp1 as
select concat_ws(',', %s) as everything
from %I
$s$, array_to_string(column_names, ','), table_name);
raise notice 'Running %', l_sql;
EXECUTE l_sql;
END;
$BODY$;
So if you e.g. pass in 'some_table' and {'one', 'two', 'three'} the generated SQL will look like this:
create table temp1 as select concat_ws(',', one,two,three) as everything from some_table
I also used a column alias for the new column, so that the new table has a defined name. Note that the way I put the column names into the SQL string won't properly deal with identifiers that need double quotes (but they should be avoided anyway)
If you want to "return a table", then maybe a function might be the better solution:
CREATE OR REPLACE function matching(IN table_name text, VARIADIC column_names text[])
returns table (everything text)
LANGUAGE plpgsql
AS
$BODY$
DECLARE
l_sql text;
BEGIN
l_sql := format($s$
select concat_ws(',', %s) as everything
from %I
$s$, array_to_string(column_names, ','), table_name);
return query execute l_sql;
END;
$BODY$;
Then you can use it like this:
select *
from matching('some_table', 'one', 'two', 'three');
I propose different but similar code.
With following script:
CREATE OR REPLACE PROCEDURE public.test(IN p_old_table text, IN p_old_column_names text[], IN p_new_table text)
LANGUAGE 'plpgsql'
AS $BODY$
DECLARE
old_column_list text;
ctas_stmt text;
BEGIN
old_column_list = array_to_string(p_old_column_names,',');
RAISE NOTICE 'old_column_list=%', old_column_list;
ctas_stmt = format('CREATE TABLE %s AS SELECT %s from %s', p_new_table, old_column_list, p_old_table);
RAISE NOTICE 'ctas_stmt=%', ctas_stmt;
EXECUTE ctas_stmt;
END;
$BODY$;
--
create table t(x int, y text, z timestamp, z1 text);
insert into t values (1, 'OK', current_timestamp, null);
select * from t;
--
call test('t',ARRAY['x','y','z'], 'tmp');
--
\d tmp;
select * from tmp;
I have following execution:
CREATE OR REPLACE PROCEDURE public.test(IN p_old_table text, IN p_old_column_names text[], IN p_new_table text)
LANGUAGE 'plpgsql'
AS $BODY$
DECLARE
old_column_list text;
ctas_stmt text;
BEGIN
old_column_list = array_to_string(p_old_column_names,',');
RAISE NOTICE 'old_column_list=%', old_column_list;
ctas_stmt = format('CREATE TABLE %s AS SELECT %s from %s', p_new_table, old_column_list, p_old_table);
RAISE NOTICE 'ctas_stmt=%', ctas_stmt;
EXECUTE ctas_stmt;
END;
$BODY$;
CREATE PROCEDURE
create table t(x int, y text, z timestamp, z1 text);
CREATE TABLE
insert into t values (1, 'OK', current_timestamp, null);
INSERT 0 1
select * from t;
x | y | z | z1
---+----+----------------------------+----
1 | OK | 2020-04-14 11:37:28.641328 |
(1 row)
call test('t',ARRAY['x','y','z'], 'tmp');
psql:tvar.sql:24: NOTICE: old_column_list=x,y,z
psql:tvar.sql:24: NOTICE: ctas_stmt=CREATE TABLE tmp AS SELECT x,y,z from t
CALL
Table "public.tmp"
Column | Type | Collation | Nullable | Default
--------+-----------------------------+-----------+----------+---------
x | integer | | |
y | text | | |
z | timestamp without time zone | | |
select * from tmp;
x | y | z
---+----+----------------------------
1 | OK | 2020-04-14 11:37:28.641328
(1 row)

Update row in trigger without recursion

I have two tables:
CREATE TABLE first (
id text primary key,
updated_at timestamp,
data text
);
CREATE TABLE second (
id text REFERENCES first (id),
book_error text,
);
and I need to update updated_at field in first table always, when any of these tables has updated. I wrote this:
CREATE FUNCTION update_timestamp() RETURNS trigger AS $$
BEGIN
UPDATE first
SET updated_at = current_timestamp
WHERE id = NEW.id;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
DO $$
DECLARE
t text;
BEGIN
FOR t IN
SELECT table_name FROM information_schema.tables
WHERE table_schema = 'public'
LOOP
EXECUTE format('CREATE TRIGGER update_timestamp
BEFORE INSERT OR UPDATE ON %I
FOR EACH ROW EXECUTE PROCEDURE update_timestamp()',
t);
END LOOP;
END;
$$ LANGUAGE plpgsql;
But it's not working because update statement inside my trigger causes call of this trigger again before executing.
How can I do update inside trigger without firing it trigger again?
Per the documentation:
TG_TABLE_NAME
Data type name; the name of the table that caused the trigger invocation.
Use the variable in the trigger function:
CREATE OR REPLACE FUNCTION update_timestamp() RETURNS trigger AS $$
BEGIN
IF TG_TABLE_NAME = 'first' THEN
NEW.updated_at = current_timestamp;
ELSE
UPDATE first
SET updated_at = current_timestamp
WHERE id = NEW.id;
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
From Postgresql documentation,
pg_trigger_depth() - current nesting level of PostgreSQL triggers (0
if not called, directly or indirectly, from inside a trigger)
You can use this inside your trigger function to check if it is called from inside trigger
DO $$
DECLARE
t text;
BEGIN
FOR t IN
SELECT table_name FROM information_schema.tables
WHERE table_schema = 'public'
LOOP
EXECUTE format('CREATE TRIGGER update_timestamp
BEFORE INSERT OR UPDATE ON %I
FOR EACH ROW
WHEN (pg_trigger_depth() = 0)
EXECUTE PROCEDURE update_timestamp()',
t);
END LOOP;
END;
$$ LANGUAGE plpgsql;
test=# Insert into first select 1,now(), 'test';
INSERT 0 1
test=# select * from first;
id | updated_at | data
----+----------------------------+------
1 | 2018-10-29 20:18:25.227281 | test
(1 row)
test=# Insert into second select 1, 'test_error';
INSERT 0 1
test=# select * from first;
id | updated_at | data
----+----------------------------+------
1 | 2018-10-29 20:19:07.456737 | test

How to know the date of modification of an SP?

Is it possible to know the date of modification and / or creation of an SP in PostgreSQL 9.4?
I need to identify them to upload them next Deploy.-
PostgreSQL has not this functionality. You can create own table and update it from event triggers.
create table updates(proc regprocedure primary key, t timestamp);
create or replace function event_trigger_for_ddl_command_end()
returns event_trigger as $$
declare obj record;
begin
for obj in select * from pg_event_trigger_ddl_commands()
loop
if obj.classid = 'pg_proc'::regclass then
insert into updates values(obj.objid, current_timestamp)
on conflict (proc) do update set t = current_timestamp
where updates.proc = excluded.proc;
end if;
end loop;
end;
$$ language plpgsql;
create event trigger trigger_for_ddl_command_end
on ddl_command_end
execute procedure event_trigger_for_ddl_command_end();
create or replace function fx(a int) returns int as $$ select 1 $$ language sql;
postgres=# select * from updates ;
+-------------+----------------------------+
| proc | t |
+-------------+----------------------------+
| fx(integer) | 2017-11-22 14:21:11.367036 |
+-------------+----------------------------+
(1 row)
-- alternative code without INSERT ON CONFLICT
create or replace function event_trigger_for_ddl_command_end()
returns event_trigger as $$
declare obj record;
begin
for obj in select * from pg_event_trigger_ddl_commands()
loop
if obj.classid = 'pg_proc'::regclass then
begin
update updates set t = current_timestamp
where proc = obj.objid;
if not found then
begin
insert into updates values(obj.objid, current_timestamp);
exception when unique_violation then
update updates set t = current_timestamp
where proc = obj.objid;
end;
end if;
end if;
end loop;
end;
$$ language plpgsql;

how to get the affected base table row count in a statement level trigger

I have these tables:
CREATE EXTENSION citext;
CREATE EXTENSION "uuid-ossp";
CREATE TABLE cities
(
city_id serial PRIMARY KEY,
city_name citext NOT NULL UNIQUE
);
INSERT INTO cities(city_name) VALUES
('New York'), ('Paris'), ('Madrid');
CREATE TABLE etags
(
etag_name varchar(128) PRIMARY KEY,
etag_value uuid
);
INSERT INTO etags(etag_name, etag_value)
VALUES ('cities', uuid_generate_v4());
I want to update the cities etag when the cities table changes. If no rows are affected by the insert, update or delete statement, I'd like to avoid to change the cities etag, so I wrote the following statement level trigger:
CREATE OR REPLACE FUNCTION update_etag()
RETURNS trigger AS
$BODY$
DECLARE
record_count integer;
vetag_name varchar(128);
BEGIN
GET DIAGNOSTICS record_count = ROW_COUNT;
vetag_name := TG_ARGV[0];
RAISE NOTICE 'affected %:%', vetag_name, record_count;
IF record_count = 0 THEN
RETURN NULL;
END IF;
UPDATE etags SET etag_value = uuid_generate_v4()
WHERE etag_name = vetag_name;
RETURN null;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
CREATE TRIGGER update_cities_etag_trigger
AFTER INSERT OR UPDATE OR DELETE
ON cities
FOR EACH STATEMENT
EXECUTE PROCEDURE update_etag('cities');
However GET DIAGNOSTICS record_count = ROW_COUNT; doesn't work for me, as it always returns 0.
If I execute the following:
DELETE FROM cities;
The following is output:
NOTICE: affected cities:0 Query returned successfully: 3 rows
affected, 47 msec execution time.
Is there a way to figure out how many rows are affected by the statement that triggers the trigger in a PostgreSQL statement-level trigger?
Version 10
CREATE TRIGGER
...
[ REFERENCING { { OLD | NEW } TABLE [ AS ] transition_relation_name } [ ... ] ]
...
https://www.postgresql.org/docs/current/static/release-10.html
Add AFTER trigger transition tables to record changed rows (Kevin
Grittner, Thomas Munro)
Transition tables are accessible from triggers written in server-side
languages.
Example
Solves it:
CREATE OR REPLACE FUNCTION update_etag()
RETURNS trigger AS
$BODY$
DECLARE
record_count integer;
vetag_name varchar(128);
begin
IF (TG_OP = 'DELETE') or (TG_OP = 'UPDATE') THEN
select count(*) from oldtbl into record_count ;
ELSE
select count(*) from newtbl into record_count ;
END IF;
vetag_name := TG_ARGV[0];
RAISE NOTICE 'affected %:%:%', vetag_name,TG_OP, record_count;
IF record_count = 0 THEN
RETURN NULL;
END IF;
UPDATE etags SET etag_value = uuid_generate_v4()
WHERE etag_name = vetag_name;
RETURN null;
END;
$BODY$
LANGUAGE plpgsql VOLATILE;
CREATE TRIGGER update_ins_cities_etag_trigger
AFTER INSERT
ON cities
REFERENCING NEW TABLE AS newtbl
FOR EACH STATEMENT
EXECUTE PROCEDURE update_etag('cities');
CREATE TRIGGER update_upd_cities_etag_trigger
AFTER UPDATE
ON cities
REFERENCING OLD TABLE AS oldtbl
FOR EACH STATEMENT
EXECUTE PROCEDURE update_etag('cities');
CREATE TRIGGER update_del_cities_etag_trigger
AFTER DELETE
ON cities
REFERENCING OLD TABLE AS oldtbl
FOR EACH STATEMENT
EXECUTE PROCEDURE update_etag('cities');
so=# INSERT INTO cities(city_name) VALUES
so-# ('New York'), ('Paris'), ('Madrid');
NOTICE: affected cities:INSERT:3
INSERT 0 3
so=# select * from etags;
etag_name | etag_value
-----------+--------------------------------------
cities | dc7d1525-eea7-4822-b736-5141a20764f8
(1 row)
so=# insert into cities(city_name) values ('Budapest');
NOTICE: affected cities:INSERT:1
INSERT 0 1
so=# select * from etags;
etag_name | etag_value
-----------+--------------------------------------
cities | df835f44-dada-4a94-bb62-5890f2316103
(1 row)
so=# delete from cities where city_id > 42;
NOTICE: affected cities:DELETE:0
DELETE 0
so=# select * from etags;
etag_name | etag_value
-----------+--------------------------------------
cities | df835f44-dada-4a94-bb62-5890f2316103
(1 row)

Update tables logic

I have two tables with triggers on them.
FIRST
CREATE OR REPLACE FUNCTION update_table()
RETURNS trigger AS
$BODY$
BEGIN
IF TG_OP = 'UPDATE' THEN
UPDATE filedata SET id=NEW.id,myData=NEW.myData,the_geom=ST_TRANSFORM(NEW.the_geom,70066) WHERE num=NEW.num;
RETURN NEW;
ELSEIF TG_OP = 'INSERT' THEN
INSERT INTO filedata(num,id,myData,the_geom) VALUES (NEW.num,NEW.id,NEW.myData,ST_TRANSFORM(NEW.the_geom,70066));
INSERT INTO filestatus(id,name,status) VALUES (NEW.num,NEW.myData,'Не подтвержден');
RETURN NEW;
END IF;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
SECOND
CREATE OR REPLACE FUNCTION update_table_temp()
RETURNS trigger AS
$BODY$
BEGIN
IF TG_OP = 'INSERT' THEN
INSERT INTO filedata_temp(num,id,myData,the_geom) VALUES (NEW.num,NEW.id,NEW.myData,ST_TRANSFORM(NEW.the_geom,900913));
RETURN NEW;
ELSEIF TG_OP = 'DELETE' THEN
DELETE FROM filedata_temp WHERE num=OLD.num;
RETURN OLD;
END IF;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
And I have a problem. If I insert data in the first table its trigger inserts data in the second table too. But that insert causes the second table's trigger to do an insert on the first table, and so on.
Can you help me with this? How to can I get the tables to update each other without looping?
UPDATE
i have another problem
How to change data when i INSERT it in table? For example i insert GEOMETRY in the_geom column. And if geometry's SRID=70066 i want to put in the_geom column result of working of this function ST_TRANSFORM(the_geom,900913).
UPDATE 2
trigger
CREATE TRIGGER update_geom
AFTER INSERT
ON filedata_temp
FOR EACH ROW
EXECUTE PROCEDURE update_geom();
function
CREATE OR REPLACE FUNCTION update_geom()
RETURNS trigger AS
$$
BEGIN
IF ST_SRID(NEW.the_geom)=70066 THEN
UPDATE filedata_temp SET id='88',the_geom=ST_TRANSFORM(NEW.the_geom,900913);
END IF;
RETURN NEW;
END;
$$
LANGUAGE plpgsql;
If i use this function trigger no work but if this:
CREATE OR REPLACE FUNCTION update_geom()
RETURNS trigger AS
$$
BEGIN
UPDATE filedata_temp SET id='88',the_geom=ST_TRANSFORM(NEW.the_geom,900913);
RETURN NEW;
END;
$$
LANGUAGE plpgsql;
i get id=88 but ST_TRANSFORM not work.
UPDATE 3
ST_TRANSFORM() nice function but its do something strange in my case.
For example i have a table filedata_temp(SRID=4326). I Insert geometry with srid=70066 i try this trigger
CREATE OR REPLACE FUNCTION update_geom()
RETURNS trigger AS
$$
BEGIN
UPDATE filedata_temp the_geom=ST_TRANSFORM(NEW.the_geom,4326);
RETURN NEW;
END;
$$
LANGUAGE plpgsql;
And get this geometry.
"0103000020E6100000010000001800000097832C7ABD823741DA312CBF59F6174145ED23E0088337413CB8228A65F7174145ED23E0088337413CB8228A65F7174145ED23E0088337413CB8228A65F7174115B8A7F8208337416DE8C689ADF7174115B8A7F8208337416DE8C689ADF71741D1D3BAF56383374114BFD1303AF917418B016D395F8537413C2856DFF7F717413AF95F044C853741A997BC22A3F71741F88E75BD2D85374178C92D9BE6F61741F92A3B192685374165C8D76E31F61741C84AA37B26853741F2674F6A96F5174144F25B9B16853741E849D10C1BF5174105142CD2E384374112E19E8688F31741B72C78F697843741A808260138F31741FF0C0C6A0884374151A8BBFF76F21741832CF2EEF48337418BE15C1290F21741FFFB3AC6A3833741D85A253DF4F2174113E8B8956C83374109067F2139F31741E383648E3383374100C25C64D8F3174179BAEBD7178337412DA0D6482BF41741CF38E4F7038337410AB04BD7E5F41741C936158CE182374145C1EC5D99F5174197832C7ABD823741DA312CBF59F61741"
ST_transform() make this string from SRID=4326 and geometry which transform in EPSG:70066.
There is this string in 70066
"0103000020B2110100010000001800000097832C7ABD823741DA312CBF59F6174145ED23E0088337413CB8228A65F7174145ED23E0088337413CB8228A65F7174145ED23E0088337413CB8228A65F7174115B8A7F8208337416DE8C689ADF7174115B8A7F8208337416DE8C689ADF71741D1D3BAF56383374114BFD1303AF917418B016D395F8537413C2856DFF7F717413AF95F044C853741A997BC22A3F71741F88E75BD2D85374178C92D9BE6F61741F92A3B192685374165C8D76E31F61741C84AA37B26853741F2674F6A96F5174144F25B9B16853741E849D10C1BF5174105142CD2E384374112E19E8688F31741B72C78F697843741A808260138F31741FF0C0C6A0884374151A8BBFF76F21741832CF2EEF48337418BE15C1290F21741FFFB3AC6A3833741D85A253DF4F2174113E8B8956C83374109067F2139F31741E383648E3383374100C25C64D8F3174179BAEBD7178337412DA0D6482BF41741CF38E4F7038337410AB04BD7E5F41741C936158CE182374145C1EC5D99F5174197832C7ABD823741DA312CBF59F61741"
And in 4326
"0103000020E61000000100000018000000AE4F5BA2FC5B4E407E80E7E6F46C4C40F7F1BF79255C4E4019C32D62086D4C40F7F1BF79255C4E4019C32D62086D4C40F7F1BF79255C4E4019C32D62086D4C40A7CE9382325C4E40D8EA369C0D6D4C40A7CE9382325C4E40D8EA369C0D6D4C401BD2B101575C4E4064A420982A6D4C4090DF29FE665D4E4064EE5369116D4C408195B3905C5D4E403664043C0B6D4C4025A00D0E4C5D4E40F7FD7274FD6C4C404201C7B5475D4E409ADF7B26F06C4C403801C7B5475D4E40E43D0EBFE46C4C406EC339053F5D4E404085D2B7DB6C4C40BDFDA836235D4E4001EBC841BE6C4C40685B445FFA5C4E4015C4038EB86C4C40ADB5C108AD5C4E40727935C6AA6C4C408A6B4B9BA25C4E40331ECEACAC6C4C40A7368928775C4E40F7C22E47B46C4C409F640F9D595C4E4077694F81B96C4C40660C21333B5C4E4012EA7C62C56C4C406623646D2C5C4E40CE83E38FCB6C4C4042D9EDFF215C4E40C6A89957D96C4C4095D75EC00F5C4E4013FFA0A5E66C4C40AE4F5BA2FC5B4E407E80E7E6F46C4C40"
You have mutually recursive triggers and you want to prevent the recursion. Your instead want a trigger to fire only on a direct action from a user, not an action via a trigger.
Unfortunately, PostgreSQL doesn't directly support what you want, you'll need to tweak your design to avoid the mutual recursion.
Updated question: In a trigger, alter the contents of NEW, eg
IF tg_op = 'INSERT' OR tg_op = 'UPDATE' THEN
NEW.the_geom := ST_TRANSFORM(NEW.the_geom,900913)
END IF;
See the really rather good manual for triggers.
-- The scenario is:
-- for UPDATEs we use an "alternating bit protocol"
-- (could also be done by bumping and synchronisng a serial number)
-- For INSERTs: we only test for NOT EXISTS.
-- DELETEs are not yet implemented.
-- *******************************************************************
DROP SCHEMA tmp CASCADE;
CREATE SCHEMA tmp ;
SET search_path=tmp;
--
-- Tables for test: we convert int <<-->> text
--
CREATE TABLE one
( id INTEGER NOT NULL PRIMARY KEY
, flipflag boolean NOT NULL default false
, ztext varchar
);
CREATE TABLE two
( id INTEGER NOT NULL PRIMARY KEY
, flipflag boolean NOT NULL default false
, zval INTEGER
);
------------------------
CREATE function func_one()
RETURNS TRIGGER AS $body$
BEGIN
IF tg_op = 'INSERT' THEN
INSERT INTO two (id,zval)
SELECT NEW.id, NEW.ztext::integer
WHERE NOT EXISTS (
SELECT * FROM two WHERE two.id = NEW.id)
;
ELSIF tg_op = 'UPDATE' THEN
UPDATE two
SET zval = NEW.ztext::integer
, flipflag = NOT flipflag
WHERE two.id = NEW.id
;
END IF;
RETURN NEW;
END;
$body$
language plpgsql;
CREATE TRIGGER trig_one_i
AFTER INSERT ON one
FOR EACH ROW
EXECUTE PROCEDURE func_one()
;
CREATE TRIGGER trig_one_u
AFTER UPDATE ON one
FOR EACH ROW
WHEN (NEW.flipflag = OLD.flipflag)
EXECUTE PROCEDURE func_one()
;
------------------------
CREATE function func_two()
RETURNS TRIGGER AS $body$
BEGIN
IF tg_op = 'INSERT' THEN
INSERT INTO one (id,ztext)
SELECT NEW.id, NEW.zval::varchar
WHERE NOT EXISTS (
SELECT * FROM one WHERE one.id = NEW.id)
;
ELSIF tg_op = 'UPDATE' THEN
UPDATE one
SET ztext = NEW.zval::varchar
, flipflag = NOT flipflag
WHERE one.id = NEW.id
;
END IF;
RETURN NEW;
END;
$body$
language plpgsql;
CREATE TRIGGER trig_two_i
AFTER INSERT ON two
FOR EACH ROW
EXECUTE PROCEDURE func_two()
;
CREATE TRIGGER trig_two_u
AFTER UPDATE ON two
FOR EACH ROW
WHEN (NEW.flipflag = OLD.flipflag)
EXECUTE PROCEDURE func_two()
; --
-- enter some data
--
INSERT INTO one (id,ztext)
select gs, gs::text
FROM generate_series(1,10) gs
;
-- Change some data
UPDATE one SET ztext=100 where id = 1;
UPDATE two SET zval=10*zval where id IN (2,4,6,8,10);
INSERT INTO two (id, zval) VALUES(11,14);
SELECT * FROM one ORDER BY id;
SELECT * FROM two ORDER BY id;
RESULT:
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "one_pkey" for table "one"
CREATE TABLE
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "two_pkey" for table "two"
CREATE TABLE
CREATE FUNCTION
CREATE TRIGGER
CREATE TRIGGER
CREATE FUNCTION
CREATE TRIGGER
CREATE TRIGGER
INSERT 0 10
UPDATE 1
UPDATE 5
INSERT 0 1
id | flipflag | ztext
----+----------+-------
1 | f | 100
2 | t | 20
3 | f | 3
4 | t | 40
5 | f | 5
6 | t | 60
7 | f | 7
8 | t | 80
9 | f | 9
10 | t | 100
11 | f | 14
(11 rows)
id | flipflag | zval
----+----------+------
1 | t | 100
2 | f | 20
3 | f | 3
4 | f | 40
5 | f | 5
6 | f | 60
7 | f | 7
8 | f | 80
9 | f | 9
10 | f | 100
11 | f | 14
(11 rows)