Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 1978172

Browse files
committed
Make identity sequence management more robust
Some code could get confused when certain catalog state involving both identity and serial sequences was present, perhaps during an attempt to upgrade the latter to the former. Specifically, dropping the default of a serial column maintains the ownership of the sequence by the column, and so it would then be possible to afterwards make the column an identity column that would now own two sequences. This causes the code that looks up the identity sequence to error out, making the new identity column inoperable until the ownership of the previous sequence is released. To fix this, make the identity sequence lookup only consider sequences with the appropriate dependency type for an identity sequence, so it only ever finds one (unless something else is broken). In the above example, the old serial sequence would then be ignored. Reorganize the various owned-sequence-lookup functions a bit to make this clearer. Reported-by: Laurenz Albe <laurenz.albe@cybertec.at> Discussion: https://www.postgresql.org/message-id/flat/470c54fc8590be4de0f41b0d295fd6390d5e8a6c.camel@cybertec.at
1 parent efdcca5 commit 1978172

File tree

7 files changed

+48
-20
lines changed

7 files changed

+48
-20
lines changed

src/backend/catalog/pg_depend.c

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -705,10 +705,11 @@ sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId)
705705

706706
/*
707707
* Collect a list of OIDs of all sequences owned by the specified relation,
708-
* and column if specified.
708+
* and column if specified. If deptype is not zero, then only find sequences
709+
* with the specified dependency type.
709710
*/
710-
List *
711-
getOwnedSequences(Oid relid, AttrNumber attnum)
711+
static List *
712+
getOwnedSequences_internal(Oid relid, AttrNumber attnum, char deptype)
712713
{
713714
List *result = NIL;
714715
Relation depRel;
@@ -750,7 +751,8 @@ getOwnedSequences(Oid relid, AttrNumber attnum)
750751
(deprec->deptype == DEPENDENCY_AUTO || deprec->deptype == DEPENDENCY_INTERNAL) &&
751752
get_rel_relkind(deprec->objid) == RELKIND_SEQUENCE)
752753
{
753-
result = lappend_oid(result, deprec->objid);
754+
if (!deptype || deprec->deptype == deptype)
755+
result = lappend_oid(result, deprec->objid);
754756
}
755757
}
756758

@@ -762,17 +764,32 @@ getOwnedSequences(Oid relid, AttrNumber attnum)
762764
}
763765

764766
/*
765-
* Get owned sequence, error if not exactly one.
767+
* Collect a list of OIDs of all sequences owned (identity or serial) by the
768+
* specified relation.
769+
*/
770+
List *
771+
getOwnedSequences(Oid relid)
772+
{
773+
return getOwnedSequences_internal(relid, 0, 0);
774+
}
775+
776+
/*
777+
* Get owned identity sequence, error if not exactly one.
766778
*/
767779
Oid
768-
getOwnedSequence(Oid relid, AttrNumber attnum)
780+
getIdentitySequence(Oid relid, AttrNumber attnum, bool missing_ok)
769781
{
770-
List *seqlist = getOwnedSequences(relid, attnum);
782+
List *seqlist = getOwnedSequences_internal(relid, attnum, DEPENDENCY_INTERNAL);
771783

772784
if (list_length(seqlist) > 1)
773785
elog(ERROR, "more than one owned sequence found");
774786
else if (list_length(seqlist) < 1)
775-
elog(ERROR, "no owned sequence found");
787+
{
788+
if (missing_ok)
789+
return InvalidOid;
790+
else
791+
elog(ERROR, "no owned sequence found");
792+
}
776793

777794
return linitial_oid(seqlist);
778795
}

