From da324f0e2aae09f185ceca3473e8ca8eeae3c317 Mon Sep 17 00:00:00 2001
From: Nikita Glukhov <n.gluhov@postgrespro.ru>
Date: Tue, 10 Sep 2019 03:35:40 +0300
Subject: [PATCH 5/5] Remove pg_index.indoption

---
 doc/src/sgml/catalogs.sgml                | 11 -------
 src/backend/access/common/reloptions.c    | 37 +++++++++++++++++++++
 src/backend/access/nbtree/nbtree.c        |  3 +-
 src/backend/access/nbtree/nbtutils.c      | 36 +++++++++++++--------
 src/backend/catalog/index.c               | 19 ++---------
 src/backend/catalog/toasting.c            |  6 +---
 src/backend/commands/indexcmds.c          | 51 ++++++++++++++---------------
 src/backend/optimizer/util/plancat.c      | 16 ++++++----
 src/backend/parser/parse_utilcmd.c        | 26 +--------------
 src/backend/utils/adt/amutils.c           | 45 ++++++++++++++------------
 src/backend/utils/adt/ruleutils.c         | 53 ++++++++++++++++++-------------
 src/backend/utils/cache/relcache.c        | 41 +++++-------------------
 src/include/access/genam.h                |  7 ++++
 src/include/access/nbtree.h               | 11 +++----
 src/include/access/reloptions.h           |  3 ++
 src/include/catalog/index.h               |  1 -
 src/include/catalog/pg_index.h            |  9 ++----
 src/include/utils/rel.h                   |  1 -
 src/test/regress/expected/btree_index.out |  4 +--
 src/test/regress/expected/opr_sanity.out  |  3 +-
 src/test/regress/sql/opr_sanity.sql       |  3 +-
 21 files changed, 183 insertions(+), 203 deletions(-)

diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 5e71a2e..5b95131 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -3916,17 +3916,6 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
      </row>
 
      <row>
-      <entry><structfield>indoption</structfield></entry>
-      <entry><type>int2vector</type></entry>
-      <entry></entry>
-      <entry>
-       This is an array of <structfield>indnkeyatts</structfield> values that
-       store per-column flag bits.  The meaning of the bits is defined by
-       the index's access method.
-      </entry>
-     </row>
-
-     <row>
       <entry><structfield>indexprs</structfield></entry>
       <entry><type>pg_node_tree</type></entry>
       <entry></entry>
diff --git a/src/backend/access/common/reloptions.c b/src/backend/access/common/reloptions.c
index 3ad1324..5d7e704 100644
--- a/src/backend/access/common/reloptions.c
+++ b/src/backend/access/common/reloptions.c
@@ -1888,3 +1888,40 @@ AlterTableGetRelOptionsLockLevel(List *defList)
 
 	return lockmode;
 }
+
+static void
+ordattoptions_validator(void *parsed_options, relopt_value *vals, int nvals)
+{
+	OrderedAttOptions *ordopts = parsed_options;
+
+	for (int i = 0; i < nvals; i++)
+		if (!strcmp(vals[i].gen->name, "nulls_first") &&
+			!vals[i].isset)
+			ordopts->nulls_first = ordopts->desc;
+}
+
+void
+ordered_index_attoptions(local_relopts *relopts, int attno)
+{
+	OrderedAttOptions *attopts = NULL;
+
+	init_local_reloptions(relopts, attopts, sizeof(*attopts));
+	add_local_bool_reloption(relopts, INDOPTION_DESC,
+							 "Descending ordering",
+							 false, &attopts->desc);
+	add_local_bool_reloption(relopts, INDOPTION_NULLS_FIRST,
+							 "NULLs sorted first",
+							 false, &attopts->nulls_first);
+	register_reloptions_validator(relopts, ordattoptions_validator);
+}
+
+OrderedAttOptions *
+get_ordered_attoptions(Datum attoptions)
+{
+	local_relopts relopts;
+
+	ordered_index_attoptions(&relopts, 0);
+
+	return (OrderedAttOptions *)
+		parseAndFillLocalRelOptions(&relopts, attoptions, false);
+}
diff --git a/src/backend/access/nbtree/nbtree.c b/src/backend/access/nbtree/nbtree.c
index 0741107..d4ed36d 100644
--- a/src/backend/access/nbtree/nbtree.c
+++ b/src/backend/access/nbtree/nbtree.c
@@ -20,6 +20,7 @@
 
 #include "access/nbtree.h"
 #include "access/nbtxlog.h"
+#include "access/reloptions.h"
 #include "access/relscan.h"
 #include "access/xlog.h"
 #include "commands/progress.h"
@@ -133,7 +134,7 @@ bthandler(PG_FUNCTION_ARGS)
 	amroutine->amcanreturn = btcanreturn;
 	amroutine->amcostestimate = btcostestimate;
 	amroutine->amoptions = btoptions;
-	amroutine->amattoptions = NULL;
+	amroutine->amattoptions = ordered_index_attoptions;
 	amroutine->amproperty = btproperty;
 	amroutine->ambuildphasename = btbuildphasename;
 	amroutine->amvalidate = btvalidate;
diff --git a/src/backend/access/nbtree/nbtutils.c b/src/backend/access/nbtree/nbtutils.c
index 4c7b2d0..8d093de 100644
--- a/src/backend/access/nbtree/nbtutils.c
+++ b/src/backend/access/nbtree/nbtutils.c
@@ -46,7 +46,7 @@ static int	_bt_compare_array_elements(const void *a, const void *b, void *arg);
 static bool _bt_compare_scankey_args(IndexScanDesc scan, ScanKey op,
 									 ScanKey leftarg, ScanKey rightarg,
 									 bool *result);
