diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/commands/alter.c | 62 | ||||
-rw-r--r-- | src/backend/commands/cluster.c | 8 | ||||
-rw-r--r-- | src/backend/commands/tablecmds.c | 186 | ||||
-rw-r--r-- | src/backend/commands/trigger.c | 63 | ||||
-rw-r--r-- | src/backend/commands/typecmds.c | 3 |
5 files changed, 188 insertions, 134 deletions
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c index f9be3a9a4e..2954bb27dd 100644 --- a/src/backend/commands/alter.c +++ b/src/backend/commands/alter.c @@ -105,62 +105,18 @@ ExecRenameStmt(RenameStmt *stmt) case OBJECT_SEQUENCE: case OBJECT_VIEW: case OBJECT_INDEX: + case OBJECT_FOREIGN_TABLE: + RenameRelation(stmt); + break; + case OBJECT_COLUMN: case OBJECT_ATTRIBUTE: + renameatt(stmt); + break; + case OBJECT_TRIGGER: - case OBJECT_FOREIGN_TABLE: - { - Oid relid; - - CheckRelationOwnership(stmt->relation, true); - - /* - * Lock level used here should match what will be taken later, - * in RenameRelation, renameatt, or renametrig. - */ - relid = RangeVarGetRelid(stmt->relation, AccessExclusiveLock, - false); - - switch (stmt->renameType) - { - case OBJECT_TABLE: - case OBJECT_SEQUENCE: - case OBJECT_VIEW: - case OBJECT_INDEX: - case OBJECT_FOREIGN_TABLE: - { - /* - * RENAME TABLE requires that we (still) hold - * CREATE rights on the containing namespace, as - * well as ownership of the table. - */ - Oid namespaceId = get_rel_namespace(relid); - AclResult aclresult; - - aclresult = pg_namespace_aclcheck(namespaceId, - GetUserId(), - ACL_CREATE); - if (aclresult != ACLCHECK_OK) - aclcheck_error(aclresult, ACL_KIND_NAMESPACE, - get_namespace_name(namespaceId)); - - RenameRelation(relid, stmt->newname, stmt->renameType); - break; - } - case OBJECT_COLUMN: - case OBJECT_ATTRIBUTE: - renameatt(relid, stmt); - break; - case OBJECT_TRIGGER: - renametrig(relid, - stmt->subname, /* old att name */ - stmt->newname); /* new att name */ - break; - default: - /* can't happen */ ; - } - break; - } + renametrig(stmt); + break; case OBJECT_TSPARSER: RenameTSParser(stmt->object, stmt->newname); diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index edec44d2c3..e805e28a39 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -1474,28 +1474,24 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap, { Relation toastrel; Oid toastidx; - Oid toastnamespace; char NewToastName[NAMEDATALEN]; toastrel = relation_open(newrel->rd_rel->reltoastrelid, AccessShareLock); toastidx = toastrel->rd_rel->reltoastidxid; - toastnamespace = toastrel->rd_rel->relnamespace; relation_close(toastrel, AccessShareLock); /* rename the toast table ... */ snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u", OIDOldHeap); RenameRelationInternal(newrel->rd_rel->reltoastrelid, - NewToastName, - toastnamespace); + NewToastName); /* ... and its index too */ snprintf(NewToastName, NAMEDATALEN, "pg_toast_%u_index", OIDOldHeap); RenameRelationInternal(toastidx, - NewToastName, - toastnamespace); + NewToastName); } relation_close(newrel, NoLock); } diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 1ee201c141..a036f823f9 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -2064,33 +2064,15 @@ SetRelationHasSubclass(Oid relationId, bool relhassubclass) heap_close(relationRelation, RowExclusiveLock); } - /* - * renameatt_internal - workhorse for renameatt + * renameatt_check - basic sanity checks before attribute rename */ static void -renameatt_internal(Oid myrelid, - const char *oldattname, - const char *newattname, - bool recurse, - bool recursing, - int expected_parents, - DropBehavior behavior) +renameatt_check(Oid myrelid, Form_pg_class classform, bool recursing) { - Relation targetrelation; - Relation attrelation; - HeapTuple atttup; - Form_pg_attribute attform; - int attnum; - char relkind; - - /* - * Grab an exclusive lock on the target table, which we will NOT release - * until end of transaction. - */ - targetrelation = relation_open(myrelid, AccessExclusiveLock); + char relkind = classform->relkind; - if (targetrelation->rd_rel->reloftype && !recursing) + if (classform->reloftype && !recursing) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("cannot rename column of typed table"))); @@ -2102,7 +2084,6 @@ renameatt_internal(Oid myrelid, * change names that are hardcoded into the system, hence the following * restriction. */ - relkind = RelationGetForm(targetrelation)->relkind; if (relkind != RELKIND_RELATION && relkind != RELKIND_VIEW && relkind != RELKIND_COMPOSITE_TYPE && @@ -2111,19 +2092,45 @@ renameatt_internal(Oid myrelid, ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), errmsg("\"%s\" is not a table, view, composite type, index or foreign table", - RelationGetRelationName(targetrelation)))); + NameStr(classform->relname)))); /* * permissions checking. only the owner of a class can change its schema. */ if (!pg_class_ownercheck(myrelid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, - RelationGetRelationName(targetrelation)); - if (!allowSystemTableMods && IsSystemRelation(targetrelation)) + NameStr(classform->relname)); + if (!allowSystemTableMods && IsSystemClass(classform)) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied: \"%s\" is a system catalog", - RelationGetRelationName(targetrelation)))); + NameStr(classform->relname)))); +} + +/* + * renameatt_internal - workhorse for renameatt + */ +static void +renameatt_internal(Oid myrelid, + const char *oldattname, + const char *newattname, + bool recurse, + bool recursing, + int expected_parents, + DropBehavior behavior) +{ + Relation targetrelation; + Relation attrelation; + HeapTuple atttup; + Form_pg_attribute attform; + int attnum; + + /* + * Grab an exclusive lock on the target table, which we will NOT release + * until end of transaction. + */ + targetrelation = relation_open(myrelid, AccessExclusiveLock); + renameatt_check(myrelid, RelationGetForm(targetrelation), recursing); /* * if the 'recurse' flag is set then we are supposed to rename this @@ -2252,14 +2259,38 @@ renameatt_internal(Oid myrelid, relation_close(targetrelation, NoLock); /* close rel but keep lock */ } +/* + * Perform permissions and integrity checks before acquiring a relation lock. + */ +static void +RangeVarCallbackForRenameAttribute(const RangeVar *rv, Oid relid, Oid oldrelid, + void *arg) +{ + HeapTuple tuple; + Form_pg_class form; + + tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid)); + if (!HeapTupleIsValid(tuple)) + return; /* concurrently dropped */ + form = (Form_pg_class) GETSTRUCT(tuple); + renameatt_check(relid, form, false); + ReleaseSysCache(tuple); +} /* * renameatt - changes the name of a attribute in a relation */ void -renameatt(Oid myrelid, RenameStmt *stmt) +renameatt(RenameStmt *stmt) { - renameatt_internal(myrelid, + Oid relid; + + /* lock level taken here should match renameatt_internal */ + relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock, + false, false, + RangeVarCallbackForRenameAttribute, + NULL); + renameatt_internal(relid, stmt->subname, /* old att name */ stmt->newname, /* new att name */ interpretInhOption(stmt->relation->inhOpt), /* recursive? */ @@ -2268,29 +2299,44 @@ renameatt(Oid myrelid, RenameStmt *stmt) stmt->behavior); } - /* - * Execute ALTER TABLE/INDEX/SEQUENCE/VIEW/FOREIGN TABLE RENAME - * - * Caller has already done permissions checks. + * Perform permissions and integrity checks before acquiring a relation lock. */ -void -RenameRelation(Oid myrelid, const char *newrelname, ObjectType reltype) +static void +RangeVarCallbackForRenameRelation(const RangeVar *rv, Oid relid, Oid oldrelid, + void *arg) { - Relation targetrelation; - Oid namespaceId; - char relkind; + RenameStmt *stmt = (RenameStmt *) arg; + ObjectType reltype; + HeapTuple tuple; + Form_pg_class classform; + AclResult aclresult; + char relkind; - /* - * Grab an exclusive lock on the target table, index, sequence or view, - * which we will NOT release until end of transaction. - * - * Lock level used here should match ExecRenameStmt - */ - targetrelation = relation_open(myrelid, AccessExclusiveLock); + tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid)); + if (!HeapTupleIsValid(tuple)) + return; /* concurrently dropped */ + classform = (Form_pg_class) GETSTRUCT(tuple); + relkind = classform->relkind; - namespaceId = RelationGetNamespace(targetrelation); - relkind = targetrelation->rd_rel->relkind; + /* Must own table. */ + if (!pg_class_ownercheck(relid, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, + NameStr(classform->relname)); + + /* No system table modifications unless explicitly allowed. */ + if (!allowSystemTableMods && IsSystemClass(classform)) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied: \"%s\" is a system catalog", + NameStr(classform->relname)))); + + /* Must (still) have CREATE rights on containing namespace. */ + aclresult = pg_namespace_aclcheck(classform->relnamespace, GetUserId(), + ACL_CREATE); + if (aclresult != ACLCHECK_OK) + aclcheck_error(aclresult, ACL_KIND_NAMESPACE, + get_namespace_name(classform->relnamespace)); /* * For compatibility with prior releases, we don't complain if ALTER TABLE @@ -2298,23 +2344,21 @@ RenameRelation(Oid myrelid, const char *newrelname, ObjectType reltype) * ALTER SEQUENCE/VIEW/FOREIGN TABLE are only to be used with relations of * that type. */ + reltype = stmt->renameType; if (reltype == OBJECT_SEQUENCE && relkind != RELKIND_SEQUENCE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("\"%s\" is not a sequence", - RelationGetRelationName(targetrelation)))); + errmsg("\"%s\" is not a sequence", rv->relname))); if (reltype == OBJECT_VIEW && relkind != RELKIND_VIEW) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("\"%s\" is not a view", - RelationGetRelationName(targetrelation)))); + errmsg("\"%s\" is not a view", rv->relname))); if (reltype == OBJECT_FOREIGN_TABLE && relkind != RELKIND_FOREIGN_TABLE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("\"%s\" is not a foreign table", - RelationGetRelationName(targetrelation)))); + errmsg("\"%s\" is not a foreign table", rv->relname))); /* * Don't allow ALTER TABLE on composite types. We want people to use ALTER @@ -2323,17 +2367,35 @@ RenameRelation(Oid myrelid, const char *newrelname, ObjectType reltype) if (relkind == RELKIND_COMPOSITE_TYPE) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), - errmsg("\"%s\" is a composite type", - RelationGetRelationName(targetrelation)), + errmsg("\"%s\" is a composite type", rv->relname), errhint("Use ALTER TYPE instead."))); - /* Do the work */ - RenameRelationInternal(myrelid, newrelname, namespaceId); + ReleaseSysCache(tuple); +} + + +/* + * Execute ALTER TABLE/INDEX/SEQUENCE/VIEW/FOREIGN TABLE RENAME + */ +void +RenameRelation(RenameStmt *stmt) +{ + Oid relid; /* - * Close rel, but keep exclusive lock! + * Grab an exclusive lock on the target table, index, sequence or view, + * which we will NOT release until end of transaction. + * + * Lock level used here should match RenameRelationInternal, to avoid + * lock escalation. */ - relation_close(targetrelation, NoLock); + relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock, + false, false, + RangeVarCallbackForRenameRelation, + (void *) stmt); + + /* Do the work */ + RenameRelationInternal(relid, stmt->newname); } /* @@ -2346,18 +2408,20 @@ RenameRelation(Oid myrelid, const char *newrelname, ObjectType reltype) * sequence, AFAIK there's no need for it to be there. */ void -RenameRelationInternal(Oid myrelid, const char *newrelname, Oid namespaceId) +RenameRelationInternal(Oid myrelid, const char *newrelname) { Relation targetrelation; Relation relrelation; /* for RELATION relation */ HeapTuple reltup; Form_pg_class relform; + Oid namespaceId; /* * Grab an exclusive lock on the target table, index, sequence or view, * which we will NOT release until end of transaction. */ targetrelation = relation_open(myrelid, AccessExclusiveLock); + namespaceId = RelationGetNamespace(targetrelation); /* * Find relation's pg_class tuple, and make sure newrelname isn't in use. @@ -5376,7 +5440,7 @@ ATExecAddIndexConstraint(AlteredTableInfo *tab, Relation rel, ereport(NOTICE, (errmsg("ALTER TABLE / ADD CONSTRAINT USING INDEX will rename index \"%s\" to \"%s\"", indexName, constraintName))); - RenameRelation(index_oid, constraintName, OBJECT_INDEX); + RenameRelationInternal(index_oid, constraintName); } /* Extra checks needed if making primary key */ diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c index b205deca29..f4c93e5b25 100644 --- a/src/backend/commands/trigger.c +++ b/src/backend/commands/trigger.c @@ -1152,6 +1152,39 @@ get_trigger_oid(Oid relid, const char *trigname, bool missing_ok) } /* + * Perform permissions and integrity checks before acquiring a relation lock. + */ +static void +RangeVarCallbackForRenameTrigger(const RangeVar *rv, Oid relid, Oid oldrelid, + void *arg) +{ + HeapTuple tuple; + Form_pg_class form; + + tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid)); + if (!HeapTupleIsValid(tuple)) + return; /* concurrently dropped */ + form = (Form_pg_class) GETSTRUCT(tuple); + + /* only tables and views can have triggers */ + if (form->relkind != RELKIND_RELATION && form->relkind != RELKIND_VIEW) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is not a table or view", rv->relname))); + + /* you must own the table to rename one of its triggers */ + if (!pg_class_ownercheck(relid, GetUserId())) + aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, rv->relname); + if (!allowSystemTableMods && IsSystemClass(form)) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("permission denied: \"%s\" is a system catalog", + rv->relname))); + + ReleaseSysCache(tuple); +} + +/* * renametrig - changes the name of a trigger on a relation * * trigger name is changed in trigger catalog. @@ -1165,21 +1198,26 @@ get_trigger_oid(Oid relid, const char *trigname, bool missing_ok) * update row in catalog */ void -renametrig(Oid relid, - const char *oldname, - const char *newname) +renametrig(RenameStmt *stmt) { Relation targetrel; Relation tgrel; HeapTuple tuple; SysScanDesc tgscan; ScanKeyData key[2]; + Oid relid; /* - * Grab an exclusive lock on the target table, which we will NOT release - * until end of transaction. + * Look up name, check permissions, and acquire lock (which we will NOT + * release until end of transaction). */ - targetrel = heap_open(relid, AccessExclusiveLock); + relid = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock, + false, false, + RangeVarCallbackForRenameTrigger, + NULL); + + /* Have lock already, so just need to build relcache entry. */ + targetrel = relation_open(relid, NoLock); /* * Scan pg_trigger twice for existing triggers on relation. We do this in @@ -1202,14 +1240,14 @@ renametrig(Oid relid, ScanKeyInit(&key[1], Anum_pg_trigger_tgname, BTEqualStrategyNumber, F_NAMEEQ, - PointerGetDatum(newname)); + PointerGetDatum(stmt->newname)); tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true, SnapshotNow, 2, key); if (HeapTupleIsValid(tuple = systable_getnext(tgscan))) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("trigger \"%s\" for relation \"%s\" already exists", - newname, RelationGetRelationName(targetrel)))); + stmt->newname, RelationGetRelationName(targetrel)))); systable_endscan(tgscan); /* @@ -1222,7 +1260,7 @@ renametrig(Oid relid, ScanKeyInit(&key[1], Anum_pg_trigger_tgname, BTEqualStrategyNumber, F_NAMEEQ, - PointerGetDatum(oldname)); + PointerGetDatum(stmt->subname)); tgscan = systable_beginscan(tgrel, TriggerRelidNameIndexId, true, SnapshotNow, 2, key); if (HeapTupleIsValid(tuple = systable_getnext(tgscan))) @@ -1232,7 +1270,8 @@ renametrig(Oid relid, */ tuple = heap_copytuple(tuple); /* need a modifiable copy */ - namestrcpy(&((Form_pg_trigger) GETSTRUCT(tuple))->tgname, newname); + namestrcpy(&((Form_pg_trigger) GETSTRUCT(tuple))->tgname, + stmt->newname); simple_heap_update(tgrel, &tuple->t_self, tuple); @@ -1251,7 +1290,7 @@ renametrig(Oid relid, ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("trigger \"%s\" for table \"%s\" does not exist", - oldname, RelationGetRelationName(targetrel)))); + stmt->subname, RelationGetRelationName(targetrel)))); } systable_endscan(tgscan); @@ -1261,7 +1300,7 @@ renametrig(Oid relid, /* * Close rel, but keep exclusive lock! */ - heap_close(targetrel, NoLock); + relation_close(targetrel, NoLock); } diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index 84ba1a6366..2b8f9aec38 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -3121,8 +3121,7 @@ RenameType(List *names, const char *newTypeName) * RenameRelationInternal will call RenameTypeInternal automatically. */ if (typTup->typtype == TYPTYPE_COMPOSITE) - RenameRelationInternal(typTup->typrelid, newTypeName, - typTup->typnamespace); + RenameRelationInternal(typTup->typrelid, newTypeName); else RenameTypeInternal(typeOid, newTypeName, typTup->typnamespace); |