Thread: trigger question

trigger question

From
mikeo
Date:
hi,
  i've created a function as follows:

drop function rates_hist_function();
CREATE function rates_hist_function()
        returns opaque
        as 'BEGIN
               if ( old.rt_valid <> ''P'' or new.rt_valid not in
(''Y'',''N''))
                then
                  new.rt_timestamp = now();
                  insert into rates_hist values (
                        new.cut_id,new.ct_key,new.rtm_id,new.rt_sell_factor,

new.rt_sell_msg_cost,new.rt_sell_init_sec,new.rt_sell_init_cost,

new.rt_sell_addl_sec,new.rt_sell_addl_cost,new.rt_buy_factor,

new.rt_buy_msg_cost,new.rt_buy_init_sec,new.rt_buy_init_cost,

new.rt_buy_addl_sec,new.rt_buy_addl_cost,new.rt_valid,new.rse_id,
                        new.wu_id,new.rt_timestamp, new.rt_usoc_def_factor
                        );
               end if;
               return new;
            END;'
language 'plpgsql';

and i call it from this trigger:

drop TRIGGER rates_hist_trigger on rates;
CREATE TRIGGER rates_hist_trigger
        after insert or update on rates
        for each row
        execute procedure rates_hist_function();

when i attempt to insert a row into the rates table using this statement:

insert into rates(cut_id,ct_key,rt_valid,...,rt_timestamp,rt_usoc_def_factor)
          values ('mikeo',123456,'x',...,now(),1.35);

i get this error:
ERROR:  record old is unassigned yet

since this trigger is for both insert or update, why does it expect the "OLD"
value to already exist, as it would not for insert?  second, is there a way
to tell a function that it's inserting or updating, as in oracle's
"if updating..."?


thanks,
    mikeo

Re: trigger question

From
Tom Lane
Date:
mikeo <mikeo@spectrumtelecorp.com> writes:
> CREATE function rates_hist_function()
>         returns opaque
>         as 'BEGIN
>                if ( old.rt_valid <> ''P'' or new.rt_valid not in (''Y'',''N''))
                      ^^^^^^^^^^^^

> i get this error:
> ERROR:  record old is unassigned yet

> since this trigger is for both insert or update, why does it expect
> the "OLD" value to already exist, as it would not for insert?

Because you referenced it in the function code.  Am I missing something?

            regards, tom lane

Re: trigger question

From
mikeo
Date:
At 10:33 AM 6/27/00 -0400, Tom Lane wrote:
>mikeo <mikeo@spectrumtelecorp.com> writes:
>> CREATE function rates_hist_function()
>>         returns opaque
>>         as 'BEGIN
>>                if ( old.rt_valid <> ''P'' or new.rt_valid not in
(''Y'',''N''))
>                      ^^^^^^^^^^^^
>
>> i get this error:
>> ERROR:  record old is unassigned yet
>
>> since this trigger is for both insert or update, why does it expect
>> the "OLD" value to already exist, as it would not for insert?
>
>Because you referenced it in the function code.  Am I missing something?
>
>            regards, tom lane
>

maybe.
in oracle, the triggers were smart enough to know not to reference
an old value on insert in an "insert or update" trigger procedure,
apparently.

this is the original oracle trigger that works fine
with the same insert statement:

CREATE OR REPLACE TRIGGER rates_hist_trigger
        before insert or update on rates
        for each row
             WHEN (old.rt_valid <> 'P' or new.rt_valid not in ('Y','N'))
        begin
        insert into rates_hist
                values
(:new.cut_id,:new.ct_key,:new.rtm_id,:new.rt_sell_factor,

:new.rt_sell_msg_cost,:new.rt_sell_init_sec,:new.rt_sell_init_cost,

:new.rt_sell_addl_sec,:new.rt_sell_addl_cost,:new.rt_buy_factor,

:new.rt_buy_msg_cost,:new.rt_buy_init_sec,:new.rt_buy_init_cost,

:new.rt_buy_addl_sec,:new.rt_buy_addl_cost,:new.rt_valid,:new.rse_id,
                        :new.wu_id, sysdate, :new.rt_usoc_def_factor
                       );
end;
/

i can easily get around this using rules.  my main objective is to not have to
change too much code as we migrate over to postgres from oracle and that is
not
too much of a change.

thanks,
   mikeo


Re: trigger question

From
Tom Lane
Date:
mikeo <mikeo@spectrumtelecorp.com> writes:
> in oracle, the triggers were smart enough to know not to reference
> an old value on insert in an "insert or update" trigger procedure,
> apparently.

> this is the original oracle trigger that works fine
> with the same insert statement:

> CREATE OR REPLACE TRIGGER rates_hist_trigger
>         before insert or update on rates
>         for each row
>              WHEN (old.rt_valid <> 'P' or new.rt_valid not in ('Y','N'))

Hmm.  It sounds to me like Oracle treats the OLD fields as being NULL
if the context is INSERT, which is something we could certainly do at
the price of losing some error detection capability --- ie, if that
really had been a typo as I first thought, the system wouldn't flag it
for you.

Not sure which way is better.  Comments anyone?

            regards, tom lane

Re: trigger question

From
mikeo
Date:
At 11:27 AM 6/27/00 -0400, Tom Lane wrote:
>mikeo <mikeo@spectrumtelecorp.com> writes:
>> in oracle, the triggers were smart enough to know not to reference
>> an old value on insert in an "insert or update" trigger procedure,
>> apparently.
>
>> this is the original oracle trigger that works fine
>> with the same insert statement:
>
>> CREATE OR REPLACE TRIGGER rates_hist_trigger
>>         before insert or update on rates
>>         for each row
>>              WHEN (old.rt_valid <> 'P' or new.rt_valid not in ('Y','N'))
>
>Hmm.  It sounds to me like Oracle treats the OLD fields as being NULL
>if the context is INSERT, which is something we could certainly do at
>the price of losing some error detection capability --- ie, if that
>really had been a typo as I first thought, the system wouldn't flag it
>for you.
>
>Not sure which way is better.  Comments anyone?
>
>            regards, tom lane
>

it would make the insert or update trigger more flexible, and ,
truly by an insert or update procedure, IMHO :), but is definitely not
a priority.  creating a rule for each is just as quick as writing a
function with a trigger to call it.

mikeo

Re: trigger question

From
tolik@aaanet.ru (Anatoly K. Lasareff)
Date:
>>>>> "m" == mikeo  <mikeo@spectrumtelecorp.com> writes:

 m> At 11:27 AM 6/27/00 -0400, Tom Lane wrote:
 >> mikeo <mikeo@spectrumtelecorp.com> writes:
 >>> in oracle, the triggers were smart enough to know not to reference
 >>> an old value on insert in an "insert or update" trigger procedure,
 >>> apparently.
 >>
 >>> this is the original oracle trigger that works fine
 >>> with the same insert statement:
 >>
 >>> CREATE OR REPLACE TRIGGER rates_hist_trigger
 >>> before insert or update on rates
 >>> for each row
 >>> WHEN (old.rt_valid <> 'P' or new.rt_valid not in ('Y','N'))
 >>
 >> Hmm.  It sounds to me like Oracle treats the OLD fields as being NULL
 >> if the context is INSERT, which is something we could certainly do at
 >> the price of losing some error detection capability --- ie, if that
 >> really had been a typo as I first thought, the system wouldn't flag it
 >> for you.
 >>
 >> Not sure which way is better.  Comments anyone?
 >>
 >> regards, tom lane
 >>

 m> it would make the insert or update trigger more flexible, and ,
 m> truly by an insert or update procedure, IMHO :), but is definitely not
 m> a priority.  creating a rule for each is just as quick as writing a
 m> function with a trigger to call it.

I suppose you have to use TG_OP variable in your triggers. Here is a
bit from documentation:

 ------
TG_OP

    Datatype text; a string of 'INSERT', 'UPDATE' or 'DELETE' telling for which operation the
    trigger is actually fired.
 -----

So, you can type something about

  if TG_OP <> 'UPDATE' then
    ... ops for insert only
  else
    ... ops for update only
  end if;

  ... ops for both of them

--
Anatoly K. Lasareff              Email:       tolik@aaanet.ru