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")));
     * 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 &&
        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
    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? */
                       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
     * 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
    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);
 }
 
 /*
  *           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.
        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 */
 
    return oid;
 }
 
+/*
+ * 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
  *
  *     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
    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);
 
    /*
    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)))
         */
        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);
 
        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);
    /*
     * Close rel, but keep exclusive lock!
     */
-   heap_close(targetrel, NoLock);
+   relation_close(targetrel, NoLock);
 }