Thread: Rules aren't doing what I expect
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
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.
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.
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
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