Thread: Trigger loop question

Trigger loop question

From
Mike Nolan
Date:
I have some information that that I need to keep synchronized which can
be found in two different tables.   (Yes, it's not fully normalized.)

If I set up an on update trigger for table 'A' that updates the
corresponding column in table 'B', and one for table 'B' that updates
the corresponding column in table 'A', does that create an endless loop?
--
Mike Nolan

Re: Trigger loop question

From
Tom Lane
Date:
Mike Nolan <nolan@gw.tssi.com> writes:
> If I set up an on update trigger for table 'A' that updates the
> corresponding column in table 'B', and one for table 'B' that updates
> the corresponding column in table 'A', does that create an endless loop?

Yes.

You could break the loop perhaps by not issuing an UPDATE if the data is
already correct in the other table.

            regards, tom lane

Re: Trigger loop question

From
Mike Nolan
Date:
> Mike Nolan <nolan@gw.tssi.com> writes:
> > If I set up an on update trigger for table 'A' that updates the
> > corresponding column in table 'B', and one for table 'B' that updates
> > the corresponding column in table 'A', does that create an endless loop?
>
> Yes.
>
> You could break the loop perhaps by not issuing an UPDATE if the data is
> already correct in the other table.

The trigger on table 'A' is obviously going to see both the old value and the
new value for the column.  If it queries table 'B', it would see
the current value there.

However, if I update table 'B' and the 2nd trigger fires, that trigger
will still see the OLD value if does a query on table 'A', since I
think transaction atomic rules require that any updated values aren't
made available to the outside world (including other triggers) until the
transaction is complete.

I tested this, and the 2nd trigger still sees the original value of
the field from the first table, which I think is the proper result.
--
Mike Nolan


Re: Trigger loop question

From
Gregory Wood
Date:
Mike Nolan wrote:

> However, if I update table 'B' and the 2nd trigger fires, that trigger
> will still see the OLD value if does a query on table 'A', since I
> think transaction atomic rules require that any updated values aren't
> made available to the outside world (including other triggers) until the
> transaction is complete.

I could be mistaken here, but... I don't believe that is the case. The
transaction can see what's going on inside of itself. Everything outside
of the transaction typically won't see what is inside the transaction,
until it is committed anyway.

> I tested this, and the 2nd trigger still sees the original value of
> the field from the first table, which I think is the proper result.

I think this has more to do with whether the first trigger was fired
BEFORE or AFTER the UPDATE. If the first trigger is fired BEFORE the
UPDATE, then the second trigger (fired on the UPDATE) will not see the
AFTER values of the first trigger. If you fire the first trigger as
AFTER, I bet you'll see the changes.

Greg

Re: Trigger loop question

From
Mike Nolan
Date:
> I think this has more to do with whether the first trigger was fired
> BEFORE or AFTER the UPDATE. If the first trigger is fired BEFORE the
> UPDATE, then the second trigger (fired on the UPDATE) will not see the
> AFTER values of the first trigger. If you fire the first trigger as
> AFTER, I bet you'll see the changes.

Yes it does.  OK, that means Tom's original suggestion of checking
the other table for the same value before updating it should prevent
an infinite loop, providing that's done from a pair of 'after update'
triggers, using the NEW.column entries in the triggered table to update
the other table.

This tested OK in both directions.

Of course, if I need to do any manipulation of the fields in the
table being updated by the SQL command, that will require a separate
'before update' trigger.
--
Mike Nolan

Re: Trigger loop question

From
Tom Lane
Date:
Mike Nolan <nolan@gw.tssi.com> writes:
> Yes it does.  OK, that means Tom's original suggestion of checking
> the other table for the same value before updating it should prevent
> an infinite loop, providing that's done from a pair of 'after update'
> triggers, using the NEW.column entries in the triggered table to update
> the other table.

Actually, I wasn't thinking very clearly.  The easiest way to break
the loop is to avoid updating the other table when OLD.x = NEW.x
in the trigger's arguments.  The other way requires a rather-redundant
SELECT to see what is in the other table.

            regards, tom lane

Re: Trigger loop question

From
Mike Nolan
Date:
> Actually, I wasn't thinking very clearly.  The easiest way to break
> the loop is to avoid updating the other table when OLD.x = NEW.x
> in the trigger's arguments.  The other way requires a rather-redundant
> SELECT to see what is in the other table.

If I have to update the other table for any other purpose as part of
that trigger, or if some other trigger updates that table, couldn't that
result in an infinite loop?

It seems like the select-and-check method, even though it may be redundant
most of the time, is the belt-and-suspenders way of avoiding an infinite loop.

Here's a really weird question.  If in the trigger for table A I have
more than one statement that updates table B, or if more than one trigger
procedure updates table B, does that cause multiple firings of either
before or after update triggers on table B?
--
Mike Nolan

Re: Trigger loop question

From
Tom Lane
Date:
Mike Nolan <nolan@gw.tssi.com> writes:
>> Actually, I wasn't thinking very clearly.  The easiest way to break
>> the loop is to avoid updating the other table when OLD.x = NEW.x
>> in the trigger's arguments.  The other way requires a rather-redundant
>> SELECT to see what is in the other table.

> If I have to update the other table for any other purpose as part of
> that trigger, or if some other trigger updates that table, couldn't that
> result in an infinite loop?

Well, I'm assuming that your update logic converges to a fixed state;
if it doesn't, seems like you've got problems anyway ...

> Here's a really weird question.  If in the trigger for table A I have
> more than one statement that updates table B, or if more than one trigger
> procedure updates table B, does that cause multiple firings of either
> before or after update triggers on table B?

Yes, and yes.  You get one firing per row update event, IIRC, no matter
where that update came from.

            regards, tom lane