Thread: time stops within transaction

time stops within transaction

From
Alex Pilosov
Date:
I just ran into a strangest thing: within transaction, select now() will
always return time when transaction started. Same happens with select
'now'::timestamp.

This is with 7.0. I have not tested it with CVS.

I am not sure what causes this. I assume that result of now() is cached by
fmgr. Is there a way to declare functions 'not-cacheable-ever'? If there
is, such should be applied to now().

-alex



Re: time stops within transaction

From
Bruce Momjian
Date:
Wow, that is strange.


> I just ran into a strangest thing: within transaction, select now() will
> always return time when transaction started. Same happens with select
> 'now'::timestamp.
> 
> This is with 7.0. I have not tested it with CVS.
> 
> I am not sure what causes this. I assume that result of now() is cached by
> fmgr. Is there a way to declare functions 'not-cacheable-ever'? If there
> is, such should be applied to now().
> 
> -alex
> 
> 


--  Bruce Momjian                        |  http://candle.pha.pa.us pgman@candle.pha.pa.us               |  (610)
853-3000+  If your life is a hard drive,     |  830 Blythe Avenue +  Christ can be your backup.        |  Drexel Hill,
Pennsylvania19026
 


Re: time stops within transaction

From
Tom Lane
Date:
Alex Pilosov <alex@pilosoft.com> writes:
> I just ran into a strangest thing: within transaction, select now() will
> always return time when transaction started.

That is what now() is defined to return: transaction start time.
Perhaps the documentation needs improvement...
        regards, tom lane


Re: time stops within transaction

From
"John Huttley"
Date:
----- Original Message -----
From: Bruce Momjian <pgman@candle.pha.pa.us>
To: Alex Pilosov <alex@pilosoft.com>
Cc: <pgsql-hackers@postgresql.org>
Sent: Wednesday, 18 October 2000 16:21
Subject: Re: [HACKERS] time stops within transaction


> Wow, that is strange.
>
>
> > I just ran into a strangest thing: within transaction, select now() will
> > always return time when transaction started. Same happens with select
> > 'now'::timestamp.
> >


Actually, thats useful since you can put now()  into multiple fields in one
transaction.

The alternative is that CURRENT_TIMESTAMP  (??? is that the one) which isn't a
function
and stuffs up when trying to use it as a field default or as part of an
expression in a view.

(Comment true for 6.5.3 at least)
Documentation on time constants and how to misuse them is weak...

Regards



Re: time stops within transaction

From
Tom Lane
Date:
"John Huttley" <John@mwk.co.nz> writes:
>  Documentation on time constants and how to misuse them is weak...

You can say that again!  Who's up for submitting documentation patches?
        regards, tom lane


Re: time stops within transaction

From
Karel Zak
Date:
On Tue, 17 Oct 2000, Alex Pilosov wrote:

> I just ran into a strangest thing: within transaction, select now() will
> always return time when transaction started. Same happens with select
> 'now'::timestamp.
It's feature, not bug. IMHO good feature, an example I use it for rows 
identification during table filling :-)
                Karel



Re: time stops within transaction

From
Peter Eisentraut
Date:
Tom Lane writes:

> That is what now() is defined to return: transaction start time.
> Perhaps the documentation needs improvement...

Then CURRENT_TIMESTAMP is in violation of SQL.

-- 
Peter Eisentraut      peter_e@gmx.net       http://yi.org/peter-e/



Re: time stops within transaction

From
Tom Lane
Date:
Peter Eisentraut <peter_e@gmx.net> writes:
> Tom Lane writes:
>> That is what now() is defined to return: transaction start time.

> Then CURRENT_TIMESTAMP is in violation of SQL.

Au contraire, if it did not behave that way it would violate the spec.
See SQL92 6.8 general rule 3:
        3) If an SQL-statement generally contains more than one reference           to one or more <datetime value
function>s,then all such ref-           erences are effectively evaluated simultaneously. The time of
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^          evaluation of the <datetime value function> during the execution
    of the SQL-statement is implementation-dependent.
 
        regards, tom lane


Re: time stops within transaction

From
Peter Eisentraut
Date:
Tom Lane writes:

> Peter Eisentraut <peter_e@gmx.net> writes:
> > Tom Lane writes:
> >> That is what now() is defined to return: transaction start time.
> 
> > Then CURRENT_TIMESTAMP is in violation of SQL.
> 
> Au contraire, if it did not behave that way it would violate the spec.
> See SQL92 6.8 general rule 3:
> 
>          3) If an SQL-statement generally contains more than one reference
>             to one or more <datetime value function>s, then all such ref-
>             erences are effectively evaluated simultaneously. The time of
>                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>             evaluation of the <datetime value function> during the execution
>             of the SQL-statement is implementation-dependent.

statement != transaction

-- 
Peter Eisentraut      peter_e@gmx.net       http://yi.org/peter-e/



Re: time stops within transaction

From
Tom Lane
Date:
Peter Eisentraut <peter_e@gmx.net> writes:
> Tom Lane writes:
>> Au contraire, if it did not behave that way it would violate the spec.
>> See SQL92 6.8 general rule 3:
>> 
>> 3) If an SQL-statement generally contains more than one reference
>> to one or more <datetime value function>s, then all such ref-
>> erences are effectively evaluated simultaneously. The time of
>> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>> evaluation of the <datetime value function> during the execution
>> of the SQL-statement is implementation-dependent.

> statement != transaction

So?  It also says that the choice of exactly when to evaluate now()
is implementation-dependent.  Doing so at start of transaction is
an allowed behavior AFAICS.  Actually calling time(2) at each use
of now(), which is what the original poster seemed to want, is
clearly *not* an allowed behavior.

I think what you are advocating is recomputing now() at each statement
boundary within a transaction, but that's not as simple as it looks
either.  Consider statement boundaries in an SQL function --- the
function is probably being called from some outer statement, so
advancing now() within the function would violate the spec constraint
with respect to the outer statement.
        regards, tom lane


Re: time stops within transaction

From
Peter Eisentraut
Date:
Tom Lane writes:

> So?  It also says that the choice of exactly when to evaluate now()
> is implementation-dependent.  Doing so at start of transaction is
> an allowed behavior AFAICS.

But it's only talking about statements.  You can't reuse things that you
calculated for previous statements unless it says so.  (Of course
implementation-dependent means that you can do anything you want to, but
let's not go there. :-)

> Actually calling time(2) at each use
> of now(), which is what the original poster seemed to want, is
> clearly *not* an allowed behavior.

What this covers is doing things like

SELECT CURRENT_TIMESTAMP as "Today", CURRENT_TIMESTAMP + 1 DAY AS "Tomorrow";

But keep in mind that other/correct SQL implementations don't have
autocommit, so if you're in some interactive SQL shell and you keep
entering

select current_timestamp;

then it won't ever advance unless you do commits in between.  This doesn't
make much sense to me, as CURRENT_TIMESTAMP is defined to return the
"current time" .  The point of a transaction is all data or no data, not
all the same data.

> I think what you are advocating is recomputing now() at each statement
> boundary within a transaction, but that's not as simple as it looks
> either.  Consider statement boundaries in an SQL function --- the
> function is probably being called from some outer statement, so
> advancing now() within the function would violate the spec constraint
> with respect to the outer statement.

Good point.  There are probably special rules for SQL functions.

I'm not saying that this thing is a priority to me, but it's something to
consider.

-- 
Peter Eisentraut      peter_e@gmx.net       http://yi.org/peter-e/



Re: time stops within transaction

From
Don Baccus
Date:
At 12:39 PM 10/18/00 -0400, Tom Lane wrote:
>Peter Eisentraut <peter_e@gmx.net> writes:
>> Tom Lane writes:
>>> Au contraire, if it did not behave that way it would violate the spec.
>>> See SQL92 6.8 general rule 3:
>>> 
>>> 3) If an SQL-statement generally contains more than one reference
>>> to one or more <datetime value function>s, then all such ref-
>>> erences are effectively evaluated simultaneously. The time of
>>> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>>> evaluation of the <datetime value function> during the execution
>>> of the SQL-statement is implementation-dependent.
>
>> statement != transaction
>
>So?  It also says that the choice of exactly when to evaluate now()
>is implementation-dependent. 

Note the phrase "during the execution of the SQL-STATEMENT" above.  It
says that exactly when it will be evaluated within the statement is
implementation-defined, BUT THAT IT IS EVALUATED WITHIN THE STATEMENT,
not beforehand.

At least, that's how I read it :)



- Don Baccus, Portland OR <dhogaza@pacifier.com> Nature photos, on-line guides, Pacific Northwest Rare Bird Alert
Serviceand other goodies at http://donb.photo.net.
 


Re: time stops within transaction

From
Alex Pilosov
Date:
On Wed, 18 Oct 2000, Tom Lane wrote:

