serial increments on failed insert

Ask a Question related to PostgreSQL / PGSQL, Design and Development.

  1. #1

    Default serial increments on failed insert

    Ive 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

    ---------------------------(end of broadcast)---------------------------
    TIP 7: don't forget to increase your free space map settings

    David Kammer Guest

  2. Similar Questions and Discussions

    1. insert failed
      hope you can help solve this problem, ok my database field: tblA TSK_ID (autonumber) key (not Null) USR_ID (autonumber) (not Null) TSKCTDT...
    2. cmin increments by 2 except in 7.4?
      I've noticed that in PostgreSQL 7.4, successive commands in a transaction get cmin values that increment by 1, but in other versions cmin...
    3. Return value of 'serial' column on insert
      Hi all, I have several tables with an 'id' column which is a simple 'serial unique' type. Often when I insert a record the next thing I need is...
    4. string comparison and increments
      on our work registration system we use the first part of the email address (eg. john.smith) as the username for the registrant, the user has no...
    5. OT: rotate in smaller increments?
      Sorry, Sam, this was an old post, but I can't help but wonder...what's the story behind this? "Sam Poikail" <indigo_wolf@hotmail.com> wrote in...
  3. #2

    Default serial increments on failed insert

    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

    ---------------------------(end of broadcast)---------------------------
    TIP 8: explain analyze is your friend

    David Kammer Guest

  4. #3

    Default Re: serial increments on failed insert

    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

    ---------------------------(end of broadcast)---------------------------
    TIP 1: subscribe and unsubscribe commands go to [email]majordomo@postgresql.org[/email]

    Tom Lane Guest

  5. #4

    Default Re: serial increments on failed insert

    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


    ---------------------------(end of broadcast)---------------------------
    TIP 3: if posting/reading through Usenet, please send an appropriate
    subscribe-nomail command to [email]majordomo@postgresql.org[/email] so that your
    message can get through to the mailing list cleanly

    Steve Atkins Guest

  6. #5

    Default Re: serial increments on failed insert

    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
    [url]http://www.fuhr.org/~mfuhr/[/url]

    ---------------------------(end of broadcast)---------------------------
    TIP 8: explain analyze is your friend

    Michael Fuhr Guest

  7. #6

    Default Re: serial increments on failed insert

    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.

    ---------------------------(end of broadcast)---------------------------
    TIP 5: Have you checked our extensive FAQ?

    [url]http://www.postgresql.org/docs/faqs/FAQ.html[/url]

    Bruno Wolff III Guest

  8. #7

    Default Re: serial increments on failed insert

    On Fri, Jan 14, 2005 at 04:48:12PM -0800, David Kammer wrote:
    > Ive 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?
    Perhaps the docs need revision to clarify this. The SERIAL type is
    meant to generate id's (in this case, integers) which are guaranteed
    to be unique. Because they have this uniqueness property, they are
    *not* guaranteed to be gapless.

    Cheers,
    D
    --
    David Fetter [email]david@fetter.org[/email] [url]http://fetter.org/[/url]
    phone: +1 510 893 6100 mobile: +1 415 235 3778

    Remember to vote!

    ---------------------------(end of broadcast)---------------------------
    TIP 5: Have you checked our extensive FAQ?

    [url]http://www.postgresql.org/docs/faqs/FAQ.html[/url]

    David Fetter Guest

  9. #8

    Default Re: serial increments on failed insert

    I had the same problem on one of my tables. What I did was change the column to an integer, create a sequence, create a trigger function, and set a before insert trigger:

    <modify the table so the column is an integer>

    CREATE SEQUENCE tblloc_rowid;

    CREATE OR REPLACE FUNCTION process_tblloc() RETURNS TRIGGER AS $process_tblloc$
    BEGIN
    IF (TG_OP = 'INSERT') THEN
    NEW.rowid = nextval('tblloc_rowid'::regclass);
    RETURN NEW;
    END IF;
    RETURN NULL; -- result is ignored since this is an AFTER trigger
    END;
    $process_tblloc$ LANGUAGE plpgsql;

    CREATE TRIGGER tblloc_insert_rowid BEFORE INSERT ON tblloc FOR EACH ROW EXECUTE PROCEDURE process_tblloc();

    This only gets the next sequence when a row is being inserted (it isn't called on a failed insert), keeping the sequence from skipping numbers.

    Anyway - works for me, maybe it'll work for you too.

    Regards,
    Ron
    rp71 Guest

Posting Permissions

  • You may not post new threads
  • You may post replies
  • You may not post attachments
  • You may not edit your posts

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139