diff options
Diffstat (limited to 'src/backend/commands/tablecmds.c')
-rw-r--r-- | src/backend/commands/tablecmds.c | 62 |
1 files changed, 48 insertions, 14 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 99b70d223d9..0d34f7007e1 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -3733,7 +3733,7 @@ RenameConstraint(RenameStmt *stmt) ObjectAddress RenameRelation(RenameStmt *stmt) { - bool is_index = stmt->renameType == OBJECT_INDEX; + bool is_index_stmt = stmt->renameType == OBJECT_INDEX; Oid relid; ObjectAddress address; @@ -3743,24 +3743,48 @@ RenameRelation(RenameStmt *stmt) * end of transaction. * * Lock level used here should match RenameRelationInternal, to avoid lock - * escalation. + * escalation. However, because ALTER INDEX can be used with any relation + * type, we mustn't believe without verification. */ - relid = RangeVarGetRelidExtended(stmt->relation, - is_index ? ShareUpdateExclusiveLock : AccessExclusiveLock, - stmt->missing_ok ? RVR_MISSING_OK : 0, - RangeVarCallbackForAlterRelation, - (void *) stmt); - - if (!OidIsValid(relid)) + for (;;) { - ereport(NOTICE, - (errmsg("relation \"%s\" does not exist, skipping", - stmt->relation->relname))); - return InvalidObjectAddress; + LOCKMODE lockmode; + char relkind; + bool obj_is_index; + + lockmode = is_index_stmt ? ShareUpdateExclusiveLock : AccessExclusiveLock; + + relid = RangeVarGetRelidExtended(stmt->relation, lockmode, + stmt->missing_ok ? RVR_MISSING_OK : 0, + RangeVarCallbackForAlterRelation, + (void *) stmt); + + if (!OidIsValid(relid)) + { + ereport(NOTICE, + (errmsg("relation \"%s\" does not exist, skipping", + stmt->relation->relname))); + return InvalidObjectAddress; + } + + /* + * We allow mismatched statement and object types (e.g., ALTER INDEX + * to rename a table), but we might've used the wrong lock level. If + * that happens, retry with the correct lock level. We don't bother + * if we already acquired AccessExclusiveLock with an index, however. + */ + relkind = get_rel_relkind(relid); + obj_is_index = (relkind == RELKIND_INDEX || + relkind == RELKIND_PARTITIONED_INDEX); + if (obj_is_index || is_index_stmt == obj_is_index) + break; + + UnlockRelationOid(relid, lockmode); + is_index_stmt = obj_is_index; } /* Do the work */ - RenameRelationInternal(relid, stmt->newname, false, is_index); + RenameRelationInternal(relid, stmt->newname, false, is_index_stmt); ObjectAddressSet(address, RelationRelationId, relid); @@ -3809,6 +3833,16 @@ RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bo newrelname))); /* + * RenameRelation is careful not to believe the caller's idea of the + * relation kind being handled. We don't have to worry about this, but + * let's not be totally oblivious to it. We can process an index as + * not-an-index, but not the other way around. + */ + Assert(!is_index || + is_index == (targetrelation->rd_rel->relkind == RELKIND_INDEX || + targetrelation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)); + + /* * Update pg_class tuple with new relname. (Scribbling on reltup is OK * because it's a copy...) */ |