PostgreSQL 9.4 – How to Pass OLD and NEW to a Function in PL/pgSQL

functionsplpgsqlpostgresqlpostgresql-9.4

I've got 2 triggers. triggerA and triggerB that acts upon changes on tableA and tableB respectively. Inside both those triggers I want to use the same function that uses the OLD & NEW variables. I don't know how to do so because it throws me the error:

OLD hasn't been assigned yet.
The tuple structure of a not-yet-assigned record is indeterminate.

Then I tried assigning null to a variable to get around that and it's:

old_v hasn't been assigned yet.

trigger 1 & 2 (this part is common in both triggers):

DECLARE 
    added added_scores;
    old_v record;
    new_v record;
BEGIN
    CASE TG_OP
        WHEN 'INSERT' THEN
            old_v = null;
            new_v = NEW;
        WHEN 'UPDATE' THEN
            old_v = OLD;
            new_v = NEW;
        WHEN 'DELETE' THEN
            old_v = OLD;
            new_v = null;
    END CASE;

    select _i_compute_added_scores(TG_OP, old_v, new_v) into added;
        -- some computation, return result

function :

CREATE OR REPLACE FUNCTION public._i_compute_added_scores(
    tg_op_p text,
    old_p anyelement,
    new_p anyelement)
  RETURNS added_scores AS
$BODY$

DECLARE
    new_score integer;
    old_score integer;
    res added_scores;
BEGIN
    CASE TG_OP_p
        WHEN 'INSERT' THEN
            new_score := new_p.score;
            old_score := 0;
        WHEN 'DELETE' THEN
            new_score := 0;
            old_score := old_p.score;
        WHEN 'UPDATE' THEN
            new_score := new_p.score;
            old_score := old_p.score;
    END CASE;

-- some more computation and return

Best Answer

You need to assign the RECORD type before sending it as parameter, and a very simple way to do that in your case would be simple assigning it to NEW or OLD even when it wouldn't be necessary, like:

CASE TG_OP
    WHEN 'INSERT' THEN
        old_v = NEW;
        new_v = NEW;
    WHEN 'UPDATE' THEN
        old_v = OLD;
        new_v = NEW;
    WHEN 'DELETE' THEN
        old_v = OLD;
        new_v = OLD;
END CASE;

Notice that now it is very important to use TG_OP and control which variables you must read/use.