Обсуждение: functions with side effect

Поиск
Список
Период
Сортировка

functions with side effect

От
Torsten Förtsch
Дата:
Hi,

assuming 

SELECT nextval('s'), currval('s');

or

SELECT * FROM (VALUES (nextval('s'), currval('s'))) t;

is there any guarantee that the 2 output values are the same?

Thanks,
Torsten

Re: functions with side effect

От
Laurenz Albe
Дата:
Torsten Förtsch wrote:
> assuming 
> 
> SELECT nextval('s'), currval('s');
> 
> or
> 
> SELECT * FROM (VALUES (nextval('s'), currval('s'))) t;
> 
> is there any guarantee that the 2 output values are the same?

You can use at EXPLAIN (VERBOSE) output to see if it will work
in this special case, but I wouldn't depend on it in general.

Yours,
Laurenz Albe
-- 
Cybertec | https://www.cybertec-postgresql.com


Re: functions with side effect

От
Adrian Klaver
Дата:
On 07/19/2018 07:15 AM, Torsten Förtsch wrote:
> Hi,
> 
> assuming
> 
> SELECT nextval('s'), currval('s');
> 
> or
> 
> SELECT * FROM (VALUES (nextval('s'), currval('s'))) t;
> 
> is there any guarantee that the 2 output values are the same?

Assuming you are only working in single session:

https://www.postgresql.org/docs/10/static/functions-sequence.html

"currval

     Return the value most recently obtained by nextval for this 
sequence in the current session. (An error is reported if nextval has 
never been called for this sequence in this session.) Because this is 
returning a session-local value, it gives a predictable answer whether 
or not other sessions have executed nextval since the current session did."

> 
> Thanks,
> Torsten


-- 
Adrian Klaver
adrian.klaver@aklaver.com


Re: functions with side effect

От
Torsten Förtsch
Дата:
On Thu, Jul 19, 2018 at 6:35 PM Adrian Klaver <adrian.klaver@aklaver.com> wrote:
On 07/19/2018 07:15 AM, Torsten Förtsch wrote:
> Hi,
>
> assuming
>
> SELECT nextval('s'), currval('s');
>
> or
>
> SELECT * FROM (VALUES (nextval('s'), currval('s'))) t;
>
> is there any guarantee that the 2 output values are the same?

Assuming you are only working in single session:

https://www.postgresql.org/docs/10/static/functions-sequence.html

"currval

     Return the value most recently obtained by nextval for this
sequence in the current session. (An error is reported if nextval has
never been called for this sequence in this session.) Because this is
returning a session-local value, it gives a predictable answer whether
or not other sessions have executed nextval since the current session did."

I know that. My question was about the execution order of f1 and f2 in "SELECT f1(), f2()". In theory they can be executed in any order. But since the side effect in nextval determines the result of currval, I am asking if that order is well-defined or considered an implementation detail like in C.

Re: functions with side effect

От
Adrian Klaver
Дата:
On 07/19/2018 09:43 AM, Torsten Förtsch wrote:
> On Thu, Jul 19, 2018 at 6:35 PM Adrian Klaver <adrian.klaver@aklaver.com 
> <mailto:adrian.klaver@aklaver.com>> wrote:
> 
>     On 07/19/2018 07:15 AM, Torsten Förtsch wrote:
>      > Hi,
>      >
>      > assuming
>      >
>      > SELECT nextval('s'), currval('s');
>      >
>      > or
>      >
>      > SELECT * FROM (VALUES (nextval('s'), currval('s'))) t;
>      >
>      > is there any guarantee that the 2 output values are the same?
> 
>     Assuming you are only working in single session:
> 
>     https://www.postgresql.org/docs/10/static/functions-sequence.html
> 
>     "currval
> 
>           Return the value most recently obtained by nextval for this
>     sequence in the current session. (An error is reported if nextval has
>     never been called for this sequence in this session.) Because this is
>     returning a session-local value, it gives a predictable answer whether
>     or not other sessions have executed nextval since the current
>     session did."
> 
> 
> I know that. My question was about the execution order of f1 and f2 in 
> "SELECT f1(), f2()". In theory they can be executed in any order. But 
> since the side effect in nextval determines the result of currval, I am 
> asking if that order is well-defined or considered an implementation 
> detail like in C.
> 

