Thread: Date of creation and of change

Date of creation and of change

From
Andreas Tille
Date:
Hello,

could someone enlighten a fairly beginner how to define columns
of a table with the following features:
  CreateDate DEFAULT value should store current date and time  ChangeDate DEFAULT value at creation as above and a
Trigger            function which stores data end time of any change      to the data set
 

I hope someone has this quite usual feature handy or at least a
pointer where this is described.

Thank you very much
          Andreas.




Re: Date of creation and of change

From
hlefebvre
Date:

Andreas Tille wrote:
> 
> Hello,
> 
> could someone enlighten a fairly beginner how to define columns
> of a table with the following features:
> 
>    CreateDate DEFAULT value should store current date and time

create table mytable( CreateDate  timestamp default timestamp('now'),
....);  

>    ChangeDate DEFAULT value at creation as above and a Trigger
>               function which stores data end time of any change
>               to the data set


must be something like that :
CREATE FUNCTION myt_stamp () RETURNS OPAQUE AS   BEGIN       ChangeDate := timestamp(''now'');       RETURN NEW;
END;
' LANGUAGE 'plpgsql';

CREATE TRIGGER myt_stamp BEFORE INSERT OR UPDATE ON mytable   FOR EACH ROW EXECUTE PROCEDURE myt_stamp();    
> I hope someone has this quite usual feature handy or at least a
> pointer where this is described.
> 
> Thank you very much
> 
>            Andreas.


Re: Date of creation and of change

From
Andreas Tille
Date:
On Wed, 23 Aug 2000, hlefebvre wrote:

> create table mytable( CreateDate  timestamp default timestamp('now'),
> ....);  
Thanks, this works.
> CREATE FUNCTION myt_stamp () RETURNS OPAQUE AS
>     BEGIN
>         ChangeDate := timestamp(''now'');
>         RETURN NEW;
>     END;
> ' LANGUAGE 'plpgsql';
I tried:

web=# CREATE FUNCTION changed_at_timestamp () RETURNS OPAQUE AS '
web'#     BEGIN
web'#         ChangeDate := timestamp(''now'');
web'#         RETURN NEW;
web'#     END;
web'# ' LANGUAGE 'plpgsql';
CREATE
web=# select changed_at_timestamp () ;
ERROR:  typeidTypeRelid: Invalid type - oid = 0
web=# 

Is this just the wrong way to test the function?
As a beginner I try to validate each new step I do and so I wonder
if I insert the Trigger you mentioned
> CREATE TRIGGER myt_stamp BEFORE INSERT OR UPDATE ON mytable
>     FOR EACH ROW EXECUTE PROCEDURE myt_stamp();

the function could cause errors.

Sorry, I'm not very familiar with this function stuff :-(.

Kind regards
         Andreas.




Re: Date of creation and of change

From
Andreas Tille
Date:
On Wed, 23 Aug 2000, hlefebvre wrote:

> create table mytable( CreateDate  timestamp default timestamp('now'),
> ....);  
I've done a pg_dump <mydb> and there this line was transformed to:
 "createdat" timestamp DEFAULT '23.08.2000 15:35:16.00 CEST'::"timestamp",

I'm afraid if I ever should use this dump as a restore the following
dates will be wrong, thought.  So is there a save way to use in the
dumps?

May be the suggestion of Stuart <sgall@iprimus.com.au>
On Wed Aug 23 14:36:56 2000

> On insert, however, this will do the job.
> 
> Create table fred (joe integer, createdtime datetime not null default text
> 'now');
> 
> If you dont put the text in you get the date the table was created in all
> future inserts. The text force the current now to be used.
> ?Is this fixed in 7.0.x????

Would do a better job in this case?

What's wrong here?

Kind regards
         Andreas.



Re: Re: Date of creation and of change

From
hlefebvre
Date:

Andreas Tille wrote:

> I tried:
> 
> web=# CREATE FUNCTION changed_at_timestamp () RETURNS OPAQUE AS '
> web'#     BEGIN
> web'#         ChangeDate := timestamp(''now'');
> web'#         RETURN NEW;
> web'#     END;
> web'# ' LANGUAGE 'plpgsql';
> CREATE
> web=# select changed_at_timestamp () ;
> ERROR:  typeidTypeRelid: Invalid type - oid = 0
> web=#
> 
> Is this just the wrong way to test the function?

