mirror of
https://github.com/postgres/postgres.git
synced 2025-04-25 21:42:33 +03:00
Fix ALTER SEQUENCE so that it does not affect the value of currval() for
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.
This commit is contained in:
parent
dbe48765cd
commit
9ddfe034c7
@ -1,4 +1,4 @@
|
|||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.404 2007/10/23 20:46:11 tgl Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.405 2007/10/25 18:54:03 tgl Exp $ -->
|
||||||
|
|
||||||
<chapter id="functions">
|
<chapter id="functions">
|
||||||
<title>Functions and Operators</title>
|
<title>Functions and Operators</title>
|
||||||
@ -8733,15 +8733,20 @@ nextval('foo'::text) <lineannotation><literal>foo</literal> is looked up at
|
|||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
Reset the sequence object's counter value. The two-parameter
|
Reset the sequence object's counter value. The two-parameter
|
||||||
form sets the sequence's <literal>last_value</literal> field to the specified
|
form sets the sequence's <literal>last_value</literal> field to the
|
||||||
value and sets its <literal>is_called</literal> field to <literal>true</literal>,
|
specified value and sets its <literal>is_called</literal> field to
|
||||||
meaning that the next <function>nextval</function> will advance the sequence
|
<literal>true</literal>, meaning that the next
|
||||||
before returning a value. In the three-parameter form,
|
<function>nextval</function> will advance the sequence before
|
||||||
<literal>is_called</literal> can be set either <literal>true</literal> or
|
returning a value. The value reported by <function>currval</> is
|
||||||
<literal>false</literal>. If it's set to <literal>false</literal>,
|
also set to the specified value. In the three-parameter form,
|
||||||
the next <function>nextval</function> will return exactly the specified
|
<literal>is_called</literal> can be set either <literal>true</literal>
|
||||||
|
or <literal>false</literal>. <literal>true</> has the same effect as
|
||||||
|
the two-parameter form. If it's set to <literal>false</literal>, the
|
||||||
|
next <function>nextval</function> will return exactly the specified
|
||||||
value, and sequence advancement commences with the following
|
value, and sequence advancement commences with the following
|
||||||
<function>nextval</function>. For example,
|
<function>nextval</function>. Furthermore, the value reported by
|
||||||
|
<function>currval</> is not changed in this case (this is a change
|
||||||
|
from pre-8.3 behavior). For example,
|
||||||
|
|
||||||
<screen>
|
<screen>
|
||||||
SELECT setval('foo', 42); <lineannotation>Next <function>nextval</> will return 43</lineannotation>
|
SELECT setval('foo', 42); <lineannotation>Next <function>nextval</> will return 43</lineannotation>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<!--
|
<!--
|
||||||
$PostgreSQL: pgsql/doc/src/sgml/ref/alter_sequence.sgml,v 1.18 2007/10/03 16:48:43 tgl Exp $
|
$PostgreSQL: pgsql/doc/src/sgml/ref/alter_sequence.sgml,v 1.19 2007/10/25 18:54:03 tgl Exp $
|
||||||
PostgreSQL documentation
|
PostgreSQL documentation
|
||||||
-->
|
-->
|
||||||
|
|
||||||
@ -114,7 +114,10 @@ ALTER SEQUENCE <replaceable class="parameter">name</replaceable> SET SCHEMA <rep
|
|||||||
<para>
|
<para>
|
||||||
The optional clause <literal>RESTART WITH <replaceable
|
The optional clause <literal>RESTART WITH <replaceable
|
||||||
class="parameter">start</replaceable></literal> changes the
|
class="parameter">start</replaceable></literal> changes the
|
||||||
current value of the sequence.
|
current value of the sequence. This is equivalent to calling the
|
||||||
|
<function>setval</> function with <literal>is_called</literal> =
|
||||||
|
<literal>false</>: the specified value will be returned by the
|
||||||
|
<emphasis>next</> call of <function>nextval</>.
|
||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
@ -226,6 +229,12 @@ ALTER SEQUENCE <replaceable class="parameter">name</replaceable> SET SCHEMA <rep
|
|||||||
immediately.
|
immediately.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
<command>ALTER SEQUENCE</command> does not affect the <function>currval</>
|
||||||
|
status for the sequence. (Before <productname>PostgreSQL</productname>
|
||||||
|
8.3, it sometimes did.)
|
||||||
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Some variants of <command>ALTER TABLE</command> can be used with
|
Some variants of <command>ALTER TABLE</command> can be used with
|
||||||
sequences as well; for example, to rename a sequence it is also
|
sequences as well; for example, to rename a sequence it is also
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* 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 */
|
struct SeqTableData *next; /* link to next SeqTable object */
|
||||||
Oid relid; /* pg_class OID of this sequence */
|
Oid relid; /* pg_class OID of this sequence */
|
||||||
LocalTransactionId lxid; /* xact in which we last did a seq op */
|
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 last; /* value last returned by nextval */
|
||||||
int64 cached; /* last value already cached for nextval */
|
int64 cached; /* last value already cached for nextval */
|
||||||
/* if last != cached, we have not used up all the cached values */
|
/* if last != cached, we have not used up all the cached values */
|
||||||
int64 increment; /* copy of sequence's increment field */
|
int64 increment; /* copy of sequence's increment field */
|
||||||
|
/* note that increment is zero until we first do read_info() */
|
||||||
} SeqTableData;
|
} SeqTableData;
|
||||||
|
|
||||||
typedef SeqTableData *SeqTable;
|
typedef SeqTableData *SeqTable;
|
||||||
@ -336,14 +338,13 @@ AlterSequence(AlterSeqStmt *stmt)
|
|||||||
/* Check and set new values */
|
/* Check and set new values */
|
||||||
init_params(stmt->options, false, &new, &owned_by);
|
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 */
|
/* Now okay to update the on-disk tuple */
|
||||||
memcpy(seq, &new, sizeof(FormData_pg_sequence));
|
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();
|
START_CRIT_SECTION();
|
||||||
|
|
||||||
MarkBufferDirty(buf);
|
MarkBufferDirty(buf);
|
||||||
@ -443,9 +444,11 @@ nextval_internal(Oid relid)
|
|||||||
|
|
||||||
if (elm->last != elm->cached) /* some numbers were cached */
|
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;
|
elm->last += elm->increment;
|
||||||
relation_close(seqrel, NoLock);
|
relation_close(seqrel, NoLock);
|
||||||
|
last_used_seq = elm;
|
||||||
return elm->last;
|
return elm->last;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -564,6 +567,7 @@ nextval_internal(Oid relid)
|
|||||||
/* save info in local cache */
|
/* save info in local cache */
|
||||||
elm->last = result; /* last returned number */
|
elm->last = result; /* last returned number */
|
||||||
elm->cached = last; /* last fetched number */
|
elm->cached = last; /* last fetched number */
|
||||||
|
elm->last_valid = true;
|
||||||
|
|
||||||
last_used_seq = elm;
|
last_used_seq = elm;
|
||||||
|
|
||||||
@ -633,7 +637,7 @@ currval_oid(PG_FUNCTION_ARGS)
|
|||||||
errmsg("permission denied for sequence %s",
|
errmsg("permission denied for sequence %s",
|
||||||
RelationGetRelationName(seqrel))));
|
RelationGetRelationName(seqrel))));
|
||||||
|
|
||||||
if (elm->increment == 0) /* nextval/read_info were not called */
|
if (!elm->last_valid)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||||
errmsg("currval of sequence \"%s\" is not yet defined in this session",
|
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);
|
seqrel = open_share_lock(last_used_seq);
|
||||||
|
|
||||||
/* nextval() must have already been called for this sequence */
|
/* 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 &&
|
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)
|
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)));
|
bufm, bufx)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* save info in local cache */
|
/* Set the currval() state only if iscalled = true */
|
||||||
|
if (iscalled)
|
||||||
|
{
|
||||||
elm->last = next; /* last returned number */
|
elm->last = next; /* last returned number */
|
||||||
elm->cached = next; /* last cached number (forget cached values) */
|
elm->last_valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In any case, forget any future cached numbers */
|
||||||
|
elm->cached = elm->last;
|
||||||
|
|
||||||
START_CRIT_SECTION();
|
START_CRIT_SECTION();
|
||||||
|
|
||||||
@ -893,7 +903,7 @@ init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel)
|
|||||||
errmsg("out of memory")));
|
errmsg("out of memory")));
|
||||||
elm->relid = relid;
|
elm->relid = relid;
|
||||||
elm->lxid = InvalidLocalTransactionId;
|
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->last = elm->cached = elm->increment = 0;
|
||||||
elm->next = seqtab;
|
elm->next = seqtab;
|
||||||
seqtab = elm;
|
seqtab = elm;
|
||||||
@ -941,6 +951,7 @@ read_info(SeqTable elm, Relation rel, Buffer *buf)
|
|||||||
|
|
||||||
seq = (Form_pg_sequence) GETSTRUCT(&tuple);
|
seq = (Form_pg_sequence) GETSTRUCT(&tuple);
|
||||||
|
|
||||||
|
/* this is a handy place to update our copy of the increment */
|
||||||
elm->increment = seq->increment_by;
|
elm->increment = seq->increment_by;
|
||||||
|
|
||||||
return seq;
|
return seq;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user