Re: [SQL] Triggers, plpgsql, etc. - Mailing list pgsql-sql

From jwieck@debis.com (Jan Wieck)
Subject Re: [SQL] Triggers, plpgsql, etc.
Date
Msg-id m101DAO-000EBQC@orion.SAPserv.Hamburg.dsh.de
Whole thread Raw
In response to Triggers, plpgsql, etc.  (Christophe Labouisse <labouiss@club-internet.fr>)
List pgsql-sql
Christophe Labouisse wrote:

>
> I want to have a =AB date of the last update =BB field in a table. So I
> create a table with datetime field (liens_maj) and a default value to
> 'now'.
>
> As shown below it works fine.
>
> lumiere=3D> insert into liens (liens_nom,liens_url) values ('Ga','GAbuzo'=
> );
> INSERT 1009600 1
> lumiere=3D> select * from liens;
> liens_id|liens_nom|liens_url|liens_commentaire|liens_maj
> --------+---------+---------+-----------------+--------------------------=
> --
>        1|Ga       |GAbuzo   |                 |Thu Jan 14 13:29:35 1999 C=
> ET
> (1 row)
>
>
> To update automatically this field when the row is updated I thought
> of a trigger calling a plpgsql function :

    Good  idea!  Maybe you want to force the initial value to the
    actual time too, so it will allways be the time of the insert
    and  not  only the fallback 'default' and the user isn't able
    to insert anything else.

    Also the job of a trigger.

>
> create trigger liens_maj_trig after update
>     on liens for each row execute procedure liens_maj_fun();
>
>
> create function liens_maj_fun () returns opaque as '
> begin
>    update liens set liens_maj=3D''now'' where liens_id=3Dold.liens_id;
>    return new;
> end;
> ' language 'plpgsql';
>
> When I try to update a record I get the following error :
>
> lumiere=3D> update liens set liens_nom=3D'zzz' where liens_id=3D1;
> ERROR:  There is no operator '=3D$' for types 'int4' and 'int4'
>         You will either have to retype this query using an explicit cast,
>         or you will have to define the operator using CREATE OPERATOR

    Lucky you :-)

    I expected a final crash of the backend in this case (and got
    it  on  test),  because  the  trigger  procedure  itself does
    exactly the operation that triggers it. This  is  an  endless
    recursion!

    The following is the right solution:

        CREATE FUNCTION liens_maj_fun() RETURNS opaque AS '
        BEGIN
            new.liens_maj := ''now'';
            RETURN new;
        END;
        ' LANGUAGE 'plpgsql';

        CREATE TRIGGER liens_maj_trig BEFORE [INSERT OR] UPDATE TO liens
            FOR EACH ROW EXECUTE PROCEDURE liens_maj_fun();

    Why?  A  trigger  procedure  that is fired BEFORE can replace
    values in NEW just before it is put into the database.


Jan

--

#======================================================================#
# It's easier to get forgiveness for being wrong than for being right. #
# Let's break this rule - forgive me.                                  #
#======================================== jwieck@debis.com (Jan Wieck) #

pgsql-sql by date:

Previous
From: Christophe Labouisse
Date:
Subject: Triggers, plpgsql, etc.
Next
From: "Gene Selkov Jr."
Date:
Subject: Re: [SQL] Text type