> I think what you are advocating is recomputing now() at each statement
> boundary within a transaction, but that's not as simple as it looks
> either.  Consider statement boundaries in an SQL function --- the
> function is probably being called from some outer statement, so
> advancing now() within the function would violate the spec constraint
> with respect to the outer statement.
Postgres doesn't have an idea of what a 'top-level' statement is? I.E.
statement as submitted by a client (libpq)?

-alex



Re: time stops within transaction

From
Tom Lane
Date:
Alex Pilosov <alex@pilosoft.com> writes:
>> Consider statement boundaries in an SQL function --- the
>> function is probably being called from some outer statement, so
>> advancing now() within the function would violate the spec constraint
>> with respect to the outer statement.
> Postgres doesn't have an idea of what a 'top-level' statement is? I.E.
> statement as submitted by a client (libpq)?

There's never been any reason to make such a distinction.
Nor am I entirely convinced that that's the right definition...
        regards, tom lane


Re: time stops within transaction

From
Hiroshi Inoue
Date:

Tom Lane wrote:

> Alex Pilosov <alex@pilosoft.com> writes:
> >> Consider statement boundaries in an SQL function --- the
> >> function is probably being called from some outer statement, so
> >> advancing now() within the function would violate the spec constraint
> >> with respect to the outer statement.
> > Postgres doesn't have an idea of what a 'top-level' statement is? I.E.
> > statement as submitted by a client (libpq)?
>
> There's never been any reason to make such a distinction.

There's already a distinction.
Snapshot is made per top-level statement and functions/subqueries
use the same snapshot as that of top-level statement.

Regards.

Hiroshi Inoue




Re: time stops within transaction

From
Tom Lane
Date:
Hiroshi Inoue <Inoue@tpf.co.jp> writes:
>>>> Postgres doesn't have an idea of what a 'top-level' statement is? I.E.
>>>> statement as submitted by a client (libpq)?
>> 
>> There's never been any reason to make such a distinction.

> There's already a distinction.
> Snapshot is made per top-level statement and functions/subqueries
> use the same snapshot as that of top-level statement.

Not so.  SetQuerySnapshot is executed per querytree, not per top-level
statement --- for example, if a rule generates multiple queries from
a user statement, SetQuerySnapshot is called again for each query.

With the current structure of pg_exec_query_string(), an operation
executed in the outer loop, rather than the inner, would more or less
correspond to one "top level" query --- if you want to assume that
pg_exec_query_string() is only called from PostgresMain.  That's
true today but hasn't always been true --- I believe it used to be
used to parse SPI commands, and someday it may be again.
        regards, tom lane


Re: time stops within transaction

From
Hiroshi Inoue
Date:

Tom Lane wrote:

> Hiroshi Inoue <Inoue@tpf.co.jp> writes:
> >>>> Postgres doesn't have an idea of what a 'top-level' statement is? I.E.
> >>>> statement as submitted by a client (libpq)?
> >>
> >> There's never been any reason to make such a distinction.
>
> > There's already a distinction.
> > Snapshot is made per top-level statement and functions/subqueries
> > use the same snapshot as that of top-level statement.
>
> Not so.  SetQuerySnapshot is executed per querytree, not per top-level
> statement --- for example, if a rule generates multiple queries from
> a user statement, SetQuerySnapshot is called again for each query.
>
> With the current structure of pg_exec_query_string(), an operation
> executed in the outer loop, rather than the inner, would more or less
> correspond to one "top level" query --- if you want to assume that
> pg_exec_query_string() is only called from PostgresMain.  That's
> true today but hasn't always been true --- I believe it used to be
> used to parse SPI commands, and someday it may be again.
>

If there's no concept of top-level statement,there's no
concept of read consistency and MVCC isn't needed.

Regards.

Hiroshi Inoue.




Re: time stops within transaction

From
Hiroshi Inoue
Date:

Tom Lane wrote:

> Hiroshi Inoue <Inoue@tpf.co.jp> writes:
> >>>> Postgres doesn't have an idea of what a 'top-level' statement is? I.E.
> >>>> statement as submitted by a client (libpq)?
> >>
> >> There's never been any reason to make such a distinction.
>
> > There's already a distinction.
> > Snapshot is made per top-level statement and functions/subqueries
> > use the same snapshot as that of top-level statement.
>
> Not so.  SetQuerySnapshot is executed per querytree, not per top-level
> statement --- for example, if a rule generates multiple queries from
> a user statement, SetQuerySnapshot is called again for each query.
>

