Empty Updates, ON UPDATE triggers and Rules

From: Josh Trutwin <josh(at)trutwins(dot)homeip(dot)net>
To: pgsql-general(at)postgresql(dot)org
Subject: Empty Updates, ON UPDATE triggers and Rules
Date: 2009-08-06 16:53:16
Message-ID: 20090806115316.0fcb580a@sinkhole
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-general

Hello,

I have a simple table that has a trigger to set a last_modified column
using the following:

CREATE OR REPLACE FUNCTION set_last_modified ()
RETURNS TRIGGER
AS $$
BEGIN
NEW.last_modified = NOW();
RETURN NEW;
END;
$$ LANGUAGE PLPGSQL;

CREATE TRIGGER trigger_test_upd_set_last_mod
BEFORE UPDATE ON test_upd
FOR EACH ROW EXECUTE PROCEDURE set_last_modified();

The table data:

> select * from test_upd;
id | foo | bar | last_modified
----+-----+-----+----------------------------
1 | foo | 1 | 2009-08-06 11:37:09.15584
2 | foo | 2 | 2009-08-06 11:37:12.740515
3 | baz | 3 | 2009-08-06 11:37:19.730894

If I run the following query:

UPDATE test_up SET foo = 'foo', bar = 1 WHERE id = 1;

The set_last_modified() trigger is run even though the data didn't
actually change. Perhaps due to an application program which doesn't
know the contents before running the UPDATE.

New Data (notice last_modified changed for row 1):

> select * from test_upd;
id | foo | bar | last_modified
----+-----+-----+----------------------------
2 | foo | 2 | 2009-08-06 11:37:12.740515
3 | baz | 3 | 2009-08-06 11:37:19.730894
1 | foo | 1 | 2009-08-06 11:37:43.045065

Doing some research on this I found this post:
http://www.depesz.com/index.php/2007/09/08/avoiding-empty-updates/

Which has a Rule:

CREATE RULE no_unchanging_updates AS
ON UPDATE TO test_upd
WHERE ROW(OLD.*) IS NOT DISTINCT FROM ROW(NEW.*)
DO INSTEAD NOTHING;

This worked great - re-ran the update query and no change to
last_modified column for row id 1. BUT, one major issue with this -
if I inspect the table with \d it appears the rule above was expanded
to this:

Rules:
no_unchanging_updates AS
ON UPDATE TO test_upd
WHERE NOT (old.id IS DISTINCT FROM new.id OR old.foo IS DISTINCT
FROM new.foo OR old.bar IS DISTINCT FROM new.bar OR
old.last_modified IS DISTINCT FROM new.last_modified) DO INSTEAD
NOTHING

Now if I add a column using:

ALTER TABLE test_upd ADD COLUMN baz TEXT;

The rule above is not updated to include the new column and running
an empty update query involving baz causes the trigger to change
last_modified.

Do I have to DROP/recreate the Rule everytime I ALTER the table or is
there a better way?

I have an application where it's possible for end users to easily
add / remove columns from their "plugin" application so I was hoping
to not have to add rule rebuilding to these operations if possible.
I noticed if I attempt to DROP column bar that I have to add CASCADE
so the rule is deleted so I'll likely have to deal with it anyway.

Postgresql 8.3.7

Thank you,

Josh

Responses

Browse pgsql-general by date

  From Date Subject
Next Message decibel 2009-08-06 16:59:57 What happens when syslog gets blocked?
Previous Message Raymond O'Donnell 2009-08-06 14:23:46 Re: Postgresql Backups