Thread: Behaviour of triggers on replicated and non replicated tables

Behaviour of triggers on replicated and non replicated tables

From
"Luiz K. Matsumura"
Date:
Hi,
I need help to know if the follow scenario is a expected behaviour, a
bug of postgres or a bug of slony:

Postgres v8.4.8
Slony-I v 2.0.5

I have table replicated with slony and that do some updates in another
table not replicated.

The trigger on replicated table was enabled on the slave database with
the command:

ALTER TABLE table1 ENABLE ALLWAYS TRIGGER trigger1;

And this trigger is working fine as expected.

The strange behaviour is that trigger do a update in another table not
replicated, let´s say table2, and
the triggers of this table is not fired.
A unexpected behaviour IMHO, if I do

ALTER TABLE table2 ENABLE ALWAYS TRIGGER trigger2;

Then the trigger2 is fired now when trigger1 do a update in table2.

My doubt is: since table2 is not replicated why they triggers dont fire
even by a update command in
a trigger of a replicated table ?


Best Regards,

Luiz K. Matsumura

Re: Behaviour of triggers on replicated and non replicated tables

From
Robert Haas
Date:
2011/6/10 Luiz K. Matsumura <luiz@planit.com.br>:
> I need help to know if the follow scenario is a expected behaviour, a bug=
 of
> postgres or a bug of slony:
>
> Postgres v8.4.8
> Slony-I v 2.0.5
>
> I have table replicated with slony and that do some updates in another ta=
ble
> not replicated.
>
> The trigger on replicated table was enabled on the slave database with the
> command:
>
> ALTER TABLE table1 ENABLE ALLWAYS TRIGGER trigger1;
>
> And this trigger is working fine as expected.
>
> The strange behaviour is that trigger do a update in another table not
> replicated, let=B4s say table2, and
> the triggers of this table is not fired.
> A unexpected behaviour IMHO, if I do
>
> ALTER TABLE table2 ENABLE ALWAYS TRIGGER trigger2;
>
> Then the trigger2 is fired now when trigger1 do a update in table2.
>
> My doubt is: since table2 is not replicated why they triggers dont fire e=
ven
> by a update command in
> a trigger of a replicated table ?

I'm confused.  If you enable the trigger on table2, it's going to fire
when someone updates table2.  Whether or not the update is coming from
another trigger or directly from the user has nothing to do with it.

--=20
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company

Fwd: Behaviour of triggers on replicated and non replicated tables

From
Christopher Browne
Date:
2011/6/10 Luiz K. Matsumura <luiz@planit.com.br>:
> Hi,
> I need help to know if the follow scenario is a expected behaviour, a bug=
 of
> postgres or a bug of slony:
>
> Postgres v8.4.8
> Slony-I v 2.0.5
>
> I have table replicated with slony and that do some updates in another ta=
ble
> not replicated.
>
> The trigger on replicated table was enabled on the slave database with the
> command:
>
> ALTER TABLE table1 ENABLE ALLWAYS TRIGGER trigger1;
>
> And this trigger is working fine as expected.
>
> The strange behaviour is that trigger do a update in another table not
> replicated, let=B4s say table2, and
> the triggers of this table is not fired.
> A unexpected behaviour IMHO, if I do
>
> ALTER TABLE table2 ENABLE ALWAYS TRIGGER trigger2;
>
> Then the trigger2 is fired now when trigger1 do a update in table2.
>
> My doubt is: since table2 is not replicated why they triggers dont fire e=
ven
> by a update command in
> a trigger of a replicated table ?

The *normal* behaviour that Slony has is that triggers on replicated
tables should, normally, not fire on a replica.

That's typically the right thing, as typically, the trigger fired on
the master, and shouldn't need to fire again. =A0A pretty usual case is
with foreign key triggers. =A0Reiterating, if the foreign key trigger is
checked on the master, there's not much sense in checking it again on
the replica.

There's why the "default" is that triggers aren't set to ENABLE ALWAYS.

Evidently you have another scenario, where you know you need to run
the triggers even on a subscriber.

I'm not 100% sure that I'm understanding the "doubt"...

If the trigger is enabled on table2, then it's going to run whenever
something updates table2; that's pretty well independent of any
replication infrastructure.