Is it possible that a rule generates multiple queries from
a read(select)-only statement ? If so,the queries must
be executed under the same snapshot in order to guaran
tee read consistency from user's POV.
As for non-select queries I'm not sure because read
consistency doesn't have much meaning for them.

I just remembered a report from Forest Wilkinson
about a month ago [SQL] SQL functions not locking
properly?

Don't we have to distiguish simple procedure calls
(select func();) and function calls as a part of a query ?
As I mentioned once before,it seems a problem that
arbitrary functions could be called from queries.

As for procedures,it seems preferable that each
statement of them is treated as a top-level query.

Regards.
Hiroshi Inoue



Re: time stops within transaction

From
"Mikheev, Vadim"
Date:
> > > Snapshot is made per top-level statement and functions/subqueries
> > > use the same snapshot as that of top-level statement.
> >
> > Not so.  SetQuerySnapshot is executed per querytree, not per top-level
> > statement --- for example, if a rule generates multiple queries from
> > a user statement, SetQuerySnapshot is called again for each query.

This is true. I just made it to work as it was in pre-6.5 times - each
query of *top level* query list uses own snapshot (in read committed mode
only) as if they were submitted by user one by one.

But functions/subqueries called while executing query uses same snapshot
as query itself.

> > With the current structure of pg_exec_query_string(), an operation
> > executed in the outer loop, rather than the inner, would more or less
> > correspond to one "top level" query --- if you want to assume that
> > pg_exec_query_string() is only called from PostgresMain.  That's
> > true today but hasn't always been true --- I believe it used to be
> > used to parse SPI commands, and someday it may be again.

It was never used in SPI. Just look at _SPI_execute. Same parent query
snapshot is used in SPI functions. *But* SPI' queries *see* changes
made by parent query - I never was sure about this and think I've asked
other opinions. No opinions - no changes -:)

> If there's no concept of top-level statement,there's no
> concept of read consistency and MVCC isn't needed.

Except of the fact that SPI' queries see changes made by parent same
snapshot is used all time while executing top-level query (single query,
not query list).

Vadim



Re: time stops within transaction

From
Tom Lane
Date:
Hiroshi Inoue <Inoue@tpf.co.jp> writes:
> Is it possible that a rule generates multiple queries from
> a read(select)-only statement ? If so,the queries must
> be executed under the same snapshot in order to guaran
> tee read consistency from user's POV.
> As for non-select queries I'm not sure because read
> consistency doesn't have much meaning for them.

In SERIALIZABLE mode everything is done with the first snapshot obtained
*in the transaction*, which seems correct to me.  In READ COMMITTED mode
a new snapshot is taken at every SetQuerySnapshot, which means later
commands in an xact can see data committed later than transaction start.
The issue here seems to be just how often we want to do
SetQuerySnapshot.

One thing that bothers me about the current setup is that
pg_exec_query_string delays calling SetQuerySnapshot until the last
possible moment before executing a query.  In particular, parsing and
planning of the first query in a transaction will be done with no
snapshot at all!  Is this good, and if so why?

I am inclined to think that we should do SetQuerySnapshot in the outer
loop of pg_exec_query_string, just before calling
pg_analyze_and_rewrite.  This would ensure that parse/plan accesses to
the database have a snapshot, and would eliminate the question I raised
yesterday about whether ProcessUtility is missing SetQuerySnapshot
calls.

If we did that, then SetQuerySnapshot would be called once per user-
written command (defining a command as whatever the grammar produces
a single parsetree for, which is probably OK) so long as SPI functions
don't try to use pg_exec_query_string...

Then this'd also be an appropriate place to advance now(), if people
feel that's more appropriate behavior for now() than the existing one.

> I just remembered a report from Forest Wilkinson
> about a month ago [SQL] SQL functions not locking
> properly?

Yes, that was on my to-look-at list too.  Not sure if it's related.

> Don't we have to distiguish simple procedure calls
> (select func();) and function calls as a part of a query ?

"select func()" looks like a query to me.  I don't see how you are going
to make such a distinction in a useful way.  If we had a CALL statement
distinct from function invocation in expressions, then maybe it'd make
sense for that context to act differently.
        regards, tom lane


Re: time stops within transaction

