One of the occasionally annoying things about Plpgsql is that it's very static, and any sort of dynamic access to records, say by using a trigger argument, is difficult. I just conducted a little experiment that seems to make life a bit easier. The json_populate_record() function returns a record of the same type as its first argument. Mostly we just use NULL::record_type here, but it turns out that in a trigger function it works perfectly happily with NEW and OLD, and they can be modified using any sort of dynamic values you like, including values from TG_ARGV
Here's a simple example:
Here's a simple example:
mydb=# create type rainbow as enum('r','o','y','g','b','i','v');
CREATE TYPE
mydb=# create table foo (a text, b int, c boolean, d rainbow);
CREATE TABLE
mydb=# create or replace function foo_tr()
returns trigger
language plpgsql as $$
begin
if tg_op = 'INSERT' or tg_op = 'UPDATE'
then
return json_populate_record(NEW,json_object(TG_ARGV));
else
return old;
end if;
end;
$$;
CREATE FUNCTION
mydb=# create trigger foo_tri before insert on foo for each row execute procedure foo_tr(d,i);
CREATE TRIGGER
mydb=# create trigger foo_tru before update on foo for each row execute procedure foo_tr(c,true);
CREATE TRIGGER
mydb=# insert into foo values ('x',1,null,'r') returning *;
a | b | c | d
---+---+---+---
x | 1 | | i
(1 row)
INSERT 0 1
mydb=# update foo set c = null, d = 'o' returning *;
a | b | c | d
---+---+---+---
x | 1 | t | o
(1 row)
UPDATE 1
mydb=#