Can't answer definitively, but:

create sequence order_test;

DO
$$
DECLARE
     rs record;
BEGIN
     FOR i IN 1..1000 LOOP
         SELECT INTO rs nextval('order_test'), currval('order_test');
         RAISE NOTICE 'Currval is %', rs.currval;
     END LOOP;
END$$;

has not failed over multiple runs.

-- 
Adrian Klaver
adrian.klaver@aklaver.com


Re: functions with side effect

От
Pavel Luzanov
Дата:
Very interesting question.

postgres=# create sequence s;
CREATE SEQUENCE
postgres=# select currval('s'), nextval('s');
ERROR:  currval of sequence "s" is not yet defined in this session
postgres=# select nextval('s'), currval('s');
 nextval | currval
---------+---------
       1 |       1

We see different result with different order of functions.
So the question is: in which order expressions evaluated.
And I don't think that we can rely on this order.

Moreover, according to SQL standard[1]:
"If there are multiple instances of <next value expression>s specifying the same sequence generator within a
single SQL-statement, all those instances return the same value for a given row processed by that SQL-statement."

But in fact nextval return new value each time:

postgres=# select nextval('s'), nextval('s') from generate_series (1,3);
 nextval | nextval
---------+---------
       2 |       3
       4 |       5
       6 |       7

[1] http://www.wiscorp.com/sql_2003_standard.zip
    5WD-02-Foundation-2003-09.pdf
        4.21.2 Operations involving sequence generators
-----
Pavel Luzanov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
On 19.07.2018 19:43, Torsten Förtsch wrote:
On Thu, Jul 19, 2018 at 6:35 PM Adrian Klaver <adrian.klaver@aklaver.com> wrote:
On 07/19/2018 07:15 AM, Torsten Förtsch wrote:
> Hi,
>
> assuming
>
> SELECT nextval('s'), currval('s');
>
> or
>
> SELECT * FROM (VALUES (nextval('s'), currval('s'))) t;
>
> is there any guarantee that the 2 output values are the same?

Assuming you are only working in single session:

https://www.postgresql.org/docs/10/static/functions-sequence.html

"currval

     Return the value most recently obtained by nextval for this
sequence in the current session. (An error is reported if nextval has
never been called for this sequence in this session.) Because this is
returning a session-local value, it gives a predictable answer whether
or not other sessions have executed nextval since the current session did."

I know that. My question was about the execution order of f1 and f2 in "SELECT f1(), f2()". In theory they can be executed in any order. But since the side effect in nextval determines the result of currval, I am asking if that order is well-defined or considered an implementation detail like in C.


Re: functions with side effect

От
Adrian Klaver
Дата:
On 07/19/2018 09:43 AM, Torsten Förtsch wrote:
> On Thu, Jul 19, 2018 at 6:35 PM Adrian Klaver <adrian.klaver@aklaver.com 
> <mailto:adrian.klaver@aklaver.com>> wrote:
> 
>     On 07/19/2018 07:15 AM, Torsten Förtsch wrote:
>      > Hi,
>      >
>      > assuming
>      >
>      > SELECT nextval('s'), currval('s');
>      >
>      > or
>      >
>      > SELECT * FROM (VALUES (nextval('s'), currval('s'))) t;
>      >
>      > is there any guarantee that the 2 output values are the same?
> 
>     Assuming you are only working in single session:
> 
>     https://www.postgresql.org/docs/10/static/functions-sequence.html
> 
>     "currval
> 
>           Return the value most recently obtained by nextval for this
>     sequence in the current session. (An error is reported if nextval has
>     never been called for this sequence in this session.) Because this is
>     returning a session-local value, it gives a predictable answer whether
>     or not other sessions have executed nextval since the current
>     session did."
> 
> 
> I know that. My question was about the execution order of f1 and f2 in 
> "SELECT f1(), f2()". In theory they can be executed in any order. But 
> since the side effect in nextval determines the result of currval, I am 
> asking if that order is well-defined or considered an implementation 
> detail like in C.
> 