-static bool _bt_fix_scankey_strategy(ScanKey skey, int16 *indoption);
+static bool _bt_fix_scankey_strategy(ScanKey skey, bytea **attoptions);
 static void _bt_mark_scankey_required(ScanKey skey);
 static bool _bt_check_rowcompare(ScanKey skey,
 								 IndexTuple tuple, int tupnatts, TupleDesc tupdesc,
@@ -54,6 +54,9 @@ static bool _bt_check_rowcompare(ScanKey skey,
 static int	_bt_keep_natts(Relation rel, IndexTuple lastleft,
 						   IndexTuple firstright, BTScanInsert itup_key);
 
+#define _bt_scankey_ordering_flags(ordopts) \
+	((ordopts->desc ? SK_BT_DESC : 0) | \
+	 (ordopts->nulls_first ? SK_BT_NULLS_FIRST : 0))
 
 /*
  * _bt_mkscankey
@@ -88,13 +91,13 @@ _bt_mkscankey(Relation rel, IndexTuple itup)
 	ScanKey		skey;
 	TupleDesc	itupdesc;
 	int			indnkeyatts;
-	int16	   *indoption;
+	bytea	  **attoptions;
 	int			tupnatts;
 	int			i;
 
 	itupdesc = RelationGetDescr(rel);
 	indnkeyatts = IndexRelationGetNumberOfKeyAttributes(rel);
-	indoption = rel->rd_indoption;
+	attoptions = RelationGetIndexAttOptions(rel, false);
 	tupnatts = itup ? BTreeTupleGetNAtts(itup, rel) : 0;
 
 	Assert(tupnatts <= IndexRelationGetNumberOfAttributes(rel));
@@ -117,6 +120,7 @@ _bt_mkscankey(Relation rel, IndexTuple itup)
 	for (i = 0; i < indnkeyatts; i++)
 	{
 		FmgrInfo   *procinfo;
+		OrderedAttOptions *ordopts = (OrderedAttOptions *) attoptions[i];
 		Datum		arg;
 		bool		null;
 		int			flags;
@@ -139,7 +143,9 @@ _bt_mkscankey(Relation rel, IndexTuple itup)
 			arg = (Datum) 0;
 			null = true;
 		}
-		flags = (null ? SK_ISNULL : 0) | (indoption[i] << SK_BT_INDOPTION_SHIFT);
+
+		flags = (null ? SK_ISNULL : 0) | _bt_scankey_ordering_flags(ordopts);
+
 		ScanKeyEntryInitializeWithInfo(&skey[i],
 									   flags,
 									   (AttrNumber) (i + 1),
@@ -192,7 +198,7 @@ _bt_preprocess_array_keys(IndexScanDesc scan)
 {
 	BTScanOpaque so = (BTScanOpaque) scan->opaque;
 	int			numberOfKeys = scan->numberOfKeys;
-	int16	   *indoption = scan->indexRelation->rd_indoption;
+	bytea	  **attopts = RelationGetIndexAttOptions(scan->indexRelation, false);
 	int			numArrayKeys;
 	ScanKey		cur;
 	int			i;
@@ -335,7 +341,7 @@ _bt_preprocess_array_keys(IndexScanDesc scan)
 		 * successive primitive indexscans produce data in index order.
 		 */
 		num_elems = _bt_sort_array_elements(scan, cur,
-											(indoption[cur->sk_attno - 1] & INDOPTION_DESC) != 0,
+											((OrderedAttOptions *) attopts[cur->sk_attno - 1])->desc,
 											elem_values, num_nonnulls);
 
 		/*
@@ -745,7 +751,7 @@ _bt_preprocess_keys(IndexScanDesc scan)
 {
 	BTScanOpaque so = (BTScanOpaque) scan->opaque;
 	int			numberOfKeys = scan->numberOfKeys;
-	int16	   *indoption = scan->indexRelation->rd_indoption;
+	bytea	  **attoptions = RelationGetIndexAttOptions(scan->indexRelation, false);
 	int			new_numberOfKeys;
 	int			numberOfEqualCols;
 	ScanKey		inkeys;
@@ -782,7 +788,7 @@ _bt_preprocess_keys(IndexScanDesc scan)
 	if (numberOfKeys == 1)
 	{
 		/* Apply indoption to scankey (might change sk_strategy!) */
-		if (!_bt_fix_scankey_strategy(cur, indoption))
+		if (!_bt_fix_scankey_strategy(cur, attoptions))
 			so->qual_ok = false;
 		memcpy(outkeys, cur, sizeof(ScanKeyData));
 		so->numberOfKeys = 1;
@@ -817,7 +823,7 @@ _bt_preprocess_keys(IndexScanDesc scan)
 		if (i < numberOfKeys)
 		{
 			/* Apply indoption to scankey (might change sk_strategy!) */
-			if (!_bt_fix_scankey_strategy(cur, indoption))
+			if (!_bt_fix_scankey_strategy(cur, attoptions))
 			{
 				/* NULL can't be matched, so give up */
 				so->qual_ok = false;
@@ -1195,11 +1201,10 @@ _bt_compare_scankey_args(IndexScanDesc scan, ScanKey op,
  * not going to change while the scankey survives.
  */
 static bool
-_bt_fix_scankey_strategy(ScanKey skey, int16 *indoption)
+_bt_fix_scankey_strategy(ScanKey skey, bytea **attopts)
 {
-	int			addflags;
-
-	addflags = indoption[skey->sk_attno - 1] << SK_BT_INDOPTION_SHIFT;
+	OrderedAttOptions *ordopts = (OrderedAttOptions *) attopts[skey->sk_attno - 1];
+	int			addflags = _bt_scankey_ordering_flags(ordopts);
 
 	/*
 	 * We treat all btree operators as strict (even if they're not so marked
@@ -1268,7 +1273,10 @@ _bt_fix_scankey_strategy(ScanKey skey, int16 *indoption)
 		for (;;)
 		{
 			Assert(subkey->sk_flags & SK_ROW_MEMBER);
-			addflags = indoption[subkey->sk_attno - 1] << SK_BT_INDOPTION_SHIFT;
+
+			ordopts = (OrderedAttOptions *) attopts[subkey->sk_attno - 1];
+			addflags = _bt_scankey_ordering_flags(ordopts);
+
 			if ((addflags & SK_BT_DESC) && !(subkey->sk_flags & SK_BT_DESC))
 				subkey->sk_strategy = BTCommuteStrategyNumber(subkey->sk_strategy);
 			subkey->sk_flags |= addflags;
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index cb7f0ba..60ec7ab 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -114,7 +114,6 @@ static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
 								IndexInfo *indexInfo,
 								Oid *collationOids,
 								Oid *classOids,
-								int16 *coloptions,
 								bool primary,
 								bool isexclusion,
 								bool immediate,
@@ -535,7 +534,6 @@ UpdateIndexRelation(Oid indexoid,
 					IndexInfo *indexInfo,
 					Oid *collationOids,
 					Oid *classOids,
-					int16 *coloptions,
 					bool primary,
 					bool isexclusion,
 					bool immediate,
@@ -545,7 +543,6 @@ UpdateIndexRelation(Oid indexoid,
 	int2vector *indkey;
 	oidvector  *indcollation;
 	oidvector  *indclass;
-	int2vector *indoption;
 	Datum		exprsDatum;
 	Datum		predDatum;
 	Datum		values[Natts_pg_index];
@@ -555,7 +552,7 @@ UpdateIndexRelation(Oid indexoid,
 	int			i;
 
 	/*
-	 * Copy the index key, opclass, and indoption info into arrays (should we
+	 * Copy the index key and opclass info into arrays (should we
 	 * make the caller pass them like this to start with?)
 	 */
 	indkey = buildint2vector(NULL, indexInfo->ii_NumIndexAttrs);
@@ -563,7 +560,6 @@ UpdateIndexRelation(Oid indexoid,
 		indkey->values[i] = indexInfo->ii_IndexAttrNumbers[i];
 	indcollation = buildoidvector(collationOids, indexInfo->ii_NumIndexKeyAttrs);
 	indclass = buildoidvector(classOids, indexInfo->ii_NumIndexKeyAttrs);
-	indoption = buildint2vector(coloptions, indexInfo->ii_NumIndexKeyAttrs);
 
 	/*
 	 * Convert the index expressions (if any) to a text datum
@@ -622,7 +618,6 @@ UpdateIndexRelation(Oid indexoid,
 	values[Anum_pg_index_indkey - 1] = PointerGetDatum(indkey);
 	values[Anum_pg_index_indcollation - 1] = PointerGetDatum(indcollation);
 	values[Anum_pg_index_indclass - 1] = PointerGetDatum(indclass);
-	values[Anum_pg_index_indoption - 1] = PointerGetDatum(indoption);
 	values[Anum_pg_index_indexprs - 1] = exprsDatum;
 	if (exprsDatum == (Datum) 0)
 		nulls[Anum_pg_index_indexprs - 1] = true;
@@ -665,7 +660,6 @@ UpdateIndexRelation(Oid indexoid,
  * tableSpaceId: OID of tablespace to use
  * collationObjectId: array of collation OIDs, one per index column
  * classObjectId: array of index opclass OIDs, one per index column
- * coloptions: array of per-index-column indoption settings
  * reloptions: AM-specific options
  * flags: bitmask that can include any combination of these bits:
  *		INDEX_CREATE_IS_PRIMARY
@@ -705,7 +699,6 @@ index_create(Relation heapRelation,
 			 Oid tableSpaceId,
 			 Oid *collationObjectId,
 			 Oid *classObjectId,
-			 int16 *coloptions,
 			 Datum reloptions,
 			 bits16 flags,
 			 bits16 constr_flags,
@@ -950,7 +943,7 @@ index_create(Relation heapRelation,
 	 */
 	UpdateIndexRelation(indexRelationId, heapRelationId, parentIndexRelid,
 						indexInfo,
-						collationObjectId, classObjectId, coloptions,
+						collationObjectId, classObjectId,
 						isprimary, is_exclusion,
 						(constr_flags & INDEX_CONSTR_CREATE_DEFERRABLE) == 0,
 						!concurrent && !invalid,
@@ -1215,10 +1208,8 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, const char
 	HeapTuple	indexTuple,
 				classTuple;
 	Datum		indclassDatum,
-				colOptionDatum,
 				optionDatum;
 	oidvector  *indclass;
-	int2vector *indcoloptions;
 	bool		isnull;
 	List	   *indexColNames = NIL;
 	List	   *indexExprs = NIL;
@@ -1247,11 +1238,6 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, const char
 	Assert(!isnull);
 	indclass = (oidvector *) DatumGetPointer(indclassDatum);
 
-	colOptionDatum = SysCacheGetAttr(INDEXRELID, indexTuple,
-									 Anum_pg_index_indoption, &isnull);
-	Assert(!isnull);
-	indcoloptions = (int2vector *) DatumGetPointer(colOptionDatum);
-
 	/* Fetch options of index if any */
 	classTuple = SearchSysCache1(RELOID, oldIndexId);
 	if (!HeapTupleIsValid(classTuple))
@@ -1339,7 +1325,6 @@ index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, const char
 							  indexRelation->rd_rel->reltablespace,
 							  indexRelation->rd_indcollation,
 							  indclass->values,
-							  indcoloptions->values,
 							  optionDatum,
 							  INDEX_CREATE_SKIP_BUILD | INDEX_CREATE_CONCURRENT,
 							  0,
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index 7290731..5361955 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -142,7 +142,6 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
 	IndexInfo  *indexInfo;
 	Oid			collationObjectId[2];
 	Oid			classObjectId[2];
-	int16		coloptions[2];
 	ObjectAddress baseobject,
 				toastobject;
 
@@ -320,16 +319,13 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
 	classObjectId[0] = OID_BTREE_OPS_OID;
 	classObjectId[1] = INT4_BTREE_OPS_OID;
 
-	coloptions[0] = 0;
-	coloptions[1] = 0;
-
 	index_create(toast_rel, toast_idxname, toastIndexOid, InvalidOid,
 				 InvalidOid, InvalidOid,
 				 indexInfo,
 				 list_make2("chunk_id", "chunk_seq"),
 				 BTREE_AM_OID,
 				 rel->rd_rel->reltablespace,
-				 collationObjectId, classObjectId, coloptions, (Datum) 0,
+				 collationObjectId, classObjectId, (Datum) 0,
 				 INDEX_CREATE_IS_PRIMARY, 0, true, true, NULL);
 
 	table_close(toast_rel, NoLock);
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 04148e5..1e08100 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -73,7 +73,6 @@ static void ComputeIndexAttrs(IndexInfo *indexInfo,
 							  Oid *typeOidP,
 							  Oid *collationOidP,
 							  Oid *classOidP,
-							  int16 *colOptionP,
 							  List *attList,
 							  List *exclusionOpNames,
 							  Oid relId,
@@ -155,7 +154,6 @@ CheckIndexCompatible(Oid oldId,
 	Form_pg_am	accessMethodForm;
 	IndexAmRoutine *amRoutine;
 	bool		amcanorder;
-	int16	   *coloptions;
 	IndexInfo  *indexInfo;
 	int			numberOfAttributes;
 	int			old_natts;
@@ -208,11 +206,9 @@ CheckIndexCompatible(Oid oldId,
 	typeObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
 	collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
 	classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
-	coloptions = (int16 *) palloc(numberOfAttributes * sizeof(int16));
 	ComputeIndexAttrs(indexInfo,
 					  typeObjectId, collationObjectId, classObjectId,
-					  coloptions, attributeList,
-					  exclusionOpNames, relationId,
+					  attributeList, exclusionOpNames, relationId,
 					  accessMethodName, accessMethodId,
 					  amcanorder, isconstraint);
 
@@ -504,7 +500,6 @@ DefineIndex(Oid relationId,
 	amoptions_function amoptions;
 	bool		partitioned;
 	Datum		reloptions;
-	int16	   *coloptions;
 	IndexInfo  *indexInfo;
 	bits16		flags;
 	bits16		constr_flags;
@@ -834,11 +829,9 @@ DefineIndex(Oid relationId,
 	typeObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
 	collationObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
 	classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
-	coloptions = (int16 *) palloc(numberOfAttributes * sizeof(int16));
 	ComputeIndexAttrs(indexInfo,
 					  typeObjectId, collationObjectId, classObjectId,
-					  coloptions, allIndexParams,
-					  stmt->excludeOpNames, relationId,
+					  allIndexParams, stmt->excludeOpNames, relationId,
 					  accessMethodName, accessMethodId,
 					  amcanorder, stmt->isconstraint);
 
@@ -1036,7 +1029,7 @@ DefineIndex(Oid relationId,
 					 stmt->oldNode, indexInfo, indexColNames,
 					 accessMethodId, tablespaceId,
 					 collationObjectId, classObjectId,
-					 coloptions, reloptions,
+					 reloptions,
 					 flags, constr_flags,
 					 allowSystemTableMods, !check_rights,
 					 &createdConstraintId);
@@ -1566,7 +1559,6 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
 				  Oid *typeOidP,
 				  Oid *collationOidP,
 				  Oid *classOidP,
-				  int16 *colOptionP,
 				  List *attList,	/* list of IndexElem's */
 				  List *exclusionOpNames,
 				  Oid relId,
@@ -1714,7 +1706,6 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
 						 errmsg("including column does not support NULLS FIRST/LAST options")));
 
 			classOidP[attn] = InvalidOid;
-			colOptionP[attn] = 0;
 			collationOidP[attn] = InvalidOid;
 			attn++;
 
@@ -1829,22 +1820,7 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
 		 * zero for any un-ordered index, while ordered indexes have DESC and
 		 * NULLS FIRST/LAST options.
 		 */
-		colOptionP[attn] = 0;
-		if (amcanorder)
-		{
-			/* default ordering is ASC */
-			if (attribute->ordering == SORTBY_DESC)
-				colOptionP[attn] |= INDOPTION_DESC;
-			/* default null ordering is LAST for ASC, FIRST for DESC */
-			if (attribute->nulls_ordering == SORTBY_NULLS_DEFAULT)
-			{
-				if (attribute->ordering == SORTBY_DESC)
-					colOptionP[attn] |= INDOPTION_NULLS_FIRST;
-			}
-			else if (attribute->nulls_ordering == SORTBY_NULLS_FIRST)
-				colOptionP[attn] |= INDOPTION_NULLS_FIRST;
-		}
-		else
+		if (!amcanorder)
 		{
 			/* index AM does not support ordering */
 			if (attribute->ordering != SORTBY_DEFAULT)
@@ -1859,6 +1835,25 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
 								accessMethodName)));
 		}
 
+		if (attribute->ordering == SORTBY_DESC)
+		{
+			attribute->opclassopts =
+				lappend(attribute->opclassopts,
+						makeDefElem(INDOPTION_DESC, NULL, -1));
+
+			if (attribute->nulls_ordering == SORTBY_NULLS_LAST)
+				attribute->opclassopts =
+					lappend(attribute->opclassopts,
+							makeDefElem(INDOPTION_NULLS_FIRST,
+										(Node *) makeString("false"), -1));
+		}
+		else if (attribute->nulls_ordering == SORTBY_NULLS_FIRST)
+		{
+			attribute->opclassopts =
+				lappend(attribute->opclassopts,
+						makeDefElem(INDOPTION_NULLS_FIRST, NULL, -1));
+		}
+
 		/* Set up the per-column opclass options (attoptions field). */
 		if (attribute->opclassopts)
 		{
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index de9b6f4..6845079 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -299,10 +299,12 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
 
 				for (i = 0; i < nkeycolumns; i++)
 				{
-					int16		opt = indexRelation->rd_indoption[i];
+					OrderedAttOptions *opt = (OrderedAttOptions *) info->opclassoptions[i];
 
-					info->reverse_sort[i] = (opt & INDOPTION_DESC) != 0;
-					info->nulls_first[i] = (opt & INDOPTION_NULLS_FIRST) != 0;
+					Assert(opt);
+
+					info->reverse_sort[i] = opt->desc;
+					info->nulls_first[i] = opt->nulls_first;
 				}
 			}
 			else if (amroutine->amcanorder)
@@ -327,14 +329,16 @@ get_relation_info(PlannerInfo *root, Oid relationObjectId, bool inhparent,
 
 				for (i = 0; i < nkeycolumns; i++)
 				{
-					int16		opt = indexRelation->rd_indoption[i];
+					OrderedAttOptions *opt = (OrderedAttOptions *) info->opclassoptions[i];
 					Oid			ltopr;
 					Oid			btopfamily;
 					Oid			btopcintype;
 					int16		btstrategy;
 
-					info->reverse_sort[i] = (opt & INDOPTION_DESC) != 0;
-					info->nulls_first[i] = (opt & INDOPTION_NULLS_FIRST) != 0;
+					Assert(opt);
+
+					info->reverse_sort[i] = opt->desc;
+					info->nulls_first[i] = opt->nulls_first;
 
 					ltopr = get_opfamily_member(info->opfamily[i],
 												info->opcintype[i],
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 5872376..8badc74 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -1523,7 +1523,6 @@ generateClonedIndexStmt(RangeVar *heapRel, Relation source_idx,
 		AttrNumber	attnum = idxrec->indkey.values[keyno];
 		Form_pg_attribute attr = TupleDescAttr(RelationGetDescr(source_idx),
 											   keyno);
-		int16		opt = source_idx->rd_indoption[keyno];
 
 		iparam = makeNode(IndexElem);
 
@@ -1583,28 +1582,6 @@ generateClonedIndexStmt(RangeVar *heapRel, Relation source_idx,
 		iparam->ordering = SORTBY_DEFAULT;
 		iparam->nulls_ordering = SORTBY_NULLS_DEFAULT;
 
-		/* Adjust options if necessary */
-		if (source_idx->rd_indam->amcanorder)
-		{
-			/*
-			 * If it supports sort ordering, copy DESC and NULLS opts. Don't
-			 * set non-default settings unnecessarily, though, so as to
-			 * improve the chance of recognizing equivalence to constraint
-			 * indexes.
-			 */
-			if (opt & INDOPTION_DESC)
-			{
-				iparam->ordering = SORTBY_DESC;
-				if ((opt & INDOPTION_NULLS_FIRST) == 0)
-					iparam->nulls_ordering = SORTBY_NULLS_LAST;
-			}
-			else
-			{
-				if (opt & INDOPTION_NULLS_FIRST)
-					iparam->nulls_ordering = SORTBY_NULLS_FIRST;
-			}
-		}
-
 		index->indexParams = lappend(index->indexParams, iparam);
 	}
 
@@ -2161,8 +2138,7 @@ transformIndexConstraint(Constraint *constraint, CreateStmtContext *cxt)
 				defopclass = GetDefaultOpClass(attform->atttypid,
 											   index_rel->rd_rel->relam);
 				if (indclass->values[i] != defopclass ||
-					attoptions != (Datum) 0 ||
-					index_rel->rd_indoption[i] != 0)
+					attoptions != (Datum) 0)
 					ereport(ERROR,
 							(errcode(ERRCODE_WRONG_OBJECT_TYPE),
 							 errmsg("index \"%s\" column number %d does not have default sorting behavior", index_name, i + 1),
diff --git a/src/backend/utils/adt/amutils.c b/src/backend/utils/adt/amutils.c
index e81d6cc..932f60c 100644
--- a/src/backend/utils/adt/amutils.c
+++ b/src/backend/utils/adt/amutils.c
@@ -15,9 +15,11 @@
 
 #include "access/amapi.h"
 #include "access/htup_details.h"
+#include "access/reloptions.h"
 #include "catalog/pg_class.h"
 #include "catalog/pg_index.h"
 #include "utils/builtins.h"
+#include "utils/lsyscache.h"
 #include "utils/syscache.h"
 
 
@@ -114,14 +116,11 @@ lookup_prop_name(const char *name)
  * otherwise sets *res to the boolean value to return.
  */
 static bool
-test_indoption(HeapTuple tuple, int attno, bool guard,
-			   int16 iopt_mask, int16 iopt_expect,
-			   bool *res)
+test_indoption(Oid indexrelid, int attno, bool guard,
+			   int offset, bool expect, bool *res)
 {
-	Datum		datum;
-	bool		isnull;
-	int2vector *indoption;
-	int16		indoption_val;
+	OrderedAttOptions *ordopts;
+	Datum		relopts;
 
 	if (!guard)
 	{
@@ -129,14 +128,14 @@ test_indoption(HeapTuple tuple, int attno, bool guard,
 		return true;
 	}
 
-	datum = SysCacheGetAttr(INDEXRELID, tuple,
-							Anum_pg_index_indoption, &isnull);
-	Assert(!isnull);
+	relopts = get_attoptions(indexrelid, attno);
+	ordopts = get_ordered_attoptions(relopts);
 
-	indoption = ((int2vector *) DatumGetPointer(datum));
-	indoption_val = indoption->values[attno - 1];
+	*res = *((bool *)((char *) ordopts + offset)) == expect;
 
-	*res = (indoption_val & iopt_mask) == iopt_expect;
+	pfree(ordopts);
+	if (relopts != (Datum) 0)
+		pfree(DatumGetPointer(relopts));
 
 	return true;
 }
@@ -249,29 +248,33 @@ indexam_property(FunctionCallInfo fcinfo,
 		{
 			case AMPROP_ASC:
 				if (iskey &&
-					test_indoption(tuple, attno, routine->amcanorder,
-								   INDOPTION_DESC, 0, &res))
+					test_indoption(index_oid, attno, routine->amcanorder,
+								   offsetof(OrderedAttOptions, desc), false,
+								   &res))
 					isnull = false;
 				break;
 
 			case AMPROP_DESC:
 				if (iskey &&
-					test_indoption(tuple, attno, routine->amcanorder,
-								   INDOPTION_DESC, INDOPTION_DESC, &res))
+					test_indoption(index_oid, attno, routine->amcanorder,
+								   offsetof(OrderedAttOptions, desc), true,
+								   &res))
 					isnull = false;
 				break;
 
 			case AMPROP_NULLS_FIRST:
 				if (iskey &&
-					test_indoption(tuple, attno, routine->amcanorder,
-								   INDOPTION_NULLS_FIRST, INDOPTION_NULLS_FIRST, &res))
+					test_indoption(index_oid, attno, routine->amcanorder,
+								   offsetof(OrderedAttOptions, nulls_first),
+								   true, &res))
 					isnull = false;
 				break;
 
 			case AMPROP_NULLS_LAST:
 				if (iskey &&
-					test_indoption(tuple, attno, routine->amcanorder,
-								   INDOPTION_NULLS_FIRST, 0, &res))
+					test_indoption(index_oid, attno, routine->amcanorder,
+								   offsetof(OrderedAttOptions, nulls_first),
+								   false, &res))
 					isnull = false;
 				break;
 
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index faecf04..a649e4b 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -22,6 +22,7 @@
 #include "access/amapi.h"
 #include "access/htup_details.h"
 #include "access/relation.h"
+#include "access/reloptions.h"
 #include "access/sysattr.h"
 #include "access/table.h"
 #include "catalog/dependency.h"
@@ -469,7 +470,7 @@ static void add_cast_to(StringInfo buf, Oid typid);
 static char *generate_qualified_type_name(Oid typid);
 static text *string_to_text(char *str);
 static char *flatten_reloptions(Oid relid);
-static void get_reloptions(StringInfo buf, Datum reloptions);
+static int get_reloptions(StringInfo buf, Datum reloptions, bool skip_ord_opts);
 
 #define only_marker(rte)  ((rte)->inh ? "" : "ONLY ")
 
@@ -1194,11 +1195,9 @@ pg_get_indexdef_worker(Oid indexrelid, int colno,
 	int			keyno;
 	Datum		indcollDatum;
 	Datum		indclassDatum;
-	Datum		indoptionDatum;
 	bool		isnull;
 	oidvector  *indcollation;
 	oidvector  *indclass;
-	int2vector *indoption;
 	StringInfoData buf;
 	char	   *str;
 	char	   *sep;
@@ -1218,7 +1217,7 @@ pg_get_indexdef_worker(Oid indexrelid, int colno,
 	indrelid = idxrec->indrelid;
 	Assert(indexrelid == idxrec->indexrelid);
 
-	/* Must get indcollation, indclass, and indoption the hard way */
+	/* Must get indcollation and indclass the hard way */
 	indcollDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
 								   Anum_pg_index_indcollation, &isnull);
 	Assert(!isnull);
@@ -1229,11 +1228,6 @@ pg_get_indexdef_worker(Oid indexrelid, int colno,
 	Assert(!isnull);
 	indclass = (oidvector *) DatumGetPointer(indclassDatum);
 
-	indoptionDatum = SysCacheGetAttr(INDEXRELID, ht_idx,
-									 Anum_pg_index_indoption, &isnull);
-	Assert(!isnull);
-	indoption = (int2vector *) DatumGetPointer(indoptionDatum);
-
 	/*
 	 * Fetch the pg_class tuple of the index relation
 	 */
@@ -1370,7 +1364,6 @@ pg_get_indexdef_worker(Oid indexrelid, int colno,
 		if (!attrsOnly && keyno < idxrec->indnkeyatts &&
 			(!colno || colno == keyno + 1))
 		{
-			int16		opt = indoption->values[keyno];
 			Oid			indcoll = indcollation->values[keyno];
 			Datum		attoptions = get_attoptions(indexrelid, keyno + 1);
 			bool		has_options = attoptions != (Datum) 0;
@@ -1384,27 +1377,32 @@ pg_get_indexdef_worker(Oid indexrelid, int colno,
 			get_opclass_name(indclass->values[keyno],
 							 has_options ? InvalidOid : keycoltype, &buf);
 
-			if (has_options)
+			if (has_options)	/* FIXME default opclass */
 			{
 				appendStringInfoString(&buf, " (");
-				get_reloptions(&buf, attoptions);
-				appendStringInfoChar(&buf, ')');
+				if (get_reloptions(&buf, attoptions, amroutine->amcanorder) > 0)
+					appendStringInfoChar(&buf, ')');
+				else
+					buf.len -= 2;
 			}
 
 			/* Add options if relevant */
-			if (amroutine->amcanorder)
+			if (amroutine->amcanorder && has_options)
 			{
+				OrderedAttOptions *ordopts =
+					get_ordered_attoptions(attoptions);
+
 				/* if it supports sort ordering, report DESC and NULLS opts */
-				if (opt & INDOPTION_DESC)
+				if (ordopts->desc)
 				{
 					appendStringInfoString(&buf, " DESC");
 					/* NULLS FIRST is the default in this case */
-					if (!(opt & INDOPTION_NULLS_FIRST))
+					if (!ordopts->nulls_first)
 						appendStringInfoString(&buf, " NULLS LAST");
 				}
 				else
 				{
-					if (opt & INDOPTION_NULLS_FIRST)
+					if (ordopts->nulls_first)
 						appendStringInfoString(&buf, " NULLS FIRST");
 				}
 			}
@@ -11213,18 +11211,19 @@ string_to_text(char *str)
 /*
  * Generate a C string representing a relation options from text[] datum.
  */
-static void
-get_reloptions(StringInfo buf, Datum reloptions)
+static int
+get_reloptions(StringInfo buf, Datum reloptions, bool skip_ord_opts)
 {
 	Datum	   *options;
 	int			noptions;
 	int			i;
+	int			j;
 
 	deconstruct_array(DatumGetArrayTypeP(reloptions),
 					  TEXTOID, -1, false, 'i',
 					  &options, NULL, &noptions);
 
-	for (i = 0; i < noptions; i++)
+	for (i = j = 0; i < noptions; i++)
 	{
 		char	   *option = TextDatumGetCString(options[i]);
 		char	   *name;
@@ -11245,7 +11244,15 @@ get_reloptions(StringInfo buf, Datum reloptions)
 		else
 			value = "";
 
-		if (i > 0)
+		if (skip_ord_opts &&
+			(!strcmp(name, INDOPTION_DESC) ||
+			 !strcmp(name, INDOPTION_NULLS_FIRST)))
+		{
+			pfree(option);
+			continue;
+		}
+
+		if (j++ > 0)
 			appendStringInfoString(buf, ", ");
 		appendStringInfo(buf, "%s=", quote_identifier(name));
 
@@ -11264,6 +11271,8 @@ get_reloptions(StringInfo buf, Datum reloptions)
 
 		pfree(option);
 	}
+
+	return j;
 }
 
 /*
@@ -11288,7 +11297,7 @@ flatten_reloptions(Oid relid)
 		StringInfoData buf;
 
 		initStringInfo(&buf);
-		get_reloptions(&buf, reloptions);
+		get_reloptions(&buf, reloptions, false);
 
 		result = buf.data;
 	}
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index d36b31b..ee32087 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -1365,11 +1365,9 @@ RelationInitIndexAccessInfo(Relation relation)
 	Form_pg_am	aform;
 	Datum		indcollDatum;
 	Datum		indclassDatum;
-	Datum		indoptionDatum;
 	bool		isnull;
 	oidvector  *indcoll;
 	oidvector  *indclass;
-	int2vector *indoption;
 	MemoryContext indexcxt;
 	MemoryContext oldcontext;
 	int			indnatts;
@@ -1454,9 +1452,6 @@ RelationInitIndexAccessInfo(Relation relation)
 	relation->rd_indcollation = (Oid *)
 		MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
 
-	relation->rd_indoption = (int16 *)
-		MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(int16));
-
 	/*
 	 * indcollation cannot be referenced directly through the C struct,
 	 * because it comes after the variable-width indkey field.  Must extract
@@ -1491,17 +1486,6 @@ RelationInitIndexAccessInfo(Relation relation)
 						   relation->rd_opfamily, relation->rd_opcintype,
 						   amsupport, indnkeyatts);
 
-	/*
-	 * Similarly extract indoption and copy it to the cache entry
-	 */
-	indoptionDatum = fastgetattr(relation->rd_indextuple,
-								 Anum_pg_index_indoption,
-								 GetPgIndexDescriptor(),
-								 &isnull);
-	Assert(!isnull);
-	indoption = (int2vector *) DatumGetPointer(indoptionDatum);
-	memcpy(relation->rd_indoption, indoption->values, indnkeyatts * sizeof(int16));
-
 #if 0
 	(void) RelationGetIndexAttOptions(relation, false);
 #endif
@@ -5232,6 +5216,14 @@ RelationGetIndexAttOptions(Relation relation, bool copy)
 			if (attoptions != (Datum) 0)
 				pfree(DatumGetPointer(attoptions));
 		}
+		else
+		{
+			OrderedAttOptions *opt = palloc0(sizeof(*opt));
+
+			SET_VARSIZE(opt, sizeof(*opt));
+
+			opts[i] = (bytea *) opt;
+		}
 	}
 
 	/* Copy parsed options to the cache. */
@@ -5527,7 +5519,6 @@ load_relcache_init_file(bool shared)
 			Oid		   *opcintype;
 			RegProcedure *support;
 			int			nsupport;
-			int16	   *indoption;
 			Oid		   *indcollation;
 
 			/* Count nailed indexes to ensure we have 'em all */
@@ -5604,16 +5595,6 @@ load_relcache_init_file(bool shared)
 
 			rel->rd_indcollation = indcollation;
 
-			/* finally, read the vector of indoption values */
-			if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
-				goto read_failed;
-
-			indoption = (int16 *) MemoryContextAlloc(indexcxt, len);
-			if (fread(indoption, 1, len, fp) != len)
-				goto read_failed;
-
-			rel->rd_indoption = indoption;
-
 #if 0
 			/* finally, read the vector of opcoptions values */
 			rel->rd_opcoptions = (bytea **)
@@ -5659,7 +5640,6 @@ load_relcache_init_file(bool shared)
 			Assert(rel->rd_opcintype == NULL);
 			Assert(rel->rd_support == NULL);
 			Assert(rel->rd_supportinfo == NULL);
-			Assert(rel->rd_indoption == NULL);
 			Assert(rel->rd_indcollation == NULL);
 			Assert(rel->rd_opcoptions == NULL);
 		}
@@ -5944,11 +5924,6 @@ write_relcache_init_file(bool shared)
 					   relform->relnatts * sizeof(Oid),
 					   fp);
 
-			/* finally, write the vector of indoption values */
-			write_item(rel->rd_indoption,
-					   relform->relnatts * sizeof(int16),
-					   fp);
-
 #if 0
 			Assert(rel->rd_opcoptions);
 
diff --git a/src/include/access/genam.h b/src/include/access/genam.h
index 778d17c..322577d 100644
--- a/src/include/access/genam.h
+++ b/src/include/access/genam.h
@@ -117,6 +117,13 @@ typedef enum IndexUniqueCheck
 	UNIQUE_CHECK_EXISTING		/* Check if existing tuple is unique */
 } IndexUniqueCheck;
 
+/* Common attribute options for ordered indexes */
+typedef struct OrderedAttOptions
+{
+	int32		vl_len_;		/* varlena header (do not touch directly!) */
+	bool		desc;			/* DESCending ordering */
+	bool		nulls_first;	/* NULLS FIRST/LAST */
+} OrderedAttOptions;
 
 /*
  * generalized index_ interface routines (in indexam.c)
diff --git a/src/include/access/nbtree.h b/src/include/access/nbtree.h
index 52eafe6..6901d6e 100644
--- a/src/include/access/nbtree.h
+++ b/src/include/access/nbtree.h
@@ -672,13 +672,12 @@ typedef BTScanOpaqueData *BTScanOpaque;
 /*
  * We use some private sk_flags bits in preprocessed scan keys.  We're allowed
  * to use bits 16-31 (see skey.h).  The uppermost bits are copied from the
- * index's indoption[] array entry for the index attribute.
+ * index's attoptions for the index attribute.
  */
-#define SK_BT_REQFWD	0x00010000	/* required to continue forward scan */
-#define SK_BT_REQBKWD	0x00020000	/* required to continue backward scan */
-#define SK_BT_INDOPTION_SHIFT  24	/* must clear the above bits */
-#define SK_BT_DESC			(INDOPTION_DESC << SK_BT_INDOPTION_SHIFT)
-#define SK_BT_NULLS_FIRST	(INDOPTION_NULLS_FIRST << SK_BT_INDOPTION_SHIFT)
+#define SK_BT_REQFWD		0x00010000	/* required to continue forward scan */
+#define SK_BT_REQBKWD		0x00020000	/* required to continue backward scan */
+#define SK_BT_DESC			0x00040000
+#define SK_BT_NULLS_FIRST	0x00080000
 
 /*
  * Constant definition for progress reporting.  Phase numbers must match
diff --git a/src/include/access/reloptions.h b/src/include/access/reloptions.h
index 70238f9..5592da5 100644
--- a/src/include/access/reloptions.h
+++ b/src/include/access/reloptions.h
@@ -316,4 +316,7 @@ extern bytea *attribute_reloptions(Datum reloptions, bool validate);
 extern bytea *tablespace_reloptions(Datum reloptions, bool validate);
 extern LOCKMODE AlterTableGetRelOptionsLockLevel(List *defList);
 
+extern void ordered_index_attoptions(local_relopts *relopts, int attno);
+extern OrderedAttOptions *get_ordered_attoptions(Datum attoptions);
+
 #endif							/* RELOPTIONS_H */
diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h
index 1113d25..b306882 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -64,7 +64,6 @@ extern Oid	index_create(Relation heapRelation,
 						 Oid tableSpaceId,
 						 Oid *collationObjectId,
 						 Oid *classObjectId,
-						 int16 *coloptions,
 						 Datum reloptions,
 						 bits16 flags,
 						 bits16 constr_flags,
diff --git a/src/include/catalog/pg_index.h b/src/include/catalog/pg_index.h
index 2438374..28cd920 100644
--- a/src/include/catalog/pg_index.h
+++ b/src/include/catalog/pg_index.h
@@ -49,7 +49,6 @@ CATALOG(pg_index,2610,IndexRelationId) BKI_SCHEMA_MACRO
 #ifdef CATALOG_VARLEN
 	oidvector	indcollation;	/* collation identifiers */
 	oidvector	indclass;		/* opclass identifiers */
-	int2vector	indoption;		/* per-column flags (AM-specific meanings) */
 	pg_node_tree indexprs;		/* expression trees for index attributes that
 								 * are not simple column references; one for
 								 * each zero entry in indkey[] */
@@ -68,12 +67,10 @@ typedef FormData_pg_index *Form_pg_index;
 #ifdef EXPOSE_TO_CLIENT_CODE
 
 /*
- * Index AMs that support ordered scans must support these two indoption
- * bits.  Otherwise, the content of the per-column indoption fields is
- * open for future definition.
+ * Index AMs that support ordered scans must support these two reloptions.
  */
-#define INDOPTION_DESC			0x0001	/* values are in reverse order */
-#define INDOPTION_NULLS_FIRST	0x0002	/* NULLs are first instead of last */
+#define INDOPTION_DESC			"desc"			/* values are in reverse order */
+#define INDOPTION_NULLS_FIRST	"nulls_first"	/* NULLs are first instead of last */
 
 #endif							/* EXPOSE_TO_CLIENT_CODE */
 
diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h
index 552d9eb..54b3642 100644
--- a/src/include/utils/rel.h
+++ b/src/include/utils/rel.h
@@ -159,7 +159,6 @@ typedef struct RelationData
 	Oid		   *rd_opcintype;	/* OIDs of opclass declared input data types */
 	RegProcedure *rd_support;	/* OIDs of support procedures */
 	struct FmgrInfo *rd_supportinfo; /* lookup info for support procedures */
-	int16	   *rd_indoption;	/* per-column AM-specific flags */
 	List	   *rd_indexprs;	/* index expression trees, if any */
 	List	   *rd_indpred;		/* index predicate tree, if any */
 	Oid		   *rd_exclops;		/* OIDs of exclusion operators, if any */
diff --git a/src/test/regress/expected/btree_index.out b/src/test/regress/expected/btree_index.out
index b4023de..d80d9cd 100644
--- a/src/test/regress/expected/btree_index.out
+++ b/src/test/regress/expected/btree_index.out
@@ -264,6 +264,6 @@ VACUUM delete_test_table;
 INSERT INTO delete_test_table SELECT i, 1, 2, 3 FROM generate_series(1,1000) i;
 -- Test unsupported btree opclass parameters
 create index on btree_tall_tbl (id int4_ops(foo=1));
-ERROR:  operator class int4_ops has no options
+ERROR:  unrecognized parameter "foo"
 create index on btree_tall_tbl (id default(foo=1));
-ERROR:  operator class int4_ops has no options
+ERROR:  unrecognized parameter "foo"
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 1f53a9c..a8329b6 100644
--- a/src/test/regress/expected/opr_sanity.out
+++ b/src/test/regress/expected/opr_sanity.out
@@ -2096,8 +2096,7 @@ SELECT p1.indexrelid, p1.indrelid
 FROM pg_index as p1
 WHERE array_lower(indkey, 1) != 0 OR array_upper(indkey, 1) != indnatts-1 OR
     array_lower(indclass, 1) != 0 OR array_upper(indclass, 1) != indnatts-1 OR
-    array_lower(indcollation, 1) != 0 OR array_upper(indcollation, 1) != indnatts-1 OR
-    array_lower(indoption, 1) != 0 OR array_upper(indoption, 1) != indnatts-1;
+    array_lower(indcollation, 1) != 0 OR array_upper(indcollation, 1) != indnatts-1;
  indexrelid | indrelid 
 ------------+----------
 (0 rows)
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
index cee6a40..7dd42a3 100644
--- a/src/test/regress/sql/opr_sanity.sql
+++ b/src/test/regress/sql/opr_sanity.sql
@@ -1341,8 +1341,7 @@ SELECT p1.indexrelid, p1.indrelid
 FROM pg_index as p1
 WHERE array_lower(indkey, 1) != 0 OR array_upper(indkey, 1) != indnatts-1 OR
     array_lower(indclass, 1) != 0 OR array_upper(indclass, 1) != indnatts-1 OR
-    array_lower(indcollation, 1) != 0 OR array_upper(indcollation, 1) != indnatts-1 OR
-    array_lower(indoption, 1) != 0 OR array_upper(indoption, 1) != indnatts-1;
+    array_lower(indcollation, 1) != 0 OR array_upper(indcollation, 1) != indnatts-1;
 
 -- Check that opclasses and collations match the underlying columns.
 -- (As written, this test ignores expression indexes.)
-- 
2.7.4

