Search Postgresql Archives

Re: Empty Updates, ON UPDATE triggers and Rules

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, Aug 6, 2009 at 12:53 PM, Josh Trutwin<josh@xxxxxxxxxxxxxxxxxxx> 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

-- 
Sent via pgsql-general mailing list (pgsql-general@xxxxxxxxxxxxxx)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-general


[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Postgresql Jobs]     [Postgresql Admin]     [Postgresql Performance]     [Linux Clusters]     [PHP Home]     [PHP on Windows]     [Kernel Newbies]     [PHP Classes]     [PHP Books]     [PHP Databases]     [Postgresql & PHP]     [Yosemite]
  Powered by Linux