It's not clear to me whether your "trigger1" is specifically doing
some update to table2.

If the trigger on table1 is indeed firing, and trigger "trigger1"
calls a function that updates data in table2, then I'd fully expect
the trigger "trigger2" on table2 to, at that point, fire.

I can see a good reason for that sequence of events to break down,
namely if the function for "trigger1" doesn't actually find any data
to touch in table2.

For instance, if the function for trigger1 includes the query:

=A0 update table2 set id =3D id * 2;

that would *usually* be expected to update all the tuples in table2,
and fire the trigger "trigger2" once for each tuple that is updated.

But supposing table2 happens to be empty, then that UPDATE request
will find no tuples to operate on, and so the trigger "trigger2" won't
fire as much as once.

That's where the "deep details" lie; whether trigger2 fires depends on
what the function that trigger1 fires actually does.

If you have a bug, or an unexpected data pattern, then perhaps
trigger2 doesn't fire even though you expected it to. =A0That's one of
the troublesome risks you find when programming with triggers.

I had a "trigger bug" come in this week. =A0I discovered that there was
quite a bad bug in a trigger function, and this bug had persisted for
nearly a year before someone finally did something that exercised it.
I felt rather dumb when I saw it, as, in retrospect, it was an obvious
error. =A0Sadly, a lot of our mistakes fall from things that, in
retrospect, are "obvious errors."

Triggers are weird enough that intuition fails pretty easily :-(.
--=20
When confronted by a difficult problem, solve it by reducing it to the
question, "How would the Lone Ranger handle this?"

Re: Behaviour of triggers on replicated and non replicated tables

From
"Luiz K. Matsumura"
Date:
Em 16/06/2011 19:17, Christopher Browne escreveu:
> 2011/6/10 Luiz K. Matsumura<luiz@planit.com.br>:
>> Hi,
>> I need help to know if the follow scenario is a expected behaviour, a bug of
>> postgres or a bug of slony:
>>
>> Postgres v8.4.8
>> Slony-I v 2.0.5
>>
>> I have table replicated with slony and that do some updates in another table
>> not replicated.
>>
>> The trigger on replicated table was enabled on the slave database with the
>> command:
>>
>> ALTER TABLE table1 ENABLE ALLWAYS TRIGGER trigger1;
>>
>> And this trigger is working fine as expected.
>>
>> The strange behaviour is that trigger do a update in another table not
>> replicated, let´s say table2, and
>> the triggers of this table is not fired.
>> A unexpected behaviour IMHO, if I do
>>
>> ALTER TABLE table2 ENABLE ALWAYS TRIGGER trigger2;
>>
>> Then the trigger2 is fired now when trigger1 do a update in table2.
>>
>> My doubt is: since table2 is not replicated why they triggers dont fire even
>> by a update command in
>> a trigger of a replicated table ?
> The *normal* behaviour that Slony has is that triggers on replicated
> tables should, normally, not fire on a replica.
>
> That's typically the right thing, as typically, the trigger fired on
> the master, and shouldn't need to fire again.  A pretty usual case is
> with foreign key triggers.  Reiterating, if the foreign key trigger is
> checked on the master, there's not much sense in checking it again on
> the replica.
>
> There's why the "default" is that triggers aren't set to ENABLE ALWAYS.
>
> Evidently you have another scenario, where you know you need to run
> the triggers even on a subscriber.
>
> I'm not 100% sure that I'm understanding the "doubt"...
>
> If the trigger is enabled on table2, then it's going to run whenever
> something updates table2; that's pretty well independent of any
> replication infrastructure.
>
> It's not clear to me whether your "trigger1" is specifically doing
> some update to table2.
>
> If the trigger on table1 is indeed firing, and trigger "trigger1"
> calls a function that updates data in table2, then I'd fully expect
> the trigger "trigger2" on table2 to, at that point, fire.
>
> I can see a good reason for that sequence of events to break down,
> namely if the function for "trigger1" doesn't actually find any data
> to touch in table2.
>
> For instance, if the function for trigger1 includes the query:
>
>     update table2 set id = id * 2;
>
> that would *usually* be expected to update all the tuples in table2,
> and fire the trigger "trigger2" once for each tuple that is updated.
>
> But supposing table2 happens to be empty, then that UPDATE request
> will find no tuples to operate on, and so the trigger "trigger2" won't
> fire as much as once.
>
> That's where the "deep details" lie; whether trigger2 fires depends on
> what the function that trigger1 fires actually does.
>
> If you have a bug, or an unexpected data pattern, then perhaps
> trigger2 doesn't fire even though you expected it to.  That's one of
> the troublesome risks you find when programming with triggers.
>
> I had a "trigger bug" come in this week.  I discovered that there was
> quite a bad bug in a trigger function, and this bug had persisted for
> nearly a year before someone finally did something that exercised it.
> I felt rather dumb when I saw it, as, in retrospect, it was an obvious
> error.  Sadly, a lot of our mistakes fall from things that, in
> retrospect, are "obvious errors."
>
> Triggers are weird enough that intuition fails pretty easily :-(.
>
>
Hi Christopher , thanks for reply.

My english is not so good, so please pardon me if I not explain the
problem clearly.
I will try to explain better with a more pratical example (just a
simplified example)



CREATE TABLE table1
(
   id serial NOT NULL,
   idtable2 integer NOT NULL,
   qtty integer NOT NULL,
   CONSTRAINT pk_table1 PRIMARY KEY (id)
)

CREATE TABLE table2
(
   id serial NOT NULL,
   qtty integer NOT NULL,
   qtty_used integer NOT NULL,
   lused boolean DEFAULT false,
   CONSTRAINT pk_table2 PRIMARY KEY (id)
)

CREATE OR REPLACE FUNCTION trigger1()
   RETURNS trigger AS
$BODY$
BEGIN

     IF  tg_op = 'DELETE' THEN
         UPDATE  table2
         SET qtty_used= qtty_used- old.qtty
         WHERE   id = old.idtable2;

     ELSIF  tg_op = 'INSERT' THEN

         UPDATE  vd.pdvendai
         SET qtty_used= qtty_used+ new.qtty
         WHERE   id = new.idtable2;

     ELSIF tg_op = 'UPDATE' THEN

         UPDATE  vd.pdvendai
         SET qtty_used= qtty_used+ new.qtty - old.qtty
         WHERE   id = new.idtable2;

     END IF.

     IF  tg_op = 'DELETE' THEN
         RETURN old ;
     ELSE
         RETURN new ;
     END IF;

END;
$BODY$
   LANGUAGE plpgsql VOLATILE;

CREATE TRIGGER trg_table1
   AFTER INSERT OR UPDATE OR DELETE
   ON table1
   FOR EACH ROW
   EXECUTE PROCEDURE trigger1();


CREATE OR REPLACE FUNCTION trigger2()
   RETURNS trigger AS
$BODY$
BEGIN
     new.lused = ( new.qtty_used>= new.qtty );

     RETURN new;
END
$BODY$
   LANGUAGE plpgsql VOLATILE;

CREATE TRIGGER trg_table2
   BEFORE INSERT OR UPDATE
   ON table2
   FOR EACH ROW
   EXECUTE PROCEDURE trigger2();


And then create a replication of table1 and enable the trigger
trg_table1 in all databases:

ALTER TABLE table1 ENABLE ALLWAYS TRIGGER trg_trigger1;



Then suppose in table2 of slave database I have this data

table2
id | qtty | qtty_used | lused
---+------+-----------+--------
  1 |   10 |         0 | false


If I do a insert in master database :

INSERT INTO table1 (idtable2,qtty ) VALUES ( 1, 10 )

the result on slave database table2 after replication of data in table1 is

table2
id | qtty | qtty_used | lused
---+------+-----------+--------
  1 |   10 |        10 | false <-- lused not changed to true


So the trigger trg_table2 not fire by default when the origin is from a
replication.
But my sense is that since table2 is not in replication the trigger
trg_table2 must fire
in this scenario.




--
Luiz K. Matsumura
*
*

Re: Behaviour of triggers on replicated and non replicated tables

From
"Luiz K. Matsumura"
Date:
Em 16/06/2011 16:39, Robert Haas escreveu:
> 2011/6/10 Luiz K. Matsumura<luiz@planit.com.br>:
>> I need help to know if the follow scenario is a expected behaviour, a bug of
>> postgres or a bug of slony:
>>
>> Postgres v8.4.8
>> Slony-I v 2.0.5
>>
>> I have table replicated with slony and that do some updates in another table
>> not replicated.
>>
>> The trigger on replicated table was enabled on the slave database with the
>> command:
>>
>> ALTER TABLE table1 ENABLE ALLWAYS TRIGGER trigger1;
>>
>> And this trigger is working fine as expected.
>>
>> The strange behaviour is that trigger do a update in another table not
>> replicated, let´s say table2, and
>> the triggers of this table is not fired.
>> A unexpected behaviour IMHO, if I do
>>
>> ALTER TABLE table2 ENABLE ALWAYS TRIGGER trigger2;
>>
>> Then the trigger2 is fired now when trigger1 do a update in table2.
>>
>> My doubt is: since table2 is not replicated why they triggers dont fire even
>> by a update command in
>> a trigger of a replicated table ?
> I'm confused.  If you enable the trigger on table2, it's going to fire
> when someone updates table2.  Whether or not the update is coming from
> another trigger or directly from the user has nothing to do with it.
>
Thanks for reply Robert.

This is the point, when the trigger of table2 was create with a command
like this

CREATE TRIGGER trg_table2
   BEFORE INSERT OR UPDATE
   ON table2
   FOR EACH ROW
   EXECUTE PROCEDURE trg_table2();

The trigger is enabled by default as expected. If I do a update on
table2 the trigger fire normally.
But when a replicated table fire a trigger that do the same update, now
the trigger on table2 don´t fire.
I don´t know if this is slony disabling all triggers  unless REPLICA and
ALLWAYS trrigers even over not replicated
tables or this is managed by postgresql


--
Luiz K. Matsumura
*
*

Re: Behaviour of triggers on replicated and non replicated tables

From
Robert Haas
Date:
2011/6/16 Luiz K. Matsumura <luiz@planit.com.br>:
> Em 16/06/2011 16:39, Robert Haas escreveu:
>
> 2011/6/10 Luiz K. Matsumura <luiz@planit.com.br>:
>
> I need help to know if the follow scenario is a expected behaviour, a bug=
 of
> postgres or a bug of slony:
>
> Postgres v8.4.8
> Slony-I v 2.0.5
>
> I have table replicated with slony and that do some updates in another ta=
ble
> not replicated.
>
> The trigger on replicated table was enabled on the slave database with the
> command:
>
> ALTER TABLE table1 ENABLE ALLWAYS TRIGGER trigger1;
>
> And this trigger is working fine as expected.
>
> The strange behaviour is that trigger do a update in another table not
> replicated, let=B4s say table2, and
> the triggers of this table is not fired.
> A unexpected behaviour IMHO, if I do
>
> ALTER TABLE table2 ENABLE ALWAYS TRIGGER trigger2;
>
> Then the trigger2 is fired now when trigger1 do a update in table2.
>
> My doubt is: since table2 is not replicated why they triggers dont fire e=
ven
> by a update command in
> a trigger of a replicated table ?
>
> I'm confused.  If you enable the trigger on table2, it's going to fire
> when someone updates table2.  Whether or not the update is coming from
> another trigger or directly from the user has nothing to do with it.
>
> Thanks for reply Robert.
>
> This is the point, when the trigger of table2 was create with a command l=
ike
> this
>
> CREATE TRIGGER trg_table2
> =A0 BEFORE INSERT OR UPDATE
> =A0 ON table2
> =A0 FOR EACH ROW
> =A0 EXECUTE PROCEDURE trg_table2();
>
> The trigger is enabled by default as expected. If I do a update on table2
> the trigger fire normally.
> But when a replicated table fire a trigger that do the same update, now t=
he
> trigger on table2 don=B4t fire.
> I don=B4t know if this is slony disabling all triggers=A0 unless REPLICA =
and
> ALLWAYS trrigers even over not replicated
> tables or this is managed by postgresql

OK, I see.  That's got something to do with what Slony does
internally, which unfortunately I'm not qualified to comment on, not
being a Slony guy.

--=20
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company