src/backend/commands/tablecmds.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1689,7 +1689,7 @@ ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged,
16891689
foreach(cell, rels)
16901690
{
16911691
Relation rel = (Relation) lfirst(cell);
1692-
List *seqlist = getOwnedSequences(RelationGetRelid(rel), 0);
1692+
List *seqlist = getOwnedSequences(RelationGetRelid(rel));
16931693
ListCell *seqcell;
16941694

16951695
foreach(seqcell, seqlist)
@@ -6635,7 +6635,7 @@ ATExecDropIdentity(Relation rel, const char *colName, bool missing_ok, LOCKMODE
66356635
table_close(attrelation, RowExclusiveLock);
66366636

66376637
/* drop the internal sequence */
6638-
seqid = getOwnedSequence(RelationGetRelid(rel), attnum);
6638+
seqid = getIdentitySequence(RelationGetRelid(rel), attnum, false);
66396639
deleteDependencyRecordsForClass(RelationRelationId, seqid,
66406640
RelationRelationId, DEPENDENCY_INTERNAL);
66416641
CommandCounterIncrement();

src/backend/parser/parse_utilcmd.c

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,7 +1083,7 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
10831083
* find sequence owned by old column; extract sequence parameters;
10841084
* build new create sequence command
10851085
*/
1086-
seq_relid = getOwnedSequence(RelationGetRelid(relation), attribute->attnum);
1086+
seq_relid = getIdentitySequence(RelationGetRelid(relation), attribute->attnum, false);
10871087
seq_options = sequence_options(seq_relid);
10881088
generateSerialExtraStmts(cxt, def,
10891089
InvalidOid, seq_options, true,
@@ -3165,7 +3165,7 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
31653165
if (attnum != InvalidAttrNumber &&
31663166
TupleDescAttr(tupdesc, attnum - 1)->attidentity)
31673167
{
3168-
Oid seq_relid = getOwnedSequence(relid, attnum);
3168+
Oid seq_relid = getIdentitySequence(relid, attnum, false);
31693169
Oid typeOid = typenameTypeId(pstate, def->typeName);
31703170
AlterSeqStmt *altseqstmt = makeNode(AlterSeqStmt);
31713171

@@ -3216,7 +3216,6 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
32163216
ListCell *lc;
32173217
List *newseqopts = NIL;
32183218
List *newdef = NIL;
3219-
List *seqlist;
32203219
AttrNumber attnum;
32213220

32223221
/*
@@ -3237,14 +3236,13 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
32373236

32383237
if (attnum)
32393238
{
3240-
seqlist = getOwnedSequences(relid, attnum);
3241-
if (seqlist)
3239+
Oid seq_relid = getIdentitySequence(relid, attnum, true);
3240+
3241+
if (seq_relid)
32423242
{
32433243
AlterSeqStmt *seqstmt;
3244-
Oid seq_relid;
32453244

32463245
seqstmt = makeNode(AlterSeqStmt);
3247-
seq_relid = linitial_oid(seqlist);
32483246
seqstmt->sequence = makeRangeVar(get_namespace_name(get_rel_namespace(seq_relid)),
32493247
get_rel_name(seq_relid), -1);
32503248
seqstmt->options = newseqopts;

src/backend/rewrite/rewriteHandler.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1130,7 +1130,7 @@ build_column_default(Relation rel, int attrno)
11301130
{
11311131
NextValueExpr *nve = makeNode(NextValueExpr);
11321132

1133-
nve->seqid = getOwnedSequence(RelationGetRelid(rel), attrno);
1133+
nve->seqid = getIdentitySequence(RelationGetRelid(rel), attrno, false);
11341134
nve->typeId = att_tup->atttypid;
11351135

11361136
return (Node *) nve;

src/include/catalog/dependency.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -209,8 +209,8 @@ extern long changeDependenciesOn(Oid refClassId, Oid oldRefObjectId,
209209
extern Oid getExtensionOfObject(Oid classId, Oid objectId);
210210

211211
extern bool sequenceIsOwned(Oid seqId, char deptype, Oid *tableId, int32 *colId);
212-
extern List *getOwnedSequences(Oid relid, AttrNumber attnum);
213-
extern Oid getOwnedSequence(Oid relid, AttrNumber attnum);
212+
extern List *getOwnedSequences(Oid relid);
213+
extern Oid getIdentitySequence(Oid relid, AttrNumber attnum, bool missing_ok);
214214

215215
extern Oid get_constraint_index(Oid constraintId);
216216

src/test/regress/expected/identity.out

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,3 +399,8 @@ CREATE TABLE itest_child PARTITION OF itest_parent (
399399
) FOR VALUES FROM ('2016-07-01') TO ('2016-08-01'); -- error
400400
ERROR: identity columns are not supported on partitions
401401
DROP TABLE itest_parent;
402+
-- test that sequence of half-dropped serial column is properly ignored
403+
CREATE TABLE itest14 (id serial);
404+
ALTER TABLE itest14 ALTER id DROP DEFAULT;
405+
ALTER TABLE itest14 ALTER id ADD GENERATED BY DEFAULT AS IDENTITY;
406+
INSERT INTO itest14 (id) VALUES (DEFAULT);

src/test/regress/sql/identity.sql

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,3 +254,11 @@ CREATE TABLE itest_child PARTITION OF itest_parent (
254254
f3 WITH OPTIONS GENERATED ALWAYS AS IDENTITY
255255
) FOR VALUES FROM ('2016-07-01') TO ('2016-08-01'); -- error
256256
DROP TABLE itest_parent;
257+
258+
259+
-- test that sequence of half-dropped serial column is properly ignored
260+
261+
CREATE TABLE itest14 (id serial);
262+
ALTER TABLE itest14 ALTER id DROP DEFAULT;
263+
ALTER TABLE itest14 ALTER id ADD GENERATED BY DEFAULT AS IDENTITY;
264+
INSERT INTO itest14 (id) VALUES (DEFAULT);

0 commit comments

Comments
 (0)