Commit 10a3471b authored by Tom Lane's avatar Tom Lane

Add a RESTART (without parameter) option to ALTER SEQUENCE, allowing a

sequence to be reset to its original starting value.  This requires adding the
original start value to the set of parameters (columns) of a sequence object,
which is a user-visible change with potential compatibility implications;
it also forces initdb.

Also add hopefully-SQL-compatible RESTART/CONTINUE IDENTITY options to
TRUNCATE TABLE.  RESTART IDENTITY executes ALTER SEQUENCE RESTART for all
sequences "owned by" any of the truncated relations.  CONTINUE IDENTITY is
a no-op option.

Zoltan Boszormenyi
parent 8a2f5d22
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/alter_sequence.sgml,v 1.19 2007/10/25 18:54:03 tgl Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/alter_sequence.sgml,v 1.20 2008/05/16 23:36:04 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -26,7 +26,7 @@ PostgreSQL documentation ...@@ -26,7 +26,7 @@ PostgreSQL documentation
<synopsis> <synopsis>
ALTER SEQUENCE <replaceable class="parameter">name</replaceable> [ INCREMENT [ BY ] <replaceable class="parameter">increment</replaceable> ] ALTER SEQUENCE <replaceable class="parameter">name</replaceable> [ INCREMENT [ BY ] <replaceable class="parameter">increment</replaceable> ]
[ MINVALUE <replaceable class="parameter">minvalue</replaceable> | NO MINVALUE ] [ MAXVALUE <replaceable class="parameter">maxvalue</replaceable> | NO MAXVALUE ] [ MINVALUE <replaceable class="parameter">minvalue</replaceable> | NO MINVALUE ] [ MAXVALUE <replaceable class="parameter">maxvalue</replaceable> | NO MAXVALUE ]
[ RESTART [ WITH ] <replaceable class="parameter">start</replaceable> ] [ CACHE <replaceable class="parameter">cache</replaceable> ] [ [ NO ] CYCLE ] [ RESTART [ [ WITH ] <replaceable class="parameter">start</replaceable> ] ] [ CACHE <replaceable class="parameter">cache</replaceable> ] [ [ NO ] CYCLE ]
[ OWNED BY { <replaceable class="parameter">table</replaceable>.<replaceable class="parameter">column</replaceable> | NONE } ] [ OWNED BY { <replaceable class="parameter">table</replaceable>.<replaceable class="parameter">column</replaceable> | NONE } ]
ALTER SEQUENCE <replaceable class="parameter">name</replaceable> RENAME TO <replaceable class="parameter">new_name</replaceable> ALTER SEQUENCE <replaceable class="parameter">name</replaceable> RENAME TO <replaceable class="parameter">new_name</replaceable>
ALTER SEQUENCE <replaceable class="parameter">name</replaceable> SET SCHEMA <replaceable class="parameter">new_schema</replaceable> ALTER SEQUENCE <replaceable class="parameter">name</replaceable> SET SCHEMA <replaceable class="parameter">new_schema</replaceable>
...@@ -112,12 +112,15 @@ ALTER SEQUENCE <replaceable class="parameter">name</replaceable> SET SCHEMA <rep ...@@ -112,12 +112,15 @@ ALTER SEQUENCE <replaceable class="parameter">name</replaceable> SET SCHEMA <rep
<term><replaceable class="parameter">start</replaceable></term> <term><replaceable class="parameter">start</replaceable></term>
<listitem> <listitem>
<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. This is equivalent to calling the current value of the sequence. This is equivalent to calling the
<function>setval</> function with <literal>is_called</literal> = <function>setval</> function with <literal>is_called</literal> =
<literal>false</>: the specified value will be returned by the <literal>false</>: the specified value will be returned by the
<emphasis>next</> call of <function>nextval</>. <emphasis>next</> call of <function>nextval</>.
Writing <literal>RESTART</> with no <replaceable
class="parameter">start</replaceable> value is equivalent to supplying
the start value used when the sequence was created.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
......
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/truncate.sgml,v 1.25 2008/03/28 00:21:55 tgl Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/truncate.sgml,v 1.26 2008/05/16 23:36:04 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -20,7 +20,8 @@ PostgreSQL documentation ...@@ -20,7 +20,8 @@ PostgreSQL documentation
<refsynopsisdiv> <refsynopsisdiv>
<synopsis> <synopsis>
TRUNCATE [ TABLE ] <replaceable class="PARAMETER">name</replaceable> [, ...] [ CASCADE | RESTRICT ] TRUNCATE [ TABLE ] <replaceable class="PARAMETER">name</replaceable> [, ... ]
[ RESTART IDENTITY | CONTINUE IDENTITY ] [ CASCADE | RESTRICT ]
</synopsis> </synopsis>
</refsynopsisdiv> </refsynopsisdiv>
...@@ -50,6 +51,25 @@ TRUNCATE [ TABLE ] <replaceable class="PARAMETER">name</replaceable> [, ...] [ C ...@@ -50,6 +51,25 @@ TRUNCATE [ TABLE ] <replaceable class="PARAMETER">name</replaceable> [, ...] [ C
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><literal>RESTART IDENTITY</literal></term>
<listitem>
<para>
Automatically restart sequences owned by columns of
the truncated table(s).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><literal>CONTINUE IDENTITY</literal></term>
<listitem>
<para>
Do not change the values of sequences. This is the default.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><literal>CASCADE</literal></term> <term><literal>CASCADE</literal></term>
<listitem> <listitem>
...@@ -66,7 +86,7 @@ TRUNCATE [ TABLE ] <replaceable class="PARAMETER">name</replaceable> [, ...] [ C ...@@ -66,7 +86,7 @@ TRUNCATE [ TABLE ] <replaceable class="PARAMETER">name</replaceable> [, ...] [ C
<listitem> <listitem>
<para> <para>
Refuse to truncate if any of the tables have foreign-key references Refuse to truncate if any of the tables have foreign-key references
from tables that are not to be truncated. This is the default. from tables that are not listed in the command. This is the default.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -119,11 +139,23 @@ TRUNCATE [ TABLE ] <replaceable class="PARAMETER">name</replaceable> [, ...] [ C ...@@ -119,11 +139,23 @@ TRUNCATE [ TABLE ] <replaceable class="PARAMETER">name</replaceable> [, ...] [ C
cause visible inconsistency between the contents of the truncated cause visible inconsistency between the contents of the truncated
table and other tables in the database. table and other tables in the database.
</para> </para>
</warning>
<para>
<command>TRUNCATE</> is transaction-safe with respect to the data
in the tables: the truncation will be safely rolled back if the surrounding
transaction does not commit.
</para>
<warning>
<para> <para>
<command>TRUNCATE</> is transaction-safe, however: the truncation Any <command>ALTER SEQUENCE RESTART</> operations performed as a
will be safely rolled back if the surrounding transaction does not consequence of using the <literal>RESTART IDENTITY</> option are
commit. nontransactional and will not be rolled back. To minimize risk,
these operations are performed only after all the rest of
<command>TRUNCATE</>'s work is done. In practice this will only
be an issue if <command>TRUNCATE</> is performed inside a
transaction block that is aborted afterwards.
</para> </para>
</warning> </warning>
</refsect1> </refsect1>
...@@ -132,13 +164,22 @@ TRUNCATE [ TABLE ] <replaceable class="PARAMETER">name</replaceable> [, ...] [ C ...@@ -132,13 +164,22 @@ TRUNCATE [ TABLE ] <replaceable class="PARAMETER">name</replaceable> [, ...] [ C
<title>Examples</title> <title>Examples</title>
<para> <para>
Truncate the tables <literal>bigtable</literal> and <literal>fattable</literal>: Truncate the tables <literal>bigtable</literal> and
<literal>fattable</literal>:
<programlisting> <programlisting>
TRUNCATE bigtable, fattable; TRUNCATE bigtable, fattable;
</programlisting> </programlisting>
</para> </para>
<para>
The same, and also reset any associated sequence generators:
<programlisting>
TRUNCATE bigtable, fattable RESTART IDENTITY;
</programlisting>
</para>
<para> <para>
Truncate the table <literal>othertable</literal>, and cascade to any tables Truncate the table <literal>othertable</literal>, and cascade to any tables
that reference <literal>othertable</literal> via foreign-key that reference <literal>othertable</literal> via foreign-key
...@@ -154,7 +195,10 @@ TRUNCATE othertable CASCADE; ...@@ -154,7 +195,10 @@ TRUNCATE othertable CASCADE;
<title>Compatibility</title> <title>Compatibility</title>
<para> <para>
There is no <command>TRUNCATE</command> command in the SQL standard. The draft SQL:2008 standard includes a <command>TRUNCATE</command> command,
but at this writing it is uncertain whether that will reach standardization
or be fully compatible with <productname>PostgreSQL</productname>'s
implementation.
</para> </para>
</refsect1> </refsect1>
</refentry> </refentry>
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/pg_depend.c,v 1.27 2008/03/26 21:10:37 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/catalog/pg_depend.c,v 1.28 2008/05/16 23:36:04 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -418,6 +418,58 @@ markSequenceUnowned(Oid seqId) ...@@ -418,6 +418,58 @@ markSequenceUnowned(Oid seqId)
heap_close(depRel, RowExclusiveLock); heap_close(depRel, RowExclusiveLock);
} }
/*
* Collect a list of OIDs of all sequences owned by the specified relation.
*/
List *
getOwnedSequences(Oid relid)
{
List *result = NIL;
Relation depRel;
ScanKeyData key[2];
SysScanDesc scan;
HeapTuple tup;
depRel = heap_open(DependRelationId, AccessShareLock);
ScanKeyInit(&key[0],
Anum_pg_depend_refclassid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(RelationRelationId));
ScanKeyInit(&key[1],
Anum_pg_depend_refobjid,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(relid));
scan = systable_beginscan(depRel, DependReferenceIndexId, true,
SnapshotNow, 2, key);
while (HeapTupleIsValid(tup = systable_getnext(scan)))
{
Form_pg_depend deprec = (Form_pg_depend) GETSTRUCT(tup);
/*
* We assume any auto dependency of a sequence on a column must be
* what we are looking for. (We need the relkind test because indexes
* can also have auto dependencies on columns.)
*/
if (deprec->classid == RelationRelationId &&
deprec->objsubid == 0 &&
deprec->refobjsubid != 0 &&
deprec->deptype == DEPENDENCY_AUTO &&
get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
{
result = lappend_oid(result, deprec->objid);
}
}
systable_endscan(scan);
heap_close(depRel, AccessShareLock);
return result;
}
/* /*
* get_constraint_index * get_constraint_index
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.150 2008/05/12 00:00:47 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.151 2008/05/16 23:36:04 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -91,7 +91,7 @@ static Relation open_share_lock(SeqTable seq); ...@@ -91,7 +91,7 @@ static Relation open_share_lock(SeqTable seq);
static void init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel); static void init_sequence(Oid relid, SeqTable *p_elm, Relation *p_rel);
static Form_pg_sequence read_info(SeqTable elm, Relation rel, Buffer *buf); static Form_pg_sequence read_info(SeqTable elm, Relation rel, Buffer *buf);
static void init_params(List *options, bool isInit, static void init_params(List *options, bool isInit,
Form_pg_sequence new, List **owned_by); Form_pg_sequence new, Form_pg_sequence old, List **owned_by);
static void do_setval(Oid relid, int64 next, bool iscalled); static void do_setval(Oid relid, int64 next, bool iscalled);
static void process_owned_by(Relation seqrel, List *owned_by); static void process_owned_by(Relation seqrel, List *owned_by);
...@@ -119,10 +119,10 @@ DefineSequence(CreateSeqStmt *seq) ...@@ -119,10 +119,10 @@ DefineSequence(CreateSeqStmt *seq)
NameData name; NameData name;
/* Check and set all option values */ /* Check and set all option values */
init_params(seq->options, true, &new, &owned_by); init_params(seq->options, true, &new, NULL, &owned_by);
/* /*
* Create relation (and fill *null & *value) * Create relation (and fill value[] and null[] for the tuple)
*/ */
stmt->tableElts = NIL; stmt->tableElts = NIL;
for (i = SEQ_COL_FIRSTCOL; i <= SEQ_COL_LASTCOL; i++) for (i = SEQ_COL_FIRSTCOL; i <= SEQ_COL_LASTCOL; i++)
...@@ -151,6 +151,11 @@ DefineSequence(CreateSeqStmt *seq) ...@@ -151,6 +151,11 @@ DefineSequence(CreateSeqStmt *seq)
coldef->colname = "last_value"; coldef->colname = "last_value";
value[i - 1] = Int64GetDatumFast(new.last_value); value[i - 1] = Int64GetDatumFast(new.last_value);
break; break;
case SEQ_COL_STARTVAL:
coldef->typename = makeTypeNameFromOid(INT8OID, -1);
coldef->colname = "start_value";
value[i - 1] = Int64GetDatumFast(new.start_value);
break;
case SEQ_COL_INCBY: case SEQ_COL_INCBY:
coldef->typename = makeTypeNameFromOid(INT8OID, -1); coldef->typename = makeTypeNameFromOid(INT8OID, -1);
coldef->colname = "increment_by"; coldef->colname = "increment_by";
...@@ -314,6 +319,29 @@ void ...@@ -314,6 +319,29 @@ void
AlterSequence(AlterSeqStmt *stmt) AlterSequence(AlterSeqStmt *stmt)
{ {
Oid relid; Oid relid;
/* find sequence */
relid = RangeVarGetRelid(stmt->sequence, false);
/* allow ALTER to sequence owner only */
/* if you change this, see also callers of AlterSequenceInternal! */
if (!pg_class_ownercheck(relid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
stmt->sequence->relname);
/* do the work */
AlterSequenceInternal(relid, stmt->options);
}
/*
* AlterSequenceInternal
*
* Same as AlterSequence except that the sequence is specified by OID
* and we assume the caller already checked permissions.
*/
void
AlterSequenceInternal(Oid relid, List *options)
{
SeqTable elm; SeqTable elm;
Relation seqrel; Relation seqrel;
Buffer buf; Buffer buf;
...@@ -323,23 +351,14 @@ AlterSequence(AlterSeqStmt *stmt) ...@@ -323,23 +351,14 @@ AlterSequence(AlterSeqStmt *stmt)
List *owned_by; List *owned_by;
/* open and AccessShareLock sequence */ /* open and AccessShareLock sequence */
relid = RangeVarGetRelid(stmt->sequence, false);
init_sequence(relid, &elm, &seqrel); init_sequence(relid, &elm, &seqrel);
/* allow ALTER to sequence owner only */
if (!pg_class_ownercheck(elm->relid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
stmt->sequence->relname);
/* lock page' buffer and read tuple into new sequence structure */ /* lock page' buffer and read tuple into new sequence structure */
seq = read_info(elm, seqrel, &buf); seq = read_info(elm, seqrel, &buf);
page = BufferGetPage(buf); page = BufferGetPage(buf);
/* Copy old values of options into workspace */ /* Fill workspace with appropriate new info */
memcpy(&new, seq, sizeof(FormData_pg_sequence)); init_params(options, false, &new, seq, &owned_by);
/* 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 */ /* Clear local cache so that we don't think we have cached numbers */
/* Note that we do not change the currval() state */ /* Note that we do not change the currval() state */
...@@ -970,7 +989,7 @@ read_info(SeqTable elm, Relation rel, Buffer *buf) ...@@ -970,7 +989,7 @@ read_info(SeqTable elm, Relation rel, Buffer *buf)
*/ */
static void static void
init_params(List *options, bool isInit, init_params(List *options, bool isInit,
Form_pg_sequence new, List **owned_by) Form_pg_sequence new, Form_pg_sequence old, List **owned_by)
{ {
DefElem *last_value = NULL; DefElem *last_value = NULL;
DefElem *increment_by = NULL; DefElem *increment_by = NULL;
...@@ -982,6 +1001,12 @@ init_params(List *options, bool isInit, ...@@ -982,6 +1001,12 @@ init_params(List *options, bool isInit,
*owned_by = NIL; *owned_by = NIL;
/* Copy old values of options into workspace */
if (old != NULL)
memcpy(new, old, sizeof(FormData_pg_sequence));
else
memset(new, 0, sizeof(FormData_pg_sequence));
foreach(option, options) foreach(option, options)
{ {
DefElem *defel = (DefElem *) lfirst(option); DefElem *defel = (DefElem *) lfirst(option);
...@@ -994,13 +1019,24 @@ init_params(List *options, bool isInit, ...@@ -994,13 +1019,24 @@ init_params(List *options, bool isInit,
errmsg("conflicting or redundant options"))); errmsg("conflicting or redundant options")));
increment_by = defel; increment_by = defel;
} }
else if (strcmp(defel->defname, "start") == 0)
/* {
* start is for a new sequence restart is for alter if (!isInit)
*/ ereport(ERROR,
else if (strcmp(defel->defname, "start") == 0 || (errcode(ERRCODE_SYNTAX_ERROR),
strcmp(defel->defname, "restart") == 0) errmsg("use RESTART not START in ALTER SEQUENCE")));
if (last_value)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting or redundant options")));
last_value = defel;
}
else if (strcmp(defel->defname, "restart") == 0)
{ {
if (isInit)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("use START not RESTART in CREATE SEQUENCE")));
if (last_value) if (last_value)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
...@@ -1109,24 +1145,59 @@ init_params(List *options, bool isInit, ...@@ -1109,24 +1145,59 @@ init_params(List *options, bool isInit,
bufm, bufx))); bufm, bufx)));
} }
/* START WITH */ /* START/RESTART [WITH] */
if (last_value != NULL) if (last_value != NULL)
{ {
new->last_value = defGetInt64(last_value); if (last_value->arg != NULL)
new->last_value = defGetInt64(last_value);
else
{
Assert(old != NULL);
new->last_value = old->start_value;
}
if (isInit)
new->start_value = new->last_value;
new->is_called = false; new->is_called = false;
new->log_cnt = 1; new->log_cnt = 1;
} }
else if (isInit) else if (isInit)
{ {
if (new->increment_by > 0) if (new->increment_by > 0)
new->last_value = new->min_value; /* ascending seq */ new->start_value = new->min_value; /* ascending seq */
else else
new->last_value = new->max_value; /* descending seq */ new->start_value = new->max_value; /* descending seq */
new->last_value = new->start_value;
new->is_called = false; new->is_called = false;
new->log_cnt = 1; new->log_cnt = 1;
} }
/* crosscheck */ /* crosscheck START */
if (new->start_value < new->min_value)
{
char bufs[100],
bufm[100];
snprintf(bufs, sizeof(bufs), INT64_FORMAT, new->start_value);
snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->min_value);
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("START value (%s) cannot be less than MINVALUE (%s)",
bufs, bufm)));
}
if (new->start_value > new->max_value)
{
char bufs[100],
bufm[100];
snprintf(bufs, sizeof(bufs), INT64_FORMAT, new->start_value);
snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->max_value);
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("START value (%s) cannot be greater than MAXVALUE (%s)",
bufs, bufm)));
}
/* must crosscheck RESTART separately */
if (new->last_value < new->min_value) if (new->last_value < new->min_value)
{ {
char bufs[100], char bufs[100],
...@@ -1136,7 +1207,7 @@ init_params(List *options, bool isInit, ...@@ -1136,7 +1207,7 @@ init_params(List *options, bool isInit,
snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->min_value); snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->min_value);
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("START value (%s) cannot be less than MINVALUE (%s)", errmsg("RESTART value (%s) cannot be less than MINVALUE (%s)",
bufs, bufm))); bufs, bufm)));
} }
if (new->last_value > new->max_value) if (new->last_value > new->max_value)
...@@ -1148,7 +1219,7 @@ init_params(List *options, bool isInit, ...@@ -1148,7 +1219,7 @@ init_params(List *options, bool isInit,
snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->max_value); snprintf(bufm, sizeof(bufm), INT64_FORMAT, new->max_value);
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("START value (%s) cannot be greater than MAXVALUE (%s)", errmsg("RESTART value (%s) cannot be greater than MAXVALUE (%s)",
bufs, bufm))); bufs, bufm)));
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.253 2008/05/12 00:00:48 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.254 2008/05/16 23:36:04 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
#include "catalog/toasting.h" #include "catalog/toasting.h"
#include "commands/cluster.h" #include "commands/cluster.h"
#include "commands/defrem.h" #include "commands/defrem.h"
#include "commands/sequence.h"
#include "commands/tablecmds.h" #include "commands/tablecmds.h"
#include "commands/tablespace.h" #include "commands/tablespace.h"
#include "commands/trigger.h" #include "commands/trigger.h"
...@@ -531,6 +532,7 @@ ExecuteTruncate(TruncateStmt *stmt) ...@@ -531,6 +532,7 @@ ExecuteTruncate(TruncateStmt *stmt)
{ {
List *rels = NIL; List *rels = NIL;
List *relids = NIL; List *relids = NIL;
List *seq_relids = NIL;
EState *estate; EState *estate;
ResultRelInfo *resultRelInfos; ResultRelInfo *resultRelInfos;
ResultRelInfo *resultRelInfo; ResultRelInfo *resultRelInfo;
...@@ -596,6 +598,40 @@ ExecuteTruncate(TruncateStmt *stmt) ...@@ -596,6 +598,40 @@ ExecuteTruncate(TruncateStmt *stmt)
heap_truncate_check_FKs(rels, false); heap_truncate_check_FKs(rels, false);
#endif #endif
/*
* If we are asked to restart sequences, find all the sequences,
* lock them (we only need AccessShareLock because that's all that
* ALTER SEQUENCE takes), and check permissions. We want to do this
* early since it's pointless to do all the truncation work only to fail
* on sequence permissions.
*/
if (stmt->restart_seqs)
{
foreach(cell, rels)
{
Relation rel = (Relation) lfirst(cell);
List *seqlist = getOwnedSequences(RelationGetRelid(rel));
ListCell *seqcell;
foreach(seqcell, seqlist)
{
Oid seq_relid = lfirst_oid(seqcell);
Relation seq_rel;
seq_rel = relation_open(seq_relid, AccessShareLock);
/* This check must match AlterSequence! */
if (!pg_class_ownercheck(seq_relid, GetUserId()))
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
RelationGetRelationName(seq_rel));
seq_relids = lappend_oid(seq_relids, seq_relid);
relation_close(seq_rel, NoLock);
}
}
}
/* Prepare to catch AFTER triggers. */ /* Prepare to catch AFTER triggers. */
AfterTriggerBeginQuery(); AfterTriggerBeginQuery();
...@@ -694,6 +730,25 @@ ExecuteTruncate(TruncateStmt *stmt) ...@@ -694,6 +730,25 @@ ExecuteTruncate(TruncateStmt *stmt)
heap_close(rel, NoLock); heap_close(rel, NoLock);
} }
/*
* Lastly, restart any owned sequences if we were asked to. This is done
* last because it's nontransactional: restarts will not roll back if
* we abort later. Hence it's important to postpone them as long as
* possible. (This is also a big reason why we locked and
* permission-checked the sequences beforehand.)
*/
if (stmt->restart_seqs)
{
List *options = list_make1(makeDefElem("restart", NULL));
foreach(cell, seq_relids)
{
Oid seq_relid = lfirst_oid(cell);
AlterSequenceInternal(seq_relid, options);
}
}
} }
/* /*
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.393 2008/04/29 14:59:16 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.394 2008/05/16 23:36:05 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -2156,6 +2156,7 @@ _copyTruncateStmt(TruncateStmt *from) ...@@ -2156,6 +2156,7 @@ _copyTruncateStmt(TruncateStmt *from)
TruncateStmt *newnode = makeNode(TruncateStmt); TruncateStmt *newnode = makeNode(TruncateStmt);
COPY_NODE_FIELD(relations); COPY_NODE_FIELD(relations);
COPY_SCALAR_FIELD(restart_seqs);
COPY_SCALAR_FIELD(behavior); COPY_SCALAR_FIELD(behavior);
return newnode; return newnode;
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.322 2008/04/29 14:59:16 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.323 2008/05/16 23:36:05 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1010,6 +1010,7 @@ static bool ...@@ -1010,6 +1010,7 @@ static bool
_equalTruncateStmt(TruncateStmt *a, TruncateStmt *b) _equalTruncateStmt(TruncateStmt *a, TruncateStmt *b)
{ {
COMPARE_NODE_FIELD(relations); COMPARE_NODE_FIELD(relations);
COMPARE_SCALAR_FIELD(restart_seqs);
COMPARE_SCALAR_FIELD(behavior); COMPARE_SCALAR_FIELD(behavior);
return true; return true;
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.614 2008/04/29 20:44:49 tgl Exp $ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.615 2008/05/16 23:36:05 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -206,7 +206,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args) ...@@ -206,7 +206,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
%type <str> OptSchemaName %type <str> OptSchemaName
%type <list> OptSchemaEltList %type <list> OptSchemaEltList
%type <boolean> TriggerActionTime TriggerForSpec opt_trusted %type <boolean> TriggerActionTime TriggerForSpec opt_trusted opt_restart_seqs
%type <str> opt_lancompiler %type <str> opt_lancompiler
%type <str> TriggerEvents %type <str> TriggerEvents
...@@ -381,7 +381,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args) ...@@ -381,7 +381,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT CLUSTER COALESCE COLLATE COLUMN COMMENT COMMIT
COMMITTED CONCURRENTLY CONFIGURATION CONNECTION CONSTRAINT CONSTRAINTS COMMITTED CONCURRENTLY CONFIGURATION CONNECTION CONSTRAINT CONSTRAINTS
CONTENT_P CONVERSION_P COPY COST CREATE CREATEDB CONTENT_P CONTINUE_P CONVERSION_P COPY COST CREATE CREATEDB
CREATEROLE CREATEUSER CROSS CSV CURRENT_P CURRENT_DATE CURRENT_ROLE CREATEROLE CREATEUSER CROSS CSV CURRENT_P CURRENT_DATE CURRENT_ROLE
CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE CURRENT_TIME CURRENT_TIMESTAMP CURRENT_USER CURSOR CYCLE
...@@ -399,10 +399,10 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args) ...@@ -399,10 +399,10 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
HANDLER HAVING HEADER_P HOLD HOUR_P HANDLER HAVING HEADER_P HOLD HOUR_P
IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P INCLUDING INCREMENT IDENTITY_P IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P
INDEX INDEXES INHERIT INHERITS INITIALLY INNER_P INOUT INPUT_P INCLUDING INCREMENT INDEX INDEXES INHERIT INHERITS INITIALLY
INSENSITIVE INSERT INSTEAD INT_P INTEGER INTERSECT INNER_P INOUT INPUT_P INSENSITIVE INSERT INSTEAD INT_P INTEGER
INTERVAL INTO INVOKER IS ISNULL ISOLATION INTERSECT INTERVAL INTO INVOKER IS ISNULL ISOLATION
JOIN JOIN
...@@ -2489,6 +2489,10 @@ OptSeqElem: CACHE NumericOnly ...@@ -2489,6 +2489,10 @@ OptSeqElem: CACHE NumericOnly
{ {
$$ = makeDefElem("start", (Node *)$3); $$ = makeDefElem("start", (Node *)$3);
} }
| RESTART
{
$$ = makeDefElem("restart", NULL);
}
| RESTART opt_with NumericOnly | RESTART opt_with NumericOnly
{ {
$$ = makeDefElem("restart", (Node *)$3); $$ = makeDefElem("restart", (Node *)$3);
...@@ -3364,15 +3368,22 @@ attrs: '.' attr_name ...@@ -3364,15 +3368,22 @@ attrs: '.' attr_name
*****************************************************************************/ *****************************************************************************/
TruncateStmt: TruncateStmt:
TRUNCATE opt_table qualified_name_list opt_drop_behavior TRUNCATE opt_table qualified_name_list opt_restart_seqs opt_drop_behavior
{ {
TruncateStmt *n = makeNode(TruncateStmt); TruncateStmt *n = makeNode(TruncateStmt);
n->relations = $3; n->relations = $3;
n->behavior = $4; n->restart_seqs = $4;
n->behavior = $5;
$$ = (Node *)n; $$ = (Node *)n;
} }
; ;
opt_restart_seqs:
CONTINUE_P IDENTITY_P { $$ = false; }
| RESTART IDENTITY_P { $$ = true; }
| /* EMPTY */ { $$ = false; }
;
/***************************************************************************** /*****************************************************************************
* *
* The COMMENT ON statement can take different forms based upon the type of * The COMMENT ON statement can take different forms based upon the type of
...@@ -8964,6 +8975,7 @@ unreserved_keyword: ...@@ -8964,6 +8975,7 @@ unreserved_keyword:
| CONNECTION | CONNECTION
| CONSTRAINTS | CONSTRAINTS
| CONTENT_P | CONTENT_P
| CONTINUE_P
| CONVERSION_P | CONVERSION_P
| COPY | COPY
| COST | COST
...@@ -9014,6 +9026,7 @@ unreserved_keyword: ...@@ -9014,6 +9026,7 @@ unreserved_keyword:
| HEADER_P | HEADER_P
| HOLD | HOLD
| HOUR_P | HOUR_P
| IDENTITY_P
| IF_P | IF_P
| IMMEDIATE | IMMEDIATE
| IMMUTABLE | IMMUTABLE
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.195 2008/03/27 03:57:33 tgl Exp $ * $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.196 2008/05/16 23:36:05 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -101,6 +101,7 @@ static const ScanKeyword ScanKeywords[] = { ...@@ -101,6 +101,7 @@ static const ScanKeyword ScanKeywords[] = {
{"constraint", CONSTRAINT, RESERVED_KEYWORD}, {"constraint", CONSTRAINT, RESERVED_KEYWORD},
{"constraints", CONSTRAINTS, UNRESERVED_KEYWORD}, {"constraints", CONSTRAINTS, UNRESERVED_KEYWORD},
{"content", CONTENT_P, UNRESERVED_KEYWORD}, {"content", CONTENT_P, UNRESERVED_KEYWORD},
{"continue", CONTINUE_P, UNRESERVED_KEYWORD},
{"conversion", CONVERSION_P, UNRESERVED_KEYWORD}, {"conversion", CONVERSION_P, UNRESERVED_KEYWORD},
{"copy", COPY, UNRESERVED_KEYWORD}, {"copy", COPY, UNRESERVED_KEYWORD},
{"cost", COST, UNRESERVED_KEYWORD}, {"cost", COST, UNRESERVED_KEYWORD},
...@@ -181,6 +182,7 @@ static const ScanKeyword ScanKeywords[] = { ...@@ -181,6 +182,7 @@ static const ScanKeyword ScanKeywords[] = {
{"header", HEADER_P, UNRESERVED_KEYWORD}, {"header", HEADER_P, UNRESERVED_KEYWORD},
{"hold", HOLD, UNRESERVED_KEYWORD}, {"hold", HOLD, UNRESERVED_KEYWORD},
{"hour", HOUR_P, UNRESERVED_KEYWORD}, {"hour", HOUR_P, UNRESERVED_KEYWORD},
{"identity", IDENTITY_P, UNRESERVED_KEYWORD},
{"if", IF_P, UNRESERVED_KEYWORD}, {"if", IF_P, UNRESERVED_KEYWORD},
{"ilike", ILIKE, TYPE_FUNC_NAME_KEYWORD}, {"ilike", ILIKE, TYPE_FUNC_NAME_KEYWORD},
{"immediate", IMMEDIATE, UNRESERVED_KEYWORD}, {"immediate", IMMEDIATE, UNRESERVED_KEYWORD},
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* by PostgreSQL * by PostgreSQL
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.491 2008/05/12 00:00:53 alvherre Exp $ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.492 2008/05/16 23:36:05 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -9525,7 +9525,8 @@ static void ...@@ -9525,7 +9525,8 @@ static void
dumpSequence(Archive *fout, TableInfo *tbinfo) dumpSequence(Archive *fout, TableInfo *tbinfo)
{ {
PGresult *res; PGresult *res;
char *last, char *startv,
*last,
*incby, *incby,
*maxv = NULL, *maxv = NULL,
*minv = NULL, *minv = NULL,
...@@ -9543,19 +9544,40 @@ dumpSequence(Archive *fout, TableInfo *tbinfo) ...@@ -9543,19 +9544,40 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE); snprintf(bufm, sizeof(bufm), INT64_FORMAT, SEQ_MINVALUE);
snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE); snprintf(bufx, sizeof(bufx), INT64_FORMAT, SEQ_MAXVALUE);
appendPQExpBuffer(query, if (g_fout->remoteVersion >= 80400)
"SELECT sequence_name, last_value, increment_by, " {
"CASE WHEN increment_by > 0 AND max_value = %s THEN NULL " appendPQExpBuffer(query,
" WHEN increment_by < 0 AND max_value = -1 THEN NULL " "SELECT sequence_name, "
" ELSE max_value " "start_value, last_value, increment_by, "
"END AS max_value, " "CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
"CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL " " WHEN increment_by < 0 AND max_value = -1 THEN NULL "
" WHEN increment_by < 0 AND min_value = %s THEN NULL " " ELSE max_value "
" ELSE min_value " "END AS max_value, "
"END AS min_value, " "CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
"cache_value, is_cycled, is_called from %s", " WHEN increment_by < 0 AND min_value = %s THEN NULL "
bufx, bufm, " ELSE min_value "
fmtId(tbinfo->dobj.name)); "END AS min_value, "
"cache_value, is_cycled, is_called from %s",
bufx, bufm,
fmtId(tbinfo->dobj.name));
}
else
{
appendPQExpBuffer(query,
"SELECT sequence_name, "
"0 as start_value, last_value, increment_by, "
"CASE WHEN increment_by > 0 AND max_value = %s THEN NULL "
" WHEN increment_by < 0 AND max_value = -1 THEN NULL "
" ELSE max_value "
"END AS max_value, "
"CASE WHEN increment_by > 0 AND min_value = 1 THEN NULL "
" WHEN increment_by < 0 AND min_value = %s THEN NULL "
" ELSE min_value "
"END AS min_value, "
"cache_value, is_cycled, is_called from %s",
bufx, bufm,
fmtId(tbinfo->dobj.name));
}
res = PQexec(g_conn, query->data); res = PQexec(g_conn, query->data);
check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK); check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
...@@ -9577,15 +9599,16 @@ dumpSequence(Archive *fout, TableInfo *tbinfo) ...@@ -9577,15 +9599,16 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
} }
#endif #endif
last = PQgetvalue(res, 0, 1); startv = PQgetvalue(res, 0, 1);
incby = PQgetvalue(res, 0, 2); last = PQgetvalue(res, 0, 2);
if (!PQgetisnull(res, 0, 3)) incby = PQgetvalue(res, 0, 3);
maxv = PQgetvalue(res, 0, 3);
if (!PQgetisnull(res, 0, 4)) if (!PQgetisnull(res, 0, 4))
minv = PQgetvalue(res, 0, 4); maxv = PQgetvalue(res, 0, 4);
cache = PQgetvalue(res, 0, 5); if (!PQgetisnull(res, 0, 5))
cycled = (strcmp(PQgetvalue(res, 0, 6), "t") == 0); minv = PQgetvalue(res, 0, 5);
called = (strcmp(PQgetvalue(res, 0, 7), "t") == 0); cache = PQgetvalue(res, 0, 6);
cycled = (strcmp(PQgetvalue(res, 0, 7), "t") == 0);
called = (strcmp(PQgetvalue(res, 0, 8), "t") == 0);
/* /*
* The logic we use for restoring sequences is as follows: * The logic we use for restoring sequences is as follows:
...@@ -9615,8 +9638,18 @@ dumpSequence(Archive *fout, TableInfo *tbinfo) ...@@ -9615,8 +9638,18 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
"CREATE SEQUENCE %s\n", "CREATE SEQUENCE %s\n",
fmtId(tbinfo->dobj.name)); fmtId(tbinfo->dobj.name));
if (!called) if (g_fout->remoteVersion >= 80400)
appendPQExpBuffer(query, " START WITH %s\n", last); appendPQExpBuffer(query, " START WITH %s\n", startv);
else
{
/*
* Versions before 8.4 did not remember the true start value. If
* is_called is false then the sequence has never been incremented
* so we can use last_val. Otherwise punt and let it default.
*/
if (!called)
appendPQExpBuffer(query, " START WITH %s\n", last);
}
appendPQExpBuffer(query, " INCREMENT BY %s\n", incby); appendPQExpBuffer(query, " INCREMENT BY %s\n", incby);
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.460 2008/05/16 16:31:01 tgl Exp $ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.461 2008/05/16 23:36:05 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200805161 #define CATALOG_VERSION_NO 200805162
#endif #endif
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.34 2008/03/24 19:47:35 tgl Exp $ * $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.35 2008/05/16 23:36:05 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -207,6 +207,8 @@ extern bool sequenceIsOwned(Oid seqId, Oid *tableId, int32 *colId); ...@@ -207,6 +207,8 @@ extern bool sequenceIsOwned(Oid seqId, Oid *tableId, int32 *colId);
extern void markSequenceUnowned(Oid seqId); extern void markSequenceUnowned(Oid seqId);
extern List *getOwnedSequences(Oid relid);
extern Oid get_constraint_index(Oid constraintId); extern Oid get_constraint_index(Oid constraintId);
extern Oid get_index_constraint(Oid indexId); extern Oid get_index_constraint(Oid indexId);
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/commands/sequence.h,v 1.40 2008/03/27 03:57:34 tgl Exp $ * $PostgreSQL: pgsql/src/include/commands/sequence.h,v 1.41 2008/05/16 23:36:05 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -30,6 +30,7 @@ typedef struct FormData_pg_sequence ...@@ -30,6 +30,7 @@ typedef struct FormData_pg_sequence
NameData sequence_name; NameData sequence_name;
#ifndef INT64_IS_BUSTED #ifndef INT64_IS_BUSTED
int64 last_value; int64 last_value;
int64 start_value;
int64 increment_by; int64 increment_by;
int64 max_value; int64 max_value;
int64 min_value; int64 min_value;
...@@ -38,16 +39,18 @@ typedef struct FormData_pg_sequence ...@@ -38,16 +39,18 @@ typedef struct FormData_pg_sequence
#else #else
int32 last_value; int32 last_value;
int32 pad1; int32 pad1;
int32 increment_by; int32 start_value;
int32 pad2; int32 pad2;
int32 max_value; int32 increment_by;
int32 pad3; int32 pad3;
int32 min_value; int32 max_value;
int32 pad4; int32 pad4;
int32 cache_value; int32 min_value;
int32 pad5; int32 pad5;
int32 log_cnt; int32 cache_value;
int32 pad6; int32 pad6;
int32 log_cnt;
int32 pad7;
#endif #endif
bool is_cycled; bool is_cycled;
bool is_called; bool is_called;
...@@ -61,13 +64,14 @@ typedef FormData_pg_sequence *Form_pg_sequence; ...@@ -61,13 +64,14 @@ typedef FormData_pg_sequence *Form_pg_sequence;
#define SEQ_COL_NAME 1 #define SEQ_COL_NAME 1
#define SEQ_COL_LASTVAL 2 #define SEQ_COL_LASTVAL 2
#define SEQ_COL_INCBY 3 #define SEQ_COL_STARTVAL 3
#define SEQ_COL_MAXVALUE 4 #define SEQ_COL_INCBY 4
#define SEQ_COL_MINVALUE 5 #define SEQ_COL_MAXVALUE 5
#define SEQ_COL_CACHE 6 #define SEQ_COL_MINVALUE 6
#define SEQ_COL_LOG 7 #define SEQ_COL_CACHE 7
#define SEQ_COL_CYCLE 8 #define SEQ_COL_LOG 8
#define SEQ_COL_CALLED 9 #define SEQ_COL_CYCLE 9
#define SEQ_COL_CALLED 10
#define SEQ_COL_FIRSTCOL SEQ_COL_NAME #define SEQ_COL_FIRSTCOL SEQ_COL_NAME
#define SEQ_COL_LASTCOL SEQ_COL_CALLED #define SEQ_COL_LASTCOL SEQ_COL_CALLED
...@@ -90,6 +94,7 @@ extern Datum lastval(PG_FUNCTION_ARGS); ...@@ -90,6 +94,7 @@ extern Datum lastval(PG_FUNCTION_ARGS);
extern void DefineSequence(CreateSeqStmt *stmt); extern void DefineSequence(CreateSeqStmt *stmt);
extern void AlterSequence(AlterSeqStmt *stmt); extern void AlterSequence(AlterSeqStmt *stmt);
extern void AlterSequenceInternal(Oid relid, List *options);
extern void seq_redo(XLogRecPtr lsn, XLogRecord *rptr); extern void seq_redo(XLogRecPtr lsn, XLogRecord *rptr);
extern void seq_desc(StringInfo buf, uint8 xl_info, char *rec); extern void seq_desc(StringInfo buf, uint8 xl_info, char *rec);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.365 2008/05/09 23:32:04 tgl Exp $ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.366 2008/05/16 23:36:05 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1452,6 +1452,7 @@ typedef struct TruncateStmt ...@@ -1452,6 +1452,7 @@ typedef struct TruncateStmt
{ {
NodeTag type; NodeTag type;
List *relations; /* relations (RangeVars) to be truncated */ List *relations; /* relations (RangeVars) to be truncated */
bool restart_seqs; /* restart owned sequences? */
DropBehavior behavior; /* RESTRICT or CASCADE behavior */ DropBehavior behavior; /* RESTRICT or CASCADE behavior */
} TruncateStmt; } TruncateStmt;
......
...@@ -99,9 +99,27 @@ DROP SEQUENCE sequence_test; ...@@ -99,9 +99,27 @@ DROP SEQUENCE sequence_test;
CREATE SEQUENCE foo_seq; CREATE SEQUENCE foo_seq;
ALTER TABLE foo_seq RENAME TO foo_seq_new; ALTER TABLE foo_seq RENAME TO foo_seq_new;
SELECT * FROM foo_seq_new; SELECT * FROM foo_seq_new;
sequence_name | last_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called
---------------+------------+--------------+---------------------+-----------+-------------+---------+-----------+----------- ---------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+-----------
foo_seq | 1 | 1 | 9223372036854775807 | 1 | 1 | 1 | f | f foo_seq | 1 | 1 | 1 | 9223372036854775807 | 1 | 1 | 1 | f | f
(1 row)
SELECT nextval('foo_seq_new');
nextval
---------
1
(1 row)
SELECT nextval('foo_seq_new');
nextval
---------
2
(1 row)
SELECT * FROM foo_seq_new;
sequence_name | last_value | start_value | increment_by | max_value | min_value | cache_value | log_cnt | is_cycled | is_called
---------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+-----------
foo_seq | 2 | 1 | 1 | 9223372036854775807 | 1 | 1 | 32 | f | t
(1 row) (1 row)
DROP SEQUENCE foo_seq_new; DROP SEQUENCE foo_seq_new;
...@@ -155,18 +173,49 @@ SELECT nextval('sequence_test2'); ...@@ -155,18 +173,49 @@ SELECT nextval('sequence_test2');
32 32
(1 row) (1 row)
ALTER SEQUENCE sequence_test2 RESTART WITH 16 ALTER SEQUENCE sequence_test2 RESTART WITH 24
INCREMENT BY 4 MAXVALUE 22 MINVALUE 5 CYCLE; INCREMENT BY 4 MAXVALUE 36 MINVALUE 5 CYCLE;
SELECT nextval('sequence_test2');
nextval
---------
24
(1 row)
SELECT nextval('sequence_test2'); SELECT nextval('sequence_test2');
nextval nextval
--------- ---------
16 28
(1 row)
SELECT nextval('sequence_test2');
nextval
---------
32
(1 row)
SELECT nextval('sequence_test2');
nextval
---------
36
(1 row)
SELECT nextval('sequence_test2');
nextval
---------
5
(1 row)
ALTER SEQUENCE sequence_test2 RESTART;
SELECT nextval('sequence_test2');
nextval
---------
32
(1 row) (1 row)
SELECT nextval('sequence_test2'); SELECT nextval('sequence_test2');
nextval nextval
--------- ---------
20 36
(1 row) (1 row)
SELECT nextval('sequence_test2'); SELECT nextval('sequence_test2');
......
...@@ -223,3 +223,41 @@ SELECT * FROM trunc_trigger_log; ...@@ -223,3 +223,41 @@ SELECT * FROM trunc_trigger_log;
DROP TABLE trunc_trigger_test; DROP TABLE trunc_trigger_test;
DROP TABLE trunc_trigger_log; DROP TABLE trunc_trigger_log;
DROP FUNCTION trunctrigger(); DROP FUNCTION trunctrigger();
-- test TRUNCATE ... RESTART IDENTITY
CREATE SEQUENCE truncate_a_id1 START WITH 33;
CREATE TABLE truncate_a (id serial,
id1 integer default nextval('truncate_a_id1'));
NOTICE: CREATE TABLE will create implicit sequence "truncate_a_id_seq" for serial column "truncate_a.id"
ALTER SEQUENCE truncate_a_id1 OWNED BY truncate_a.id1;
INSERT INTO truncate_a DEFAULT VALUES;
INSERT INTO truncate_a DEFAULT VALUES;
SELECT * FROM truncate_a;
id | id1
----+-----
1 | 33
2 | 34
(2 rows)
TRUNCATE truncate_a;
INSERT INTO truncate_a DEFAULT VALUES;
INSERT INTO truncate_a DEFAULT VALUES;
SELECT * FROM truncate_a;
id | id1
----+-----
3 | 35
4 | 36
(2 rows)
TRUNCATE truncate_a RESTART IDENTITY;
INSERT INTO truncate_a DEFAULT VALUES;
INSERT INTO truncate_a DEFAULT VALUES;
SELECT * FROM truncate_a;
id | id1
----+-----
1 | 33
2 | 34
(2 rows)
DROP TABLE truncate_a;
SELECT nextval('truncate_a_id1'); -- fail, seq should have been dropped
ERROR: relation "truncate_a_id1" does not exist
...@@ -33,6 +33,9 @@ DROP SEQUENCE sequence_test; ...@@ -33,6 +33,9 @@ DROP SEQUENCE sequence_test;
CREATE SEQUENCE foo_seq; CREATE SEQUENCE foo_seq;
ALTER TABLE foo_seq RENAME TO foo_seq_new; ALTER TABLE foo_seq RENAME TO foo_seq_new;
SELECT * FROM foo_seq_new; SELECT * FROM foo_seq_new;
SELECT nextval('foo_seq_new');
SELECT nextval('foo_seq_new');
SELECT * FROM foo_seq_new;
DROP SEQUENCE foo_seq_new; DROP SEQUENCE foo_seq_new;
-- renaming serial sequences -- renaming serial sequences
...@@ -68,8 +71,16 @@ CREATE SEQUENCE sequence_test2 START WITH 32; ...@@ -68,8 +71,16 @@ CREATE SEQUENCE sequence_test2 START WITH 32;
SELECT nextval('sequence_test2'); SELECT nextval('sequence_test2');
ALTER SEQUENCE sequence_test2 RESTART WITH 16 ALTER SEQUENCE sequence_test2 RESTART WITH 24
INCREMENT BY 4 MAXVALUE 22 MINVALUE 5 CYCLE; INCREMENT BY 4 MAXVALUE 36 MINVALUE 5 CYCLE;
SELECT nextval('sequence_test2');
SELECT nextval('sequence_test2');
SELECT nextval('sequence_test2');
SELECT nextval('sequence_test2');
SELECT nextval('sequence_test2');
ALTER SEQUENCE sequence_test2 RESTART;
SELECT nextval('sequence_test2'); SELECT nextval('sequence_test2');
SELECT nextval('sequence_test2'); SELECT nextval('sequence_test2');
SELECT nextval('sequence_test2'); SELECT nextval('sequence_test2');
......
...@@ -130,3 +130,29 @@ DROP TABLE trunc_trigger_test; ...@@ -130,3 +130,29 @@ DROP TABLE trunc_trigger_test;
DROP TABLE trunc_trigger_log; DROP TABLE trunc_trigger_log;
DROP FUNCTION trunctrigger(); DROP FUNCTION trunctrigger();
-- test TRUNCATE ... RESTART IDENTITY
CREATE SEQUENCE truncate_a_id1 START WITH 33;
CREATE TABLE truncate_a (id serial,
id1 integer default nextval('truncate_a_id1'));
ALTER SEQUENCE truncate_a_id1 OWNED BY truncate_a.id1;
INSERT INTO truncate_a DEFAULT VALUES;
INSERT INTO truncate_a DEFAULT VALUES;
SELECT * FROM truncate_a;
TRUNCATE truncate_a;
INSERT INTO truncate_a DEFAULT VALUES;
INSERT INTO truncate_a DEFAULT VALUES;
SELECT * FROM truncate_a;
TRUNCATE truncate_a RESTART IDENTITY;
INSERT INTO truncate_a DEFAULT VALUES;
INSERT INTO truncate_a DEFAULT VALUES;
SELECT * FROM truncate_a;
DROP TABLE truncate_a;
SELECT nextval('truncate_a_id1'); -- fail, seq should have been dropped
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment