Fix ALTER SEQUENCE so that it does not affect the value of currval() for
authorTom Lane
Thu, 25 Oct 2007 18:54:03 +0000 (18:54 +0000)
committerTom Lane
Thu, 25 Oct 2007 18:54:03 +0000 (18:54 +0000)
the sequence.  Also, make setval() with is_called = false not affect the
currval state, either.  Per report from Kris Jurka that an implicit
ALTER SEQUENCE OWNED BY unexpectedly caused currval() to become valid.
Since this isn't 100% backwards compatible, it will go into HEAD only;
I'll put a more limited patch into 8.2.

doc/src/sgml/func.sgml
doc/src/sgml/ref/alter_sequence.sgml
src/backend/commands/sequence.c

index c9d665376e4096d725c1599aad27e895e021d716..5feb572de2d9b3f9c7b1ff65135fa6f35f56902b 100644 (file)
@@ -1,4 +1,4 @@
-
+
 
  
   Functions and Operators
@@ -8733,15 +8733,20 @@ nextval('foo'::text)      foo is looked up at
       
        
         Reset the sequence object's counter value.  The two-parameter
-        form sets the sequence's last_value field to the specified
-        value and sets its is_called field to true,
-        meaning that the next nextval will advance the sequence
-        before returning a value.  In the three-parameter form,
-        is_called can be set either true or
-        false.  If it's set to false,
-        the next nextval will return exactly the specified
+        form sets the sequence's last_value field to the
+        specified value and sets its is_called field to
+        true, meaning that the next
+        nextval will advance the sequence before
+        returning a value.  The value reported by currval is
+        also set to the specified value.  In the three-parameter form,
+        is_called can be set either true
+        or false.  true has the same effect as
+        the two-parameter form. If it's set to false, the
+        next nextval will return exactly the specified
         value, and sequence advancement commences with the following
-        nextval.  For example,
+        nextval.  Furthermore, the value reported by
+        currval is not changed in this case (this is a change
+        from pre-8.3 behavior).  For example,
 
 
 SELECT setval('foo', 42);           Next nextval will return 43
index b515ae46016485a3b424e848bd27b900ed884ed0..3c982eee6f1855451933a668178b5f74ded04b59 100644 (file)
@@ -1,5 +1,5 @@
 
 
@@ -114,7 +114,10 @@ ALTER SEQUENCE name SET SCHEMA 
        
         The optional clause RESTART WITH 
         class="parameter">start changes the
-        current value of the sequence.
+        current value of the sequence.  This is equivalent to calling the
+        setval function with is_called =
+        false: the specified value will be returned by the
+        next call of nextval.
        
       
      
@@ -226,6 +229,12 @@ ALTER SEQUENCE name SET SCHEMA 
    immediately.
   
 
+  
+   ALTER SEQUENCE does not affect the currval
+   status for the sequence.  (Before PostgreSQL
+   8.3, it sometimes did.)
+  
+
   
    Some variants of ALTER TABLE can be used with
    sequences as well; for example, to rename a sequence it is also
index 25d1e2311b6d7ca95645a54e4b21c6a87130994f..619e289206be722610c124161c8f334361107657 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *   $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.146 2007/09/20 17:56:31 tgl Exp $
+ *   $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.147 2007/10/25 18:54:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -65,10 +65,12 @@ typedef struct SeqTableData
    struct SeqTableData *next;  /* link to next SeqTable object */
    Oid         relid;          /* pg_class OID of this sequence */
    LocalTransactionId lxid;    /* xact in which we last did a seq op */
+   bool        last_valid;     /* do we have a valid "last" value? */
    int64       last;           /* value last returned by nextval */
    int64       cached;         /* last value already cached for nextval */
    /* if last != cached, we have not used up all the cached values */
    int64       increment;      /* copy of sequence's increment field */
+   /* note that increment is zero until we first do read_info() */
 } SeqTableData;
 
 typedef SeqTableData *SeqTable;
@@ -336,14 +338,13 @@ AlterSequence(AlterSeqStmt *stmt)
    /* Check and set new values */
    init_params(stmt->options, false, &new, &owned_by);
 
+   /* Clear local cache so that we don't think we have cached numbers */
+   /* Note that we do not change the currval() state */
+   elm->cached = elm->last;
+
    /* Now okay to update the on-disk tuple */
    memcpy(seq, &new, sizeof(FormData_pg_sequence));
 
-   /* Clear local cache so that we don't think we have cached numbers */
-   elm->last = new.last_value; /* last returned number */
-   elm->cached = new.last_value;       /* last cached number (forget cached
-                                        * values) */
-
    START_CRIT_SECTION();
 
    MarkBufferDirty(buf);
@@ -443,9 +444,11 @@ nextval_internal(Oid relid)
 
    if (elm->last != elm->cached)       /* some numbers were cached */
    {
-       last_used_seq = elm;
+       Assert(elm->last_valid);
+       Assert(elm->increment != 0);
        elm->last += elm->increment;
        relation_close(seqrel, NoLock);
+       last_used_seq = elm;
        return elm->last;
    }
 
@@ -564,6 +567,7 @@ nextval_internal(Oid relid)
    /* save info in local cache */
    elm->last = result;         /* last returned number */
    elm->cached = last;         /* last fetched number */
+   elm->last_valid = true;
 
    last_used_seq = elm;
 
@@ -633,7 +637,7 @@ currval_oid(PG_FUNCTION_ARGS)
                 errmsg("permission denied for sequence %s",
                        RelationGetRelationName(seqrel))));
 
-   if (elm->increment == 0)    /* nextval/read_info were not called */
+   if (!elm->last_valid)
        ereport(ERROR,
                (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                 errmsg("currval of sequence \"%s\" is not yet defined in this session",
@@ -668,7 +672,7 @@ lastval(PG_FUNCTION_ARGS)
    seqrel = open_share_lock(last_used_seq);
 
    /* nextval() must have already been called for this sequence */
-   Assert(last_used_seq->increment != 0);
+   Assert(last_used_seq->last_valid);
 
    if (pg_class_aclcheck(last_used_seq->relid, GetUserId(), ACL_SELECT) != ACLCHECK_OK &&
        pg_class_aclcheck(last_used_seq->relid, GetUserId(), ACL_USAGE) != ACLCHECK_OK)
@@ -732,9 +736,15 @@ do_setval(Oid relid, int64 next, bool iscalled)
                        bufm, bufx)));
    }
 
-   /* save info in local cache */
-   elm->last = next;           /* last returned number */
-   elm->cached = next;         /* last cached number (forget cached values) */
+   /* Set the currval() state only if iscalled = true */
+   if (iscalled)
+   {
+       elm->last = next;       /* last returned number */
+       elm->last_valid = true;
+   }
+
+   /* In any case, forget any future cached numbers */
+   elm->cached = elm->last;
 
    START_CRIT_SECTION();
 
@@ -893,7 +903,7 @@ init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
                     errmsg("out of memory")));
        elm->relid = relid;
        elm->lxid = InvalidLocalTransactionId;
-       /* increment is set to 0 until we do read_info (see currval) */
+       elm->last_valid = false;
        elm->last = elm->cached = elm->increment = 0;
        elm->next = seqtab;
        seqtab = elm;
@@ -941,6 +951,7 @@ read_info(SeqTable elm, Relation rel, Buffer *buf)
 
    seq = (Form_pg_sequence) GETSTRUCT(&tuple);
 
+   /* this is a handy place to update our copy of the increment */
    elm->increment = seq->increment_by;
 
    return seq;