BUG #1083: Insert query reordering interacts badly with NEXTVAL()/CURRVAL()

Started by PostgreSQL Bugs Listabout 22 years ago7 messagesbugs
Jump to latest
#1PostgreSQL Bugs List
pgsql-bugs@postgresql.org

The following bug has been logged online:

Bug reference: 1083
Logged by: Martin Langhoff

Email address: martin@catalyst.net.nz

PostgreSQL version: 7.4

Operating system: Linux irkutsk 2.4.25-piv-smp-server #1 SMP Fri Feb 20
16:56:47 NZDT 2004 i686 unknown

Description: Insert query reordering interacts badly with
NEXTVAL()/CURRVAL()

Details:

=== SQL ===

CREATE TEMP TABLE testing (col_a integer, col_b integer);
CREATE TEMP SEQUENCE seq;

/* this statement will produce the expected result */
INSERT INTO testing (col_a, col_b) VALUES (NEXTVAL('seq'), CURRVAL('seq'));

/* this statement will reverse the order of CURRVAL()/NEXTVAL() to match the
column order of the table */
INSERT INTO testing (col_b, col_a) VALUES (NEXTVAL('seq'), CURRVAL('seq'));

SELECT * FROM testing;

=== END SQL ===

Output looks like:

col_a | col_b
-------+-------
1 | 1
1 | 2

I was expecting:

col_a | col_b
-------+-------
1 | 1
2 | 2

#2Bruno Wolff III
bruno@wolff.to
In reply to: PostgreSQL Bugs List (#1)
Re: BUG #1083: Insert query reordering interacts badly with NEXTVAL()/CURRVAL()

On Mon, Feb 23, 2004 at 21:26:57 -0400,
PostgreSQL Bugs List <pgsql-bugs@postgresql.org> wrote:

Details:

=== SQL ===

CREATE TEMP TABLE testing (col_a integer, col_b integer);
CREATE TEMP SEQUENCE seq;

/* this statement will produce the expected result */
INSERT INTO testing (col_a, col_b) VALUES (NEXTVAL('seq'), CURRVAL('seq'));

/* this statement will reverse the order of CURRVAL()/NEXTVAL() to match the
column order of the table */
INSERT INTO testing (col_b, col_a) VALUES (NEXTVAL('seq'), CURRVAL('seq'));

I don't think an order of evaluation is guarenteed for INSERT VALUE lists.

#3Tom Lane
tgl@sss.pgh.pa.us
In reply to: PostgreSQL Bugs List (#1)
Re: BUG #1083: Insert query reordering interacts badly with NEXTVAL()/CURRVAL()

"PostgreSQL Bugs List" <pgsql-bugs@postgresql.org> writes:

/* this statement will reverse the order of CURRVAL()/NEXTVAL() to match the
column order of the table */
INSERT INTO testing (col_b, col_a) VALUES (NEXTVAL('seq'), CURRVAL('seq'));

This is not a bug. The order of evaluation of select-lists and
values-lists is not defined anywhere in the SQL standard, nor promised
anywhere in the Postgres documentation. In fact, we specifically say
here:
http://www.postgresql.org/docs/7.4/static/sql-expressions.html#SYNTAX-EXPRESS-EVAL
that "The order of evaluation of subexpressions is not defined." To do
otherwise would put horrible crimps in our ability to optimize query plans.

regards, tom lane

#4Martin Langhoff
martin@catalyst.net.nz
In reply to: Tom Lane (#3)
Re: BUG #1083: Insert query reordering interacts badly with

Tom Lane wrote:

"PostgreSQL Bugs List" <pgsql-bugs@postgresql.org> writes:

/* this statement will reverse the order of CURRVAL()/NEXTVAL() to match the
column order of the table */
INSERT INTO testing (col_b, col_a) VALUES (NEXTVAL('seq'), CURRVAL('seq'));

This is not a bug. The order of evaluation of select-lists and
values-lists is not defined anywhere in the SQL standard, nor promised
anywhere in the Postgres documentation.

Thanks for the clarification. I am curious, however: I can't find a
means to achieve the same effect in a deterministic manner. Any pointers?

regards,

martin

--
-----------------------------------------------------------------------
Martin @ Catalyst .Net .NZ Ltd, PO Box 11-053, Manners St, Wellington
WEB: http://catalyst.net.nz/ PHYS: Level 2, 150-154 Willis St
OFFICE: +64(4)916-7224 MOB: +64(21)364-017
Make things as simple as possible, but no simpler - Einstein
-----------------------------------------------------------------------

#5Tom Lane
tgl@sss.pgh.pa.us
In reply to: Martin Langhoff (#4)
Re: BUG #1083: Insert query reordering interacts badly with NEXTVAL()/CURRVAL()

"Martin Langhoff (Catalyst IT)" <martin@catalyst.net.nz> writes:

Thanks for the clarification. I am curious, however: I can't find a
means to achieve the same effect in a deterministic manner. Any pointers?

How about

SELECT nextval('seq'); -- ignore result

INSERT INTO ... VALUES (currval('seq'), currval('seq'));

regards, tom lane

#6Martin Langhoff
martin@catalyst.net.nz
In reply to: Tom Lane (#5)
Re: BUG #1083: Insert query reordering interacts badly with

Tom Lane wrote:

How about

SELECT nextval('seq'); -- ignore result

INSERT INTO ... VALUES (currval('seq'), currval('seq'));

Well, it works for my sample case, I have to agree. Maybe I should
mention that I tried to boil down the bugreport to the simplest repro
case I could.

My actual SQL looks roughly like

INSERT INTO destination (record_id, page, row)
SELECT
(SELECT record_id FROM record ORDERED BY name),
(NEXTVAL('seq') / 200),
(CURRVAL('seq') % 200)

While I have a workaround, I am definitely curious as to whether there
is actually a way to do it. Thanks for your patience.

regards,

martin

--
-----------------------------------------------------------------------
Martin @ Catalyst .Net .NZ Ltd, PO Box 11-053, Manners St, Wellington
WEB: http://catalyst.net.nz/ PHYS: Level 2, 150-154 Willis St
OFFICE: +64(4)916-7224 MOB: +64(21)364-017
Make things as simple as possible, but no simpler - Einstein
-----------------------------------------------------------------------

#7Bruno Wolff III
bruno@wolff.to
In reply to: Martin Langhoff (#6)
Re: BUG #1083: Insert query reordering interacts badly with

I am going to try to move this over the sql list, since it doesn't belong
on bugs.

On Tue, Feb 24, 2004 at 23:47:48 +1300,
Martin Langhoff <martin@catalyst.net.nz> wrote:

Tom Lane wrote:

How about

SELECT nextval('seq'); -- ignore result

INSERT INTO ... VALUES (currval('seq'), currval('seq'));

Well, it works for my sample case, I have to agree. Maybe I should
mention that I tried to boil down the bugreport to the simplest repro
case I could.

My actual SQL looks roughly like

INSERT INTO destination (record_id, page, row)
SELECT
(SELECT record_id FROM record ORDERED BY name),
(NEXTVAL('seq') / 200),
(CURRVAL('seq') % 200)

While I have a workaround, I am definitely curious as to whether there
is actually a way to do it. Thanks for your patience.

I think the following will do what you want:

INSERT INTO destination (record_id, page, row)
SELECT record_id, seq/200, seq%200 FROM
(SELECT record_id, nextval('seq') as seq FROM record ORDERED BY name);