From b5565bca110c3b2d6fe55cc87d0b3fbb105a504f Mon Sep 17 00:00:00 2001 From: Tom Lane <tgl@sss.pgh.pa.us> Date: Wed, 18 Aug 2010 18:35:21 +0000 Subject: [PATCH] Fix failure of "ALTER TABLE t ADD COLUMN c serial" when done by non-owner. The implicitly created sequence was created as owned by the current user, who could be different from the table owner, eg if current user is a superuser or some member of the table's owning role. This caused sanity checks in the SEQUENCE OWNED BY code to spit up. Although possibly we don't need those sanity checks, the safest fix seems to be to make sure the implicit sequence is assigned the same owner role as the table has. (We still do all permissions checks as the current user, however.) Per report from Josh Berkus. Back-patch to 9.0. The bug goes back to the invention of SEQUENCE OWNED BY in 8.2, but the fix requires an API change for DefineRelation(), which seems to have potential for breaking third-party code if done in a minor release. Given the lack of prior complaints, it's probably not worth fixing in the stable branches. --- src/backend/commands/sequence.c | 4 ++-- src/backend/commands/tablecmds.c | 20 +++++++++++++++++--- src/backend/commands/typecmds.c | 4 ++-- src/backend/commands/view.c | 4 ++-- src/backend/nodes/copyfuncs.c | 3 ++- src/backend/nodes/equalfuncs.c | 3 ++- src/backend/parser/gram.y | 3 ++- src/backend/parser/parse_utilcmd.c | 14 +++++++++++++- src/backend/tcop/utility.c | 5 +++-- src/include/commands/tablecmds.h | 4 ++-- src/include/nodes/parsenodes.h | 3 ++- 11 files changed, 49 insertions(+), 18 deletions(-) diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index 6e0930f8d02..2c07835b952 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.170 2010/08/13 20:10:51 rhaas Exp $ + * $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.171 2010/08/18 18:35:19 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -205,7 +205,7 @@ DefineSequence(CreateSeqStmt *seq) stmt->tablespacename = NULL; stmt->if_not_exists = false; - seqoid = DefineRelation(stmt, RELKIND_SEQUENCE); + seqoid = DefineRelation(stmt, RELKIND_SEQUENCE, seq->ownerId); Assert(seqoid != InvalidOid); rel = heap_open(seqoid, AccessExclusiveLock); diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 703fd7e71b2..2766238f5fc 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.340 2010/08/13 20:10:51 rhaas Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.341 2010/08/18 18:35:19 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -341,11 +341,21 @@ static const char *storage_name(char c); * DefineRelation * Creates a new relation. * + * stmt carries parsetree information from an ordinary CREATE TABLE statement. + * The other arguments are used to extend the behavior for other cases: + * relkind: relkind to assign to the new relation + * ownerId: if not InvalidOid, use this as the new relation's owner. + * + * Note that permissions checks are done against current user regardless of + * ownerId. A nonzero ownerId is used when someone is creating a relation + * "on behalf of" someone else, so we still want to see that the current user + * has permissions to do it. + * * If successful, returns the OID of the new relation. * ---------------------------------------------------------------- */ Oid -DefineRelation(CreateStmt *stmt, char relkind) +DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId) { char relname[NAMEDATALEN]; Oid namespaceId; @@ -440,6 +450,10 @@ DefineRelation(CreateStmt *stmt, char relkind) (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("only shared relations can be placed in pg_global tablespace"))); + /* Identify user ID that will own the table */ + if (!OidIsValid(ownerId)) + ownerId = GetUserId(); + /* * Parse and validate reloptions, if any. */ @@ -532,7 +546,7 @@ DefineRelation(CreateStmt *stmt, char relkind) InvalidOid, InvalidOid, ofTypeId, - GetUserId(), + ownerId, descriptor, list_concat(cookedDefaults, old_constraints), diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 19d61a72568..7652420c3e5 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.150 2010/07/28 05:22:24 sriggs Exp $ + * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.151 2010/08/18 18:35:19 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -1548,7 +1548,7 @@ DefineCompositeType(const RangeVar *typevar, List *coldeflist) /* * Finally create the relation. This also creates the type. */ - relid = DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE); + relid = DefineRelation(createStmt, RELKIND_COMPOSITE_TYPE, InvalidOid); Assert(relid != InvalidOid); return relid; } diff --git a/src/backend/commands/view.c b/src/backend/commands/view.c index 1acf1b802d7..e67d377418e 100644 --- a/src/backend/commands/view.c +++ b/src/backend/commands/view.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.121 2010/07/25 23:21:21 rhaas Exp $ + * $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.122 2010/08/18 18:35:19 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -242,7 +242,7 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace) * existing view, so we don't need more code to complain if "replace" * is false). */ - relid = DefineRelation(createStmt, RELKIND_VIEW); + relid = DefineRelation(createStmt, RELKIND_VIEW, InvalidOid); Assert(relid != InvalidOid); return relid; } diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 70cd56a5921..d33b1198017 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -15,7 +15,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.468 2010/08/18 15:21:54 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.469 2010/08/18 18:35:20 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -3023,6 +3023,7 @@ _copyCreateSeqStmt(CreateSeqStmt *from) COPY_NODE_FIELD(sequence); COPY_NODE_FIELD(options); + COPY_SCALAR_FIELD(ownerId); return newnode; } diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 0cb87015b6e..06cdbf5185b 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -22,7 +22,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.387 2010/08/07 02:44:06 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.388 2010/08/18 18:35:20 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1513,6 +1513,7 @@ _equalCreateSeqStmt(CreateSeqStmt *a, CreateSeqStmt *b) { COMPARE_NODE_FIELD(sequence); COMPARE_NODE_FIELD(options); + COMPARE_SCALAR_FIELD(ownerId); return true; } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index d9aebb0d727..74a799f3e84 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.715 2010/08/05 04:21:53 petere Exp $ + * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.716 2010/08/18 18:35:20 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -2827,6 +2827,7 @@ CreateSeqStmt: $4->istemp = $2; n->sequence = $4; n->options = $5; + n->ownerId = InvalidOid; $$ = (Node *)n; } ; diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index b4e0a614c41..bf680a29488 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -19,7 +19,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.42 2010/08/05 15:25:35 rhaas Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_utilcmd.c,v 2.43 2010/08/18 18:35:20 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -361,6 +361,18 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt, seqstmt->sequence = makeRangeVar(snamespace, sname, -1); seqstmt->options = NIL; + /* + * If this is ALTER ADD COLUMN, make sure the sequence will be owned + * by the table's owner. The current user might be someone else + * (perhaps a superuser, or someone who's only a member of the owning + * role), but the SEQUENCE OWNED BY mechanisms will bleat unless + * table and sequence have exactly the same owning role. + */ + if (cxt->rel) + seqstmt->ownerId = cxt->rel->rd_rel->relowner; + else + seqstmt->ownerId = InvalidOid; + cxt->blist = lappend(cxt->blist, seqstmt); /* diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index db5c6e9c086..d37e9123d97 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.336 2010/07/25 23:21:22 rhaas Exp $ + * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.337 2010/08/18 18:35:20 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -510,7 +510,8 @@ standard_ProcessUtility(Node *parsetree, /* Create the table itself */ relOid = DefineRelation((CreateStmt *) stmt, - RELKIND_RELATION); + RELKIND_RELATION, + InvalidOid); /* * If "IF NOT EXISTS" was specified and the relation diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h index c94a46027ed..9cebb60f514 100644 --- a/src/include/commands/tablecmds.h +++ b/src/include/commands/tablecmds.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/commands/tablecmds.h,v 1.47 2010/07/28 05:22:24 sriggs Exp $ + * $PostgreSQL: pgsql/src/include/commands/tablecmds.h,v 1.48 2010/08/18 18:35:21 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,7 +19,7 @@ #include "utils/relcache.h" -extern Oid DefineRelation(CreateStmt *stmt, char relkind); +extern Oid DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId); extern void RemoveRelations(DropStmt *drop); diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index f02df2aca5b..6d2128df112 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -13,7 +13,7 @@ * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.434 2010/08/07 02:44:07 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.435 2010/08/18 18:35:21 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1700,6 +1700,7 @@ typedef struct CreateSeqStmt NodeTag type; RangeVar *sequence; /* the sequence to create */ List *options; + Oid ownerId; /* ID of owner, or InvalidOid for default */ } CreateSeqStmt; typedef struct AlterSeqStmt -- GitLab