To eliminate plan caching:

DO
$$
DECLARE
     rs record;
BEGIN
     FOR i IN 1..1000 LOOP
         EXECUTE 'SELECT  nextval($1), currval($1)' INTO rs USING 
'order_test';
         RAISE NOTICE 'Currval is %', rs.currval;
     END LOOP;
END$$;

It still works over multiple runs, even when bumping LOOP counter to 
100,000.

-- 
Adrian Klaver
adrian.klaver@aklaver.com


Re: functions with side effect

От
Tom Lane
Дата:
=?UTF-8?Q?Torsten_F=C3=B6rtsch?= <tfoertsch123@gmail.com> writes:
> I know that. My question was about the execution order of f1 and f2 in
> "SELECT f1(), f2()". In theory they can be executed in any order. But since
> the side effect in nextval determines the result of currval, I am asking if
> that order is well-defined or considered an implementation detail like in C.

The current implementation evaluates select-list items left to right.
I doubt we'd be eager to change that, since there are surely many
applications that depend on that behavior, whether it's formally specified
or not.  But elsewhere in a query than the select target list, there are
no guarantees, and there's lots of precedent for whacking around the
evaluation order in e.g. WHERE.

I'd be a little more wary with examples like your other one:

SELECT * FROM (VALUES (nextval('s'), currval('s'))) t;

since there's an additional unspecified question there, which is
whether the planner will "flatten" the sub-select.  To put it more
clearly, you'd be taking big risks with

SELECT y, x FROM (VALUES (nextval('s'), currval('s'))) t(x, y);

Right now it seems the nextval is done first, but I would not want to bet
on that staying true in the future.  [ experiments some more ... ]
Actually, looks like we have a rule against flattening sub-selects whose
targetlists contain volatile functions, so maybe you'd get away with that
for the indefinite future too.

            regards, tom lane


Re: functions with side effect

От
Torsten Förtsch
Дата:
On Thu, Jul 19, 2018 at 8:10 PM Tom Lane <tgl@sss.pgh.pa.us> wrote:
Torsten Förtsch <tfoertsch123@gmail.com> writes:
> I know that. My question was about the execution order of f1 and f2 in
> "SELECT f1(), f2()". In theory they can be executed in any order. But since
> the side effect in nextval determines the result of currval, I am asking if
> that order is well-defined or considered an implementation detail like in C.

The current implementation evaluates select-list items left to right.
I doubt we'd be eager to change that, since there are surely many
applications that depend on that behavior, whether it's formally specified
or not.  But elsewhere in a query than the select target list, there are
no guarantees, and there's lots of precedent for whacking around the
evaluation order in e.g. WHERE.

I'd be a little more wary with examples like your other one:

SELECT * FROM (VALUES (nextval('s'), currval('s'))) t;

since there's an additional unspecified question there, which is
whether the planner will "flatten" the sub-select.  To put it more
clearly, you'd be taking big risks with

SELECT y, x FROM (VALUES (nextval('s'), currval('s'))) t(x, y);

Right now it seems the nextval is done first, but I would not want to bet
on that staying true in the future.  [ experiments some more ... ]
Actually, looks like we have a rule against flattening sub-selects whose
targetlists contain volatile functions, so maybe you'd get away with that
for the indefinite future too.

 Thanks, this was actually a part of an insert statement I found in our code. Something like

INSERT INTO ...
VALUES (nextval(), ..., 'string' || currval())

Just to be on the safe side I changed it to

INSERT INTO ...
SELECT next.id, ..., 'string' || next.id
FROM nextval() next(id)