From: | Merlin Moncure <mmoncure(at)gmail(dot)com> |
---|---|
To: | Josh Trutwin <josh(at)trutwins(dot)homeip(dot)net> |
Cc: | pgsql-general(at)postgresql(dot)org |
Subject: | Re: Empty Updates, ON UPDATE triggers and Rules |
Date: | 2009-08-06 17:15:57 |
Message-ID: | b42b73150908061015n6c8f5bbboae96d8166cc2026c@mail.gmail.com |
Views: | Raw Message | Whole Thread | Download mbox | Resend email |
Thread: | |
Lists: | pgsql-general |
On Thu, Aug 6, 2009 at 12:53 PM, Josh Trutwin<josh(at)trutwins(dot)homeip(dot)net> wrote:
> 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.
Triggers are supposed to fire regardless if new == old. In fact it's
common practice to do something like:
update foo set x = x; to get trigger to fire.
> CREATE RULE no_unchanging_updates AS
> ON UPDATE TO test_upd
> WHERE ROW(OLD.*) IS NOT DISTINCT FROM ROW(NEW.*)
> DO INSTEAD NOTHING;
in 8.3 you can also do:
WHERE old::text = new.text
in 8.4 you can (and should) do:
WHERE old = new
> 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
'*' is expanded during the creation of the rule. There's nothing you
can do about this for rules, however for functions '*' is preserved
because the function is recompiled from source when necessary. So,
from this we conclude:
*) '*' is dangerous except in functions
*) use functions instead of rules where possible
how about:
CREATE OR REPLACE FUNCTION set_last_modified ()
RETURNS TRIGGER
AS $$
BEGIN
IF NEW != OLD THEN -- 8.4 syntax
NEW.last_modified = NOW();
END IF;
RETURN NEW;
END;
$$ LANGUAGE PLPGSQL;
merlin
From | Date | Subject | |
---|---|---|---|
Next Message | Jeff Davis | 2009-08-06 17:17:23 | Re: Empty Updates, ON UPDATE triggers and Rules |
Previous Message | Sam Mason | 2009-08-06 17:06:42 | Re: Clients disconnect but query still runs |