Thread: BUG #3929: RULE causes unintended update of SEQUENCE

BUG #3929: RULE causes unintended update of SEQUENCE

From
"Arjan Tuinhout"
Date:
The following bug has been logged online:

Bug reference:      3929
Logged by:          Arjan Tuinhout
Email address:      at@tuko.nl
PostgreSQL version: 8.1
Operating system:   Kubuntu 6.06 Dapper
Description:        RULE causes unintended update of SEQUENCE
Details:

-- The SQL code explains the problem:
-- I have 2 tables one storing basic data about documents 'doc' and one
storing the revisions 'rev'
-- I add one RULE to make sure that the latest available revision identifier
is available in the 'doc' table
-- The rev_id is generated by a SEQUENCE
-- However the intended code does not work: appearantly the SEQUENCE is
update by calling the RULE; proofed by the workaround.

-- Please help. Thanx. Arjan.


CREATE SEQUENCE id;

CREATE TABLE doc (doc_id INT4 DEFAULT nextval('id') PRIMARY KEY, name TEXT,
curr_rev_id INT4);

CREATE TABLE rev (doc_id INT4 REFERENCES doc, rev_id INT4 DEFAULT
nextval('id') PRIMARY KEY, revision TEXT);

CREATE RULE upd_doc AS ON INSERT TO rev DO ALSO UPDATE doc SET curr_rev_id =
NEW.rev_id WHERE doc_id = NEW.doc_id;

INSERT INTO doc VALUES(1, 'Book on PostgreSQL', NULL);
INSERT INTO rev (doc_id, revision) VALUES (1, 'Revision 1');
INSERT INTO rev (doc_id, revision) VALUES (1, 'Revision 2');

-- The next select statement should yield the current doc version, but
returns nothing...
SELECT * FROM doc NATURAL JOIN rev WHERE curr_rev_id = rev_id;

-- From the next select statement indicates the problem: the RULE does
increment the SEQUENCE id!!!
SELECT * FROM doc NATURAL JOIN rev;

-- A work around, proofing the problem lies in the RULE statement, could
be:
CREATE OR REPLACE RULE upd_doc AS ON INSERT TO rev DO ALSO UPDATE doc SET
curr_rev_id = currval('id')WHERE doc_id = NEW.doc_id;
-- This works but is dangerous... because you need to rely on using the
sequence to create unique identifiers for revisions...)

Re: BUG #3929: RULE causes unintended update of SEQUENCE

From
Tom Lane
Date:
"Arjan Tuinhout" <at@tuko.nl> writes:
> -- However the intended code does not work: appearantly the SEQUENCE is
> update by calling the RULE; proofed by the workaround.

This is the expected behavior with a rule --- it's a macro, so multiple
references to the same input value risk multiple evaluations.

> -- Please help. Thanx. Arjan.

Use a trigger instead when your intent is to copy data from the
inserted/updated row to someplace else.

            regards, tom lane