Thread: serial increments on failed insert

serial increments on failed insert

From
David Kammer
Date:
I've noticed what seems to be an odd effect in psql 7.3.  It works like
this:

1> Create a table:
CREATE TABLE foo
(
  sval serial,
  uval int UNIQUE
);

2> Run 3 inserts, the second of which fails because it fails the
   unique constraint:
INSERT INTO foo VALUES (DEFAULT,1);
INSERT INTO foo VALUES (DEFAULT,1);   <--- This fails
INSERT INTO foo VALUES (DEFAULT,2);

3> look at the table:
SELECT * FROM foo;
sval | uval
------+------
   1 |    1
   3 |    2   <--- look here
(2 rows)

Notice that even though the second insert failed, it still incremented
the serial value.  This seems counter intuative to the way that serial
should work.  Is this truly a bug, or is there a good work around?

Thanks,
Dave

Re: serial increments on failed insert

From
Tom Lane
Date:
David Kammer <djkammer@u.washington.edu> writes:
> Notice that even though the second insert failed, it still incremented
> the serial value.  This seems counter intuative to the way that serial
> should work.  Is this truly a bug,

No.  nextval() calls never roll back; see the documentation.

> is there a good work around?

Don't assume that a serial column is without gaps.  It's only intended
to be unique.

            regards, tom lane

Re: serial increments on failed insert

From
Steve Atkins
Date:
On Fri, Jan 14, 2005 at 04:57:19PM -0800, David Kammer wrote:

> Notice that even though the second insert failed, it still incremented
> the serial value.  This seems counter intuative to the way that serial
> should work.  Is this truly a bug, or is there a good work around?

That's correct, documented behaviour. A serial column is mostly just a
sequence in disguise. A sequence is guaranteed to give unique,
increasing values, but in many cases may miss a value (for several
reasons - in this case because once a sequence value is used, it's
used, even if the transaction it was used in is rolled back).

Do you really need that column to increase one at a time? Or just
to increase and be unique?

You could look at the maximum value in the column and use the maximum
value plus one (and be prepared to retry if there's an index on that
column to guarantee uniqueness).

Cheers,
  Steve


Re: serial increments on failed insert

From
Michael Fuhr
Date:
On Fri, Jan 14, 2005 at 04:57:19PM -0800, David Kammer wrote:

> Notice that even though the second insert failed, it still incremented
> the serial value.  This seems counter intuative to the way that serial
> should work.  Is this truly a bug, or is there a good work around?

See the "Sequence Manipulation Functions" section in the "Functions
and Operators" chapter of the documentation.  The page contains
the following note:

    Important:  To avoid blocking of concurrent transactions that obtain
    numbers from the same sequence, a nextval operation is never rolled
    back; that is, once a value has been fetched it is considered used,
    even if the transaction that did the nextval later aborts.  This
    means that aborted transactions may leave unused "holes" in the
    sequence of assigned values.  setval operations are never rolled
    back, either.

Sequences are for obtaining numbers guaranteed to be unique; other
assumptions about their behavior are probably unwarranted.

--
Michael Fuhr
http://www.fuhr.org/~mfuhr/

Re: serial increments on failed insert

From
Bruno Wolff III
Date:
On Fri, Jan 14, 2005 at 17:49:42 -0800,
  Steve Atkins <steve@blighty.com> wrote:
>
> That's correct, documented behaviour. A serial column is mostly just a
> sequence in disguise. A sequence is guaranteed to give unique,
> increasing values, but in many cases may miss a value (for several
> reasons - in this case because once a sequence value is used, it's
> used, even if the transaction it was used in is rolled back).

Note that the increasing part is only guarenteed within a session,
not accross sessions and only if you haven't changed the sequence
to allow it to roll over.