From
"Vadim Mikheev"
Date:
> > > Snapshot is made per top-level statement and functions/subqueries
> > > use the same snapshot as that of top-level statement.
> >
> > Not so.  SetQuerySnapshot is executed per querytree, not per top-level
> > statement --- for example, if a rule generates multiple queries from
> > a user statement, SetQuerySnapshot is called again for each query.

This is true. I just make it to work as it was in pre-6.5 times - each
query of *top level* query list uses own snapshot (in read committed mode
only) as if they were submitted by user one by one.

But functions/subqueries called while executing query uses same snapshot
as query itself.

> > With the current structure of pg_exec_query_string(), an operation
> > executed in the outer loop, rather than the inner, would more or less
> > correspond to one "top level" query --- if you want to assume that
> > pg_exec_query_string() is only called from PostgresMain.  That's
> > true today but hasn't always been true --- I believe it used to be
> > used to parse SPI commands, and someday it may be again.

It was never used in SPI. Just look at _SPI_execute. Same parent query
snapshot is used in SPI functions. *But* SPI' queries *see* changes
made by parent query - I never was sure about this and think I've asked
other opinions. No opinions - no changes -:)

> If there's no concept of top-level statement,there's no
> concept of read consistency and MVCC isn't needed.

Except of the fact that SPI' queries see changes made by parent same
snapshot
is used all time while executing top-level query (single query, not query
list).

Vadim




Re: time stops within transaction

From
"Vadim Mikheev"
Date:
> I am inclined to think that we should do SetQuerySnapshot in the outer
> loop of pg_exec_query_string, just before calling
> pg_analyze_and_rewrite.  This would ensure that parse/plan accesses to
^^^^^^^^^^^^^^
Actually not - snapshot is passed as parameter to heap_beginscan...
And currently SnapshotNow is used everywhere.

> If we did that, then SetQuerySnapshot would be called once per user-
> written command (defining a command as whatever the grammar produces
> a single parsetree for, which is probably OK) so long as SPI functions
> don't try to use pg_exec_query_string...

SPI doesn't try this from its birthday in ~6.2

Vadim




RE: time stops within transaction

From
"Hiroshi Inoue"
Date:
> -----Original Message-----
> From: Tom Lane [mailto:tgl@sss.pgh.pa.us]
> 
> 
> > I just remembered a report from Forest Wilkinson
> > about a month ago [SQL] SQL functions not locking
> > properly?
> 
> Yes, that was on my to-look-at list too.  Not sure if it's related.
> 

As I replied to his posting,the cause is obvious.
Because the queries in a function are executed under
the same snapshot,SELECT statements never
see the changes made by other backends.
OTOH SELECT .. FOR UPDATE has a different visiblity
from simple SELECT. Yes,SELECT .. FOR UPDATE
doesn't guarantee read consistency because it has to
acquire a lock on the latest tuples.
I recommended to use SELECT .. FOR UPDATE then
but it's far from being reasonable.

> > Don't we have to distiguish simple procedure calls
> > (select func();) and function calls as a part of a query ?
> 
> "select func()" looks like a query to me.  I don't see how you are going
> to make such a distinction in a useful way.  If we had a CALL statement
> distinct from function invocation in expressions, then maybe it'd make
> sense for that context to act differently.
>

As I mentioned before,calling functions which have strong side effect e.g.  select strong_effect(column1), column2 from
table1where ...;
 
is a problem. IMHO the use of functions should be restricted.
Of cource,we have to call(execute)procedures which change
the database. Unfortunately we don't have a command to call
(execute) functions as procedures currently.

Regards.
Hiroshi Inoue


Re: time stops within transaction

From
Hiroshi Inoue
Date:

Vadim Mikheev wrote:

> > I am inclined to think that we should do SetQuerySnapshot in the outer
> > loop of pg_exec_query_string, just before calling
> > pg_analyze_and_rewrite.  This would ensure that parse/plan accesses to
>                                            ^^^^^^^^^^^^^^
> Actually not - snapshot is passed as parameter to heap_beginscan...
> And currently SnapshotNow is used everywhere.
>

I sometimes mentioned anxieties about the use of SnapshotNow,
though I 've had no reasonable solution for it.
SnapshotNow isn't a real snapshot and so it wouldn't be able to
give us a complete consistency e.g. in the case "DDL statements
in transaction block".

However I couldn't think of any reasnoable way how to
handle the following cases.

We would have PREPARE statements in the near future.
How does PREPARE use the same snapshot as the execution ?
We would never be able to have shared catalog cache.
We coulnd't delete dropped table files immediately after commit.
...

Regards.
Hiroshi Inoue