Repair a longstanding bug in CLUSTER and the rewriting variants of ALTER

TABLE: if the command is executed by someone other than the table owner (eg,
a superuser) and the table has a toast table, the toast table's pg_type row
ends up with the wrong typowner, ie, the command issuer not the table owner.
This is quite harmless for most purposes, since no interesting permissions
checks consult the pg_type row.  However, it could lead to unexpected failures
if one later tries to drop the role that issued the command (in 8.1 or 8.2),
or strange warnings from pg_dump afterwards (in 8.3 and up, which will allow
the DROP ROLE because we don't create a "redundant" owner dependency for table
rowtypes).  Problem identified by Cott Lang.

Back-patch to 8.1.  The problem is actually far older --- the CLUSTER variant
can be demonstrated in 7.0 --- but it's mostly cosmetic before 8.1 because we
didn't track ownership dependencies before 8.1.  Also, fixing it before 8.1
would require changing the call signature of heap_create_with_catalog(), which
seems to carry a nontrivial risk of breaking add-on modules.
This commit is contained in:
Tom Lane 2009-02-24 01:38:49 +00:00
parent 5d4ed4d0ff
commit 1ae836132e
5 changed files with 28 additions and 14 deletions

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.327 2008/01/01 19:45:48 momjian Exp $ * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.327.2.1 2009/02/24 01:38:49 tgl Exp $
* *
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
@ -72,6 +72,7 @@ static Oid AddNewRelationType(const char *typeName,
Oid typeNamespace, Oid typeNamespace,
Oid new_rel_oid, Oid new_rel_oid,
char new_rel_kind, char new_rel_kind,
Oid ownerid,
Oid new_array_type); Oid new_array_type);
static void RelationRemoveInheritance(Oid relid); static void RelationRemoveInheritance(Oid relid);
static void StoreRelCheck(Relation rel, char *ccname, char *ccbin); static void StoreRelCheck(Relation rel, char *ccname, char *ccbin);
@ -740,6 +741,7 @@ AddNewRelationType(const char *typeName,
Oid typeNamespace, Oid typeNamespace,
Oid new_rel_oid, Oid new_rel_oid,
char new_rel_kind, char new_rel_kind,
Oid ownerid,
Oid new_array_type) Oid new_array_type)
{ {
return return
@ -748,6 +750,7 @@ AddNewRelationType(const char *typeName,
typeNamespace, /* type namespace */ typeNamespace, /* type namespace */
new_rel_oid, /* relation oid */ new_rel_oid, /* relation oid */
new_rel_kind, /* relation kind */ new_rel_kind, /* relation kind */
ownerid, /* owner's ID */
-1, /* internal size (varlena) */ -1, /* internal size (varlena) */
TYPTYPE_COMPOSITE, /* type-type (composite) */ TYPTYPE_COMPOSITE, /* type-type (composite) */
DEFAULT_TYPDELIM, /* default array delimiter */ DEFAULT_TYPDELIM, /* default array delimiter */
@ -908,6 +911,7 @@ heap_create_with_catalog(const char *relname,
relnamespace, relnamespace,
relid, relid,
relkind, relkind,
ownerid,
new_array_oid); new_array_oid);
/* /*
@ -924,6 +928,7 @@ heap_create_with_catalog(const char *relname,
relnamespace, /* Same namespace as parent */ relnamespace, /* Same namespace as parent */
InvalidOid, /* Not composite, no relationOid */ InvalidOid, /* Not composite, no relationOid */
0, /* relkind, also N/A here */ 0, /* relkind, also N/A here */
ownerid, /* owner's ID */
-1, /* Internal size (varlena) */ -1, /* Internal size (varlena) */
TYPTYPE_BASE, /* Not composite - typelem is */ TYPTYPE_BASE, /* Not composite - typelem is */
DEFAULT_TYPDELIM, /* default array delimiter */ DEFAULT_TYPDELIM, /* default array delimiter */

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.115 2008/01/01 19:45:48 momjian Exp $ * $PostgreSQL: pgsql/src/backend/catalog/pg_type.c,v 1.115.2.1 2009/02/24 01:38:49 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -45,7 +45,7 @@
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
Oid Oid
TypeShellMake(const char *typeName, Oid typeNamespace) TypeShellMake(const char *typeName, Oid typeNamespace, Oid ownerId)
{ {
Relation pg_type_desc; Relation pg_type_desc;
TupleDesc tupDesc; TupleDesc tupDesc;
@ -85,7 +85,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
namestrcpy(&name, typeName); namestrcpy(&name, typeName);
values[i++] = NameGetDatum(&name); /* typname */ values[i++] = NameGetDatum(&name); /* typname */
values[i++] = ObjectIdGetDatum(typeNamespace); /* typnamespace */ values[i++] = ObjectIdGetDatum(typeNamespace); /* typnamespace */
values[i++] = ObjectIdGetDatum(GetUserId()); /* typowner */ values[i++] = ObjectIdGetDatum(ownerId); /* typowner */
values[i++] = Int16GetDatum(sizeof(int4)); /* typlen */ values[i++] = Int16GetDatum(sizeof(int4)); /* typlen */
values[i++] = BoolGetDatum(true); /* typbyval */ values[i++] = BoolGetDatum(true); /* typbyval */
values[i++] = CharGetDatum(TYPTYPE_PSEUDO); /* typtype */ values[i++] = CharGetDatum(TYPTYPE_PSEUDO); /* typtype */
@ -130,7 +130,7 @@ TypeShellMake(const char *typeName, Oid typeNamespace)
typoid, typoid,
InvalidOid, InvalidOid,
0, 0,
GetUserId(), ownerId,
F_SHELL_IN, F_SHELL_IN,
F_SHELL_OUT, F_SHELL_OUT,
InvalidOid, InvalidOid,
@ -169,6 +169,7 @@ TypeCreate(Oid newTypeOid,
Oid typeNamespace, Oid typeNamespace,
Oid relationOid, /* only for relation rowtypes */ Oid relationOid, /* only for relation rowtypes */
char relationKind, /* ditto */ char relationKind, /* ditto */
Oid ownerId,
int16 internalSize, int16 internalSize,
char typeType, char typeType,
char typDelim, char typDelim,
@ -247,7 +248,7 @@ TypeCreate(Oid newTypeOid,
namestrcpy(&name, typeName); namestrcpy(&name, typeName);
values[i++] = NameGetDatum(&name); /* typname */ values[i++] = NameGetDatum(&name); /* typname */
values[i++] = ObjectIdGetDatum(typeNamespace); /* typnamespace */ values[i++] = ObjectIdGetDatum(typeNamespace); /* typnamespace */
values[i++] = ObjectIdGetDatum(GetUserId()); /* typowner */ values[i++] = ObjectIdGetDatum(ownerId); /* typowner */
values[i++] = Int16GetDatum(internalSize); /* typlen */ values[i++] = Int16GetDatum(internalSize); /* typlen */
values[i++] = BoolGetDatum(passedByValue); /* typbyval */ values[i++] = BoolGetDatum(passedByValue); /* typbyval */
values[i++] = CharGetDatum(typeType); /* typtype */ values[i++] = CharGetDatum(typeType); /* typtype */
@ -317,7 +318,7 @@ TypeCreate(Oid newTypeOid,
/* /*
* shell type must have been created by same owner * shell type must have been created by same owner
*/ */
if (((Form_pg_type) GETSTRUCT(tup))->typowner != GetUserId()) if (((Form_pg_type) GETSTRUCT(tup))->typowner != ownerId)
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, typeName); aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE, typeName);
/* trouble if caller wanted to force the OID */ /* trouble if caller wanted to force the OID */
@ -363,7 +364,7 @@ TypeCreate(Oid newTypeOid,
typeObjectId, typeObjectId,
relationOid, relationOid,
relationKind, relationKind,
GetUserId(), ownerId,
inputProcedure, inputProcedure,
outputProcedure, outputProcedure,
receiveProcedure, receiveProcedure,

View File

@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.88 2008/01/01 19:45:49 momjian Exp $ * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.88.2.1 2009/02/24 01:38:49 tgl Exp $
* *
* DESCRIPTION * DESCRIPTION
* These routines take the parse tree and pick out the * These routines take the parse tree and pick out the
@ -136,7 +136,7 @@ compute_return_type(TypeName *returnType, Oid languageOid,
if (aclresult != ACLCHECK_OK) if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_NAMESPACE, aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
get_namespace_name(namespaceId)); get_namespace_name(namespaceId));
rettype = TypeShellMake(typname, namespaceId); rettype = TypeShellMake(typname, namespaceId, GetUserId());
Assert(OidIsValid(rettype)); Assert(OidIsValid(rettype));
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.113 2008/01/01 19:45:49 momjian Exp $ * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.113.2.1 2009/02/24 01:38:49 tgl Exp $
* *
* DESCRIPTION * DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the * The "DefineFoo" routines take the parse tree and pick out the
@ -160,7 +160,7 @@ DefineType(List *names, List *parameters)
*/ */
if (!OidIsValid(typoid)) if (!OidIsValid(typoid))
{ {
typoid = TypeShellMake(typeName, typeNamespace); typoid = TypeShellMake(typeName, typeNamespace, GetUserId());
/* Make new shell type visible for modification below */ /* Make new shell type visible for modification below */
CommandCounterIncrement(); CommandCounterIncrement();
@ -417,6 +417,7 @@ DefineType(List *names, List *parameters)
typeNamespace, /* namespace */ typeNamespace, /* namespace */
InvalidOid, /* relation oid (n/a here) */ InvalidOid, /* relation oid (n/a here) */
0, /* relation kind (ditto) */ 0, /* relation kind (ditto) */
GetUserId(), /* owner's ID */
internalLength, /* internal size */ internalLength, /* internal size */
TYPTYPE_BASE, /* type-type (base type) */ TYPTYPE_BASE, /* type-type (base type) */
delimiter, /* array element delimiter */ delimiter, /* array element delimiter */
@ -453,6 +454,7 @@ DefineType(List *names, List *parameters)
typeNamespace, /* namespace */ typeNamespace, /* namespace */
InvalidOid, /* relation oid (n/a here) */ InvalidOid, /* relation oid (n/a here) */
0, /* relation kind (ditto) */ 0, /* relation kind (ditto) */
GetUserId(), /* owner's ID */
-1, /* internal size (always varlena) */ -1, /* internal size (always varlena) */
TYPTYPE_BASE, /* type-type (base type) */ TYPTYPE_BASE, /* type-type (base type) */
DEFAULT_TYPDELIM, /* array element delimiter */ DEFAULT_TYPDELIM, /* array element delimiter */
@ -864,6 +866,7 @@ DefineDomain(CreateDomainStmt *stmt)
domainNamespace, /* namespace */ domainNamespace, /* namespace */
InvalidOid, /* relation oid (n/a here) */ InvalidOid, /* relation oid (n/a here) */
0, /* relation kind (ditto) */ 0, /* relation kind (ditto) */
GetUserId(), /* owner's ID */
internalLength, /* internal size */ internalLength, /* internal size */
TYPTYPE_DOMAIN, /* type-type (domain type) */ TYPTYPE_DOMAIN, /* type-type (domain type) */
delimiter, /* array element delimiter */ delimiter, /* array element delimiter */
@ -1044,6 +1047,7 @@ DefineEnum(CreateEnumStmt *stmt)
enumNamespace, /* namespace */ enumNamespace, /* namespace */
InvalidOid, /* relation oid (n/a here) */ InvalidOid, /* relation oid (n/a here) */
0, /* relation kind (ditto) */ 0, /* relation kind (ditto) */
GetUserId(), /* owner's ID */
sizeof(Oid), /* internal size */ sizeof(Oid), /* internal size */
TYPTYPE_ENUM, /* type-type (enum type) */ TYPTYPE_ENUM, /* type-type (enum type) */
DEFAULT_TYPDELIM, /* array element delimiter */ DEFAULT_TYPDELIM, /* array element delimiter */
@ -1080,6 +1084,7 @@ DefineEnum(CreateEnumStmt *stmt)
enumNamespace, /* namespace */ enumNamespace, /* namespace */
InvalidOid, /* relation oid (n/a here) */ InvalidOid, /* relation oid (n/a here) */
0, /* relation kind (ditto) */ 0, /* relation kind (ditto) */
GetUserId(), /* owner's ID */
-1, /* internal size (always varlena) */ -1, /* internal size (always varlena) */
TYPTYPE_BASE, /* type-type (base type) */ TYPTYPE_BASE, /* type-type (base type) */
DEFAULT_TYPDELIM, /* array element delimiter */ DEFAULT_TYPDELIM, /* array element delimiter */

View File

@ -8,7 +8,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/pg_type.h,v 1.191 2008/01/01 19:45:57 momjian Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.191.2.1 2009/02/24 01:38:49 tgl Exp $
* *
* NOTES * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
@ -634,13 +634,16 @@ DATA(insert OID = 3500 ( anyenum PGNSP PGUID 4 t p t \054 0 0 0 anyenum_in any
/* /*
* prototypes for functions in pg_type.c * prototypes for functions in pg_type.c
*/ */
extern Oid TypeShellMake(const char *typeName, Oid typeNamespace); extern Oid TypeShellMake(const char *typeName,
Oid typeNamespace,
Oid ownerId);
extern Oid TypeCreate(Oid newTypeOid, extern Oid TypeCreate(Oid newTypeOid,
const char *typeName, const char *typeName,
Oid typeNamespace, Oid typeNamespace,
Oid relationOid, Oid relationOid,
char relationKind, char relationKind,
Oid ownerId,
int16 internalSize, int16 internalSize,
char typeType, char typeType,
char typDelim, char typDelim,