Yes. The keywords NEW / OLD are available only in triggers
see
http://www.postgresql.org/users-lounge/docs/7.0/user/c40874113.htm#AEN4286

> As a beginner I try to validate each new step I do and so I wonder
> if I insert the Trigger you mentioned
> 
> > CREATE TRIGGER myt_stamp BEFORE INSERT OR UPDATE ON mytable
> >     FOR EACH ROW EXECUTE PROCEDURE myt_stamp();
> 
> the function could cause errors.
> 
> Sorry, I'm not very familiar with this function stuff :-(.
> 
> Kind regards
> 
>           Andreas.


Re: Re: Date of creation and of change

From
Tom Lane
Date:
Andreas Tille <tillea@rki.de> writes:
> On Wed, 23 Aug 2000, hlefebvre wrote:
>> create table mytable( CreateDate  timestamp default timestamp('now'),
>> ....);  
> I've done a pg_dump <mydb> and there this line was transformed to:

>   "createdat" timestamp DEFAULT '23.08.2000 15:35:16.00 CEST'::"timestamp",

This approach does not work in 7.0 (I think it did work in some prior
releases, but not recently).  The recommended method is shown in the
FAQ:     4.22) How do I create a column that will default to the current time?     Use now():       CREATE TABLE test
(xint, modtime timestamp default now() );
 

        regards, tom lane


Re: Date of creation and of change

From
Andreas Tille
Date:
On Wed, 23 Aug 2000, hlefebvre wrote:

> Yes. The keywords NEW / OLD are available only in triggers
> see
> http://www.postgresql.org/users-lounge/docs/7.0/user/c40874113.htm#AEN4286
Well, I believe that, but


CREATE FUNCTION changed_at_timestamp() RETURNS OPAQUE AS '   BEGIN       ChangedAt := timestamp(''now'');       RETURN
NEW;  END;
 
' LANGUAGE 'plpgsql';

CREATE TABLE WebSeite (IdWebSeite int4 DEFAULT nextval('seqwebseite'::text) NOT NULL,CreatedAt timestamp DEFAULT
now(),changedattimestamp DEFAULT now(),       ...
 
);

CREATE TABLE Menu (IdMenu int4 DEFAULT nextval('seqmenu'::text) NOT NULL,CreatedAt timestamp DEFAULT now(),ChangedAt
timestampDEFAULT now(),       ...
 
);

CREATE TABLE MenuItem (IdMenu int4 DEFAULT nextval('seqmenu'::text) NOT NULL,CreatedAt timestamp DEFAULT
now(),ChangedAttimestamp DEFAULT now(),       ...
 
);

CREATE TRIGGER webseite_changed_at_timestamp BEFORE INSERT OR UPDATE ON WebSeite   FOR EACH ROW EXECUTE PROCEDURE
changed_at_timestamp();
CREATE TRIGGER menu_changed_at_timestamp BEFORE INSERT OR UPDATE ON Menu   FOR EACH ROW EXECUTE PROCEDURE
changed_at_timestamp();
CREATE TRIGGER menuitem_changed_at_timestamp BEFORE INSERT OR UPDATE ON MenuItem   FOR EACH ROW EXECUTE PROCEDURE
changed_at_timestamp();



web=# insert into menu (IdMenu, ...) values (3, ... );
ERROR:  parser: parse error at or near "changedat"


What's the problem here.  Is there a conflict between the definition with
DEFAULT now() and the TRIGGER BEFORE INSERT OR UPDATE.  Should perhaps
be the DEFAULT in the definition be removed or just the INSERT in
the TRIGGER?  Or is there a completely different problem?

Kind regards
        Andreas.



Re: Re: Date of creation and of change

From
hlefebvre
Date:

Andreas Tille wrote:
> 
> On Wed, 23 Aug 2000, hlefebvre wrote:
> 
> > Yes. The keywords NEW / OLD are available only in triggers
> > see
> > http://www.postgresql.org/users-lounge/docs/7.0/user/c40874113.htm#AEN4286
> Well, I believe that, but
> 
> CREATE FUNCTION changed_at_timestamp() RETURNS OPAQUE AS '
>     BEGIN
>         ChangedAt := timestamp(''now'');
>         RETURN NEW;
>     END;
> ' LANGUAGE 'plpgsql';
<snip>
> web=# insert into menu (IdMenu, ...) values (3, ... );
> ERROR:  parser: parse error at or near "changedat"
> 
> What's the problem here. 

No I suppose that the problem is the identifier "changedat" is unknown.

You must probably prefix it : NEW.changedat
CREATE FUNCTION changed_at_timestamp() RETURNS OPAQUE AS '    BEGIN        NEW.ChangedAt := timestamp(''now'');
RETURNNEW;    END;' LANGUAGE 'plpgsql';
 

I didn't test it, but as pgSQL looks like Oracle, it should be ok :-)

regards


Re: Date of creation and of change

From
Andreas Tille
Date:
On Fri, 25 Aug 2000, hlefebvre wrote:

> No I suppose that the problem is the identifier "changedat" is unknown.
> 
> You must probably prefix it : NEW.changedat
> 
>  CREATE FUNCTION changed_at_timestamp() RETURNS OPAQUE AS '
>      BEGIN
>          NEW.ChangedAt := timestamp(''now'');
>          RETURN NEW;
>      END;
>  ' LANGUAGE 'plpgsql';
> 
> I didn't test it, but as pgSQL looks like Oracle, it should be ok :-)
This avoids the error message, but doesn't have any effect to the value
of ChangedAt.  It just remains the same as CreatedAt :-(.

Kind regards
        Andreas.



Re: Re: Date of creation and of change

From
hlefebvre
Date:

Andreas Tille wrote:
> 
> On Fri, 25 Aug 2000, hlefebvre wrote:
> 
> > No I suppose that the problem is the identifier "changedat" is unknown.
> >
> > You must probably prefix it : NEW.changedat
> >
> >  CREATE FUNCTION changed_at_timestamp() RETURNS OPAQUE AS '
> >      BEGIN
> >          NEW.ChangedAt := timestamp(''now'');
> >          RETURN NEW;
> >      END;
> >  ' LANGUAGE 'plpgsql';
> >
> > I didn't test it, but as pgSQL looks like Oracle, it should be ok :-)
> This avoids the error message, but doesn't have any effect to the value
> of ChangedAt.  It just remains the same as CreatedAt :-(.
> 

I tried... 
I fact it seems that it doesn'nt work if you don't use the changedat
column in your UPDATE our insert statement. Just put null, and it will
be ok I think.


Re: Re: Date of creation and of change

From
Tom Lane
Date:
Andreas Tille <tillea@rki.de> writes:
>> NEW.ChangedAt := timestamp(''now'');

> This avoids the error message, but doesn't have any effect to the value
> of ChangedAt.  It just remains the same as CreatedAt :-(.

I think you are getting burnt by premature constant folding --- see
nearby discussion of how to define a column default that gives the
time of insertion.  You need to write this asNEW.ChangedAt := now();
to prevent the system from reducing timestamp('now') to a constant
when the function is first executed.
        regards, tom lane


Re: Date of creation and of change

From
Andreas Tille
Date:
On Fri, 25 Aug 2000, Tom Lane wrote:

> I think you are getting burnt by premature constant folding --- see
> nearby discussion of how to define a column default that gives the
> time of insertion.  You need to write this as
>     NEW.ChangedAt := now();
> to prevent the system from reducing timestamp('now') to a constant
> when the function is first executed.
This doesn't work, too.
It just puts allways the constant time when the function was created
into the database.  May be it has to be escaped in somw way??

I don't know how to follow hlefebvre's hint to "put null" into the
field.

Bay the way:  If we once solved the problem it might be a topic for
the FAQ, perhaps?

Kind regards
        Andreas.



Re: Re: Date of creation and of change

From
hlefebvre
Date:

Tom Lane wrote:
> 
> Andreas Tille <tillea@rki.de> writes:
> >> NEW.ChangedAt := timestamp(''now'');
> 
> > This avoids the error message, but doesn't have any effect to the value
> > of ChangedAt.  It just remains the same as CreatedAt :-(.
> 
> I think you are getting burnt by premature constant folding --- see
> nearby discussion of how to define a column default that gives the
> time of insertion.  You need to write this as
>         NEW.ChangedAt := now();
> to prevent the system from reducing timestamp('now') to a constant
> when the function is first executed.
> 
>                         regards, tom lane
yep you're right :

aegir=#
aegir=# drop table menu
aegir-# ;
DROP
aegir=# drop function changed_at_timestamp() ;
DROP
aegir=# CREATE TABLE Menu (
aegir(#          CreatedAt timestamp DEFAULT now(),
aegir(#          ChangedAt timestamp
aegir(#  );
CREATE
aegir=#
aegir=#
aegir=#  CREATE FUNCTION changed_at_timestamp() RETURNS OPAQUE AS '
aegir'#  BEGIN
aegir'#  NEW.ChangedAt := now();
aegir'#   RETURN NEW;
aegir'#   END;
aegir'# ' LANGUAGE 'plpgsql';
CREATE
aegir=#
aegir=#
aegir=#  CREATE TRIGGER menu_changed_at_timestamp BEFORE INSERT OR
UPDATE ON Men
u
aegir-#  FOR EACH ROW EXECUTE PROCEDURE changed_at_timestamp();
CREATE
aegir=#
aegir=# insert into menu(createdat) values(null);
INSERT 27700 1
aegir=# select * from menu;createdat |       changedat
-----------+------------------------          | 2000-08-25 16:29:28+02
(1 row)


aegir=# insert into menu(createdat) values(null);
INSERT 27701 1
aegir=# select * from menu;createdat |       changedat
-----------+------------------------          | 2000-08-25 16:29:28+02          | 2000-08-25 16:30:53+02
(2 rows)

aegir=# update menu set createdat = now();
UPDATE 2
aegir=# select * from menu;      createdat        |       changedat
------------------------+------------------------2000-08-25 16:31:24+02 | 2000-08-25 16:31:24+022000-08-25 16:31:24+02
|2000-08-25 16:31:24+02
 
(2 rows)


Re: Date of creation and of change

From
Andreas Tille
Date:
On Fri, 25 Aug 2000, hlefebvre wrote:

> Tom Lane wrote:

> >         NEW.ChangedAt := now();
> > to prevent the system from reducing timestamp('now') to a constant
> > when the function is first executed.
> > 
> >                         regards, tom lane
> yep you're right :
You both are completely right.  Forget about my previous mail.  I made
a boring mistake and left the old state untouched.  Now it works.

By the way: Hwo can I prevent Access from warning me about the fact,
that "another user" (well it's the postgres server) has changed the
data set while I was edditing it?  (In general it's no problem, but
if I try two changes immediately the second change will be started
with this boring warning.)  But this is perhaps off topic in this
list ....

Kind regards and many thanks to you all
       Andreas.



Re: Re: Date of creation and of change

From
hlefebvre
Date:

Andreas Tille wrote:
> 
> On Fri, 25 Aug 2000, Tom Lane wrote:
> 
> > I think you are getting burnt by premature constant folding --- see
> > nearby discussion of how to define a column default that gives the
> > time of insertion.  You need to write this as
> >       NEW.ChangedAt := now();
> > to prevent the system from reducing timestamp('now') to a constant
> > when the function is first executed.
> This doesn't work, too.
> It just puts allways the constant time when the function was created
> into the database.  May be it has to be escaped in somw way??
> 
> I don't know how to follow hlefebvre's hint to "put null" into the
> field.

As I said, I was wrong, and Tom is right.

I was suspecting a problem if the field is not used in the query, but
the pb was about the now() function.


> Bay the way:  If we once solved the problem it might be a topic for
> the FAQ, perhaps?
IMHO this is a documentation problem. 
There is no example about such trigger who will modify data, and 'now'
is described as "transaction time".
also, in date/time function now() is not mentionned 
(doc about pgSQL 7.0 on the web site at
http://www.postgresql.org/users-lounge/docs/7.0/user/functions2872.htm)