Thread: Rules aren't doing what I expect

Rules aren't doing what I expect

From
Mark Volpe
Date:
Hi again,

I have a table with a trigger that can potentially modify a row before it gets
inserted or updated:
CREATE TABLE t1 (a int);CREATE FUNCTION t1_validate() RETURNS opaque AS'    BEGIN    IF (NEW.a>10) THEN NEW.a=10; END
IF;   IF (NEW.a<0) THEN NEW.a=0; END IF;    RETURN NEW;    END;' LANGUAGE 'plpgsql';CREATE TRIGGER t1_trig BEFORE
INSERTOR UPDATE    ON t1 FOR EACH ROW EXECUTE PROCEDURE t1_validate();
 

I have another table that tracks changes in the first table with rules:
CREATE TABLE t1_log (old_a int, new_a int);CREATE RULE t1_insert AS ON INSERT TO t1    DO INSERT INTO t1_log
VALUES(NULL,NEW.a);CREATE RULE t1_update AS ON UPDATE TO t1    DO INSERT INTO t1_log VALUES(OLD.a, NEW.a);CREATE RULE
t1_deleteAS ON DELETE TO t1    DO INSERT INTO t1_log VALUES(OLD.a, NULL);
 

When I try this out, however, the rule seems to use the original value, rather
than the "corrected" value.
INSERT INTO t1 VALUES(2);INSERT INTO t1 VALUES(8);INSERT INTO t1 VALUES(15);SELECT * FROM t1;
 a  ----  2  8 10

The table t1 shows the corrected value of 10, but,
SELECT * FROM FROM t1_log; old_a | new_a -------+-------       |     2       |     8       |    15
The t1_log table doesn't show what was actually inserted into t1!
Are there any changes I can make to the logic above so that t1_log can
show the correct value?

Thanks,
Mark


Re: Rules aren't doing what I expect

From
Ang Chin Han
Date:
On Wed, Aug 09, 2000 at 12:04:13PM -0400, Mark Volpe wrote:

> I have a table with a trigger that can potentially modify a row before it gets
> inserted or updated:

[snip]

> I have another table that tracks changes in the first table with rules:

AFAIK, rules get rewritten first, before triggers are invoked,
so your rules are getting the values before your trigger changes them.

> The t1_log table doesn't show what was actually inserted into t1!
> Are there any changes I can make to the logic above so that t1_log can
> show the correct value?

Either somehow rewrite your trigger as a rule, or stick another
trigger to change the value before getting into your log table.
You might be able to reuse your trigger function, I think, just
point the trigger to that function. A bit inefficient, since it
gets called twice.


Re: Rules aren't doing what I expect

From
Mark Volpe
Date:
The actual trigger function I'm working with is over two screens long and
rather expensive to be calling twice! Perhaps I need to add another trigger
that updates the log table with the correct values after the fact. Recursive
triggers, fun! Thanks for the help,

Mark

Ang Chin Han wrote:
> 
> Either somehow rewrite your trigger as a rule, or stick another
> trigger to change the value before getting into your log table.
> You might be able to reuse your trigger function, I think, just
> point the trigger to that function. A bit inefficient, since it
> gets called twice.


Re: Rules aren't doing what I expect

From
Tom Lane
Date:
Mark Volpe <volpe.mark@epamail.epa.gov> writes:
> When I try this out, however, the rule seems to use the original
> value, rather than the "corrected" value.

Queries added by non-INSTEAD rules are always performed before the
initially-given query, so you're right, the rule will see the unmodified
value.

I'd suggest folding the log-entry-making into your trigger, actually.
If you have a trigger anyway then the insert into t1_log is only one
more line in that trigger procedure...
        regards, tom lane


Re: Rules aren't doing what I expect

From
Mark Volpe
Date:
Tom Lane wrote:
> 
> Queries added by non-INSTEAD rules are always performed before the
> initially-given query, so you're right, the rule will see the unmodified
> value.
> 
> I'd suggest folding the log-entry-making into your trigger, actually.
> If you have a trigger anyway then the insert into t1_log is only one
> more line in that trigger procedure...
> 
>                         regards, tom lane

Thanks for the explanation, Tom.  I left out part of my story though. :)  I
would like normal users to be able to modify t1 but not t1_log, and doing what
you said would require INSERT permission on t1_log. So what I did was go ahead
and allow INSERT permission, but create before and after triggers on t1_log
that check the inserted values against reality... but that brings up another
question -

If I do an UPDATE on t1, it calls a trigger which eventually does:
INSERT INTO t1_log VALUES(OLD.a, NEW.a);

If t1_log has before and after triggers, the before trigger will always see
the old row in t1, and the after trigger will always see the new data, right?
At least that's what I'm seeing.  The "visibility of data changes" document
was kinda confusing...

Mark