diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 192891bc4f..71e20f2740 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -3005,14 +3005,15 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
        will be disallowed outright (we'll tell the user to issue a
        <command>DROP</command> against the referenced object, instead).
        While a regular internal dependency will prevent
-       the dependent object from being dropped while any such dependencies remain,
-       <literal>DEPENDENCY_INTERNAL_AUTO</literal> will allow such a drop as long
-       as the object can be found by following any of such dependencies.
-       Example: an index
-       on a partition is made internal-auto-dependent on both the partition
-       itself as well as on the index on the parent partitioned table;
-       so the partition index is dropped together with either partition it indexes,
-       or with the parent index it is attached to.
+       the dependent object from being dropped while any such dependencies
+       remain, <literal>DEPENDENCY_INTERNAL_AUTO</literal> will allow such
+       a drop as long as the object can be found by following any of such
+       dependencies.
+       Example: an index on a partition is made internal-auto-dependent on
+       both the partition itself as well as on the index on the parent
+       partitioned table; so the partition index is dropped together with
+       either the partition it indexes, or with the parent index it is
+       attached to.
       </para>
      </listitem>
     </varlistentry>
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index a46e859488..be60270ea5 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -637,14 +637,16 @@ findDependentObjects(const ObjectAddress *object,
 				 * For INTERNAL_AUTO dependencies, we don't enforce this;
 				 * in other words, we don't follow the links back to the
 				 * owning object.
-				 *
+				 */
+				if (foundDep->deptype == DEPENDENCY_INTERNAL_AUTO)
+					break;
+
+				/*
 				 * First, release caller's lock on this object and get
 				 * deletion lock on the owning object.  (We must release
 				 * caller's lock to avoid deadlock against a concurrent
 				 * deletion of the owning object.)
 				 */
-				if (foundDep->deptype == DEPENDENCY_INTERNAL_AUTO)
-					break;
 				ReleaseDeletionLock(object);
 				AcquireDeletionLock(&otherObject, 0);
 
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index 6c4649c594..4e10026297 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -42,6 +42,7 @@
 #include "catalog/pg_constraint.h"
 #include "catalog/pg_constraint_fn.h"
 #include "catalog/pg_depend.h"
+#include "catalog/pg_inherits_fn.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_opclass.h"
 #include "catalog/pg_tablespace.h"
@@ -56,6 +57,7 @@
 #include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
 #include "parser/parser.h"
+#include "rewrite/rewriteManip.h"
 #include "storage/bufmgr.h"
 #include "storage/lmgr.h"
 #include "storage/predicate.h"
@@ -869,9 +871,9 @@ index_create(Relation heapRelation,
 	}
 
 	/*
-	 * create the index relation's relcache entry and physical disk file. (If
-	 * we fail further down, it's the smgr's responsibility to remove the disk
-	 * file again.)
+	 * create the index relation's relcache entry and, if necessary, the
+	 * physical disk file. (If we fail further down, it's the smgr's
+	 * responsibility to remove the disk file again, if any.)
 	 */
 	indexRelation = heap_create(indexRelationName,
 								namespaceId,
@@ -1044,7 +1046,6 @@ index_create(Relation heapRelation,
 			recordDependencyOn(&myself, &referenced, DEPENDENCY_INTERNAL_AUTO);
 		}
 
-
 		/* Store dependency on collations */
 		/* The default collation is pinned, so don't bother recording it */
 		for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
@@ -1745,7 +1746,7 @@ BuildIndexInfo(Relation index)
  * attmap is an attribute map where info2 is input and info1 is output.
  */
 bool
-CompareIndexInfo(IndexInfo *info1, IndexInfo *info2, AttrNumber *attmap)
+CompareIndexInfo(IndexInfo *info1, IndexInfo *info2, AttrNumber *attmap, int maplen)
 {
 	int		i;
 
@@ -1759,7 +1760,9 @@ CompareIndexInfo(IndexInfo *info1, IndexInfo *info2, AttrNumber *attmap)
 
 	/*
 	 * and columns match through the attribute map (actual attribute numbers
-	 * might differ!)
+	 * might differ!)  Note that this implies that index columns that are
+	 * expressions appear in the same positions.  We will next compare the
+	 * expressions themselves.
 	 */
 	for (i = 0; i < info1->ii_NumIndexAttrs; i++)
 	{
@@ -1769,11 +1772,24 @@ CompareIndexInfo(IndexInfo *info1, IndexInfo *info2, AttrNumber *attmap)
 	}
 
 	/*
-	 * Expression indexes are currently not considered equal.  Not needed for
-	 * current callers.
+	 * For expression indexes: either both are expression indexes, or neither
+	 * is; if they are, make sure the expressions match.
 	 */
-	if (info1->ii_Expressions != NIL || info2->ii_Expressions != NIL)
+	if ((info1->ii_Expressions != NIL) != (info2->ii_Expressions != NIL))
 		return false;
+	else
+	{
+		bool	found_whole_row;
+		Node   *mapped;
+
+		mapped = map_variable_attnos((Node *) info2->ii_Expressions,
+									 1, 0, attmap, maplen,
+									 InvalidOid, &found_whole_row);
+		if (found_whole_row)
+			elog(ERROR, "having fun with whole-row expressions, are we?");
+
+		return equal(info1->ii_Expressions, mapped);
+	}
 
 	/* Index predicates must be identical */
 	if (!equal(info1->ii_Predicate, info2->ii_Predicate))
diff --git a/src/backend/catalog/pg_inherits.c b/src/backend/catalog/pg_inherits.c
index bde5176cab..973e8d5835 100644
--- a/src/backend/catalog/pg_inherits.c
+++ b/src/backend/catalog/pg_inherits.c
@@ -410,7 +410,7 @@ typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId)
  * Create a single pg_inherits row with the given data
  */
 void
-StoreSingleInheritance(Oid relationId, Oid parentOid, int16 seqNumber)
+StoreSingleInheritance(Oid relationId, Oid parentOid, int32 seqNumber)
 {
 	Datum		values[Natts_pg_inherits];
 	bool		nulls[Natts_pg_inherits];
@@ -424,7 +424,7 @@ StoreSingleInheritance(Oid relationId, Oid parentOid, int16 seqNumber)
 	 */
 	values[Anum_pg_inherits_inhrelid - 1] = ObjectIdGetDatum(relationId);
 	values[Anum_pg_inherits_inhparent - 1] = ObjectIdGetDatum(parentOid);
-	values[Anum_pg_inherits_inhseqno - 1] = Int16GetDatum(seqNumber);
+	values[Anum_pg_inherits_inhseqno - 1] = Int32GetDatum(seqNumber);
 
 	memset(nulls, 0, sizeof(nulls));
 
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 9b7f29c7fc..1a921f70a2 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -816,7 +816,7 @@ DefineIndex(Oid relationId,
 													   parentDesc,
 													   gettext_noop("could not convert row type"));
 
-					if (CompareIndexInfo(cldIdxInfo, indexInfo, attmap))
+					if (CompareIndexInfo(cldIdxInfo, indexInfo, attmap, parentDesc->natts))
 					{
 						/*
 						 * Found a match.  Attach index to parent and we're
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index a9a1d7fdd7..649a644158 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -4206,9 +4206,13 @@ ATRewriteTables(AlterTableStmt *parsetree, List **wqueue, LOCKMODE lockmode)
 	{
 		AlteredTableInfo *tab = (AlteredTableInfo *) lfirst(ltab);
 
-		/* Foreign tables have no storage, nor do partitioned tables. */
+		/*
+		 * Foreign tables have no storage, nor do partitioned tables and
+		 * indexes.
+		 */
 		if (tab->relkind == RELKIND_FOREIGN_TABLE ||
-			tab->relkind == RELKIND_PARTITIONED_TABLE)
+			tab->relkind == RELKIND_PARTITIONED_TABLE ||
+			tab->relkind == RELKIND_PARTITIONED_INDEX)
 			continue;
 
 		/*
@@ -14084,7 +14088,8 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
 				if (has_superclass(RelationGetRelid(attachrelIdxRels[i])))
 					continue;
 
-				if (CompareIndexInfo(info, attachInfos[i], attmap))
+				if (CompareIndexInfo(info, attachInfos[i], attmap,
+									 RelationGetDescr(rel)->natts))
 				{
 					/* bingo. */
 					IndexSetParentIndex(attachrelIdxRels[i], idx);
@@ -14121,6 +14126,8 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
 			pfree(idxes);
 		if (attachRelIdxs)
 			pfree(attachRelIdxs);
+		if (attachInfos)
+			pfree(attachInfos);
 	}
 
 	/*
@@ -14283,8 +14290,7 @@ ATExecDetachPartition(Relation rel, RangeVar *name)
 		if (!has_superclass(idxid))
 			continue;
 
-		Assert(!has_superclass(idxid) ||
-			   (IndexGetRelation(get_partition_parent(idxid), false) ==
+		Assert((IndexGetRelation(get_partition_parent(idxid), false) ==
 			   RelationGetRelid(rel)));
 
 		idx = index_open(idxid, AccessExclusiveLock);
@@ -14402,16 +14408,16 @@ ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx, RangeVar *name)
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
 				 errmsg("index \"%s\" does not exist", name->relname)));
 
-	/* no deadlock risk: our callback above already acquired the lock */
+	/* no deadlock risk: RangeVarGetRelidExtended already acquired the lock */
 	partIdx = relation_open(partIdxId, AccessExclusiveLock);
 
-	/* we already hold lock on both tables, so this is safe: */
+	/* we already hold locks on both tables, so this is safe: */
 	parentTbl = relation_open(parentIdx->rd_index->indrelid, AccessShareLock);
 	partTbl = relation_open(partIdx->rd_index->indrelid, NoLock);
 
 	ObjectAddressSet(address, RelationRelationId, RelationGetRelid(partIdx));
 
-	/* Silently do nothing if already the right state */
+	/* Silently do nothing if already in the right state */
 	currParent = !has_superclass(partIdxId) ? InvalidOid :
 		get_partition_parent(partIdxId);
 	if (currParent != RelationGetRelid(parentIdx))
@@ -14463,7 +14469,8 @@ ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx, RangeVar *name)
 		attmap = convert_tuples_by_name_map(RelationGetDescr(parentTbl),
 											RelationGetDescr(partTbl),
 											gettext_noop("could not convert row type"));
-		if (!CompareIndexInfo(parentInfo, childInfo, attmap))
+		if (!CompareIndexInfo(parentInfo, childInfo, attmap,
+							  RelationGetDescr(partTbl)->natts))
 			ereport(ERROR,
 					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
 					 errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 04ef741a4c..5bf8dc2e56 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -7390,6 +7390,7 @@ IndexStmt:	CREATE opt_unique INDEX opt_concurrently opt_index_name
 					n->concurrent = $4;
 					n->idxname = $8;
 					n->relation = $10;
+					n->relationId = InvalidOid;
 					n->accessMethod = $11;
 					n->indexParams = $13;
 					n->options = $15;
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 16c4f8fad4..1a29dda783 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1353,8 +1353,7 @@ ProcessUtilitySlow(ParseState *pstate,
 					commandCollected = true;
 					EventTriggerAlterTableEnd();
 
-					if (inheritors)
-						list_free(inheritors);
+					list_free(inheritors);
 				}
 				break;
 
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index a28046f857..2e4e968a90 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -430,20 +430,26 @@ static void
 RelationParseRelOptions(Relation relation, HeapTuple tuple)
 {
 	bytea	   *options;
-	bool		isindex;
+	amoptions_function amoptsfn;
 
 	relation->rd_options = NULL;
 
-	/* Fall out if relkind should not have options */
+	/*
+	 * Look up any AM-specific parse function; fall out if relkind should not
+	 * have options.
+	 */
 	switch (relation->rd_rel->relkind)
 	{
 		case RELKIND_RELATION:
 		case RELKIND_TOASTVALUE:
-		case RELKIND_INDEX:
-		case RELKIND_PARTITIONED_INDEX:
 		case RELKIND_VIEW:
 		case RELKIND_MATVIEW:
 		case RELKIND_PARTITIONED_TABLE:
+			amoptsfn = NULL;
+			break;
+		case RELKIND_INDEX:
+		case RELKIND_PARTITIONED_INDEX:
+			amoptsfn = relation->rd_amroutine->amoptions;
 			break;
 		default:
 			return;
@@ -454,12 +460,7 @@ RelationParseRelOptions(Relation relation, HeapTuple tuple)
 	 * we might not have any other for pg_class yet (consider executing this
 	 * code for pg_class itself)
 	 */
-	isindex = relation->rd_rel->relkind == RELKIND_INDEX ||
-		relation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX;
-	options = extractRelOptions(tuple,
-								GetPgClassDescriptor(),
-								isindex ? relation->rd_amroutine->amoptions :
-								NULL);
+	options = extractRelOptions(tuple, GetPgClassDescriptor(), amoptions);
 
 	/*
 	 * Copy parsed data into CacheMemoryContext.  To guard against the
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 2b2c166266..f1765af4ba 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	201712291
+#define CATALOG_VERSION_NO	201712251
 
 #endif
diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h
index 67d8a20be3..46c271a46c 100644
--- a/src/include/catalog/dependency.h
+++ b/src/include/catalog/dependency.h
@@ -60,7 +60,7 @@
  * Example: an index on a partition is made internal-auto-dependent on
  * both the partition itself as well as on the index on the parent
  * partitioned table; so the partition index is dropped together with
- * either partition it indexes, or with the parent index it is attached
+ * either the partition it indexes, or with the parent index it is attached
  * to.
 
  * DEPENDENCY_EXTENSION ('e'): the dependent object is a member of the
diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h
index 139365c3b3..8ff3a0732e 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -87,7 +87,8 @@ extern void index_drop(Oid indexId, bool concurrent);
 
 extern IndexInfo *BuildIndexInfo(Relation index);
 
-extern bool CompareIndexInfo(IndexInfo *info1, IndexInfo *info2, AttrNumber *attmap);
+extern bool CompareIndexInfo(IndexInfo *info1, IndexInfo *info2,
+				 AttrNumber *attmap, int maplen);
 
 extern void BuildSpeculativeIndexInfo(Relation index, IndexInfo *ii);
 
diff --git a/src/include/catalog/pg_inherits_fn.h b/src/include/catalog/pg_inherits_fn.h
index b587f2d042..d0abde4168 100644
--- a/src/include/catalog/pg_inherits_fn.h
+++ b/src/include/catalog/pg_inherits_fn.h
@@ -24,6 +24,6 @@ extern bool has_subclass(Oid relationId);
 extern bool has_superclass(Oid relationId);
 extern bool typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId);
 extern void StoreSingleInheritance(Oid relationId, Oid parentOid,
-					   int16 seqNumber);
+					   int32 seqNumber);
 
 #endif							/* PG_INHERITS_FN_H */
