Updated patch. Changes:

  - returns NULL rather than "cache lookup failed"

  - added pg_index_column_has_property (incl. docs)

  - added regression tests

Not changed / need consideration:

  - this still has everything in amapi.c rather than creating any new
    files. Also, the regression tests are in create_index.sql for lack
    of any obviously better place.

The list of column properties is:

  ordered  - (same as "amcanorder" AM capability)
  ordered_asc
  ordered_desc
  ordered_nulls_first
  ordered_nulls_last

If "ordered" is true then exactly one of _asc/_desc and exactly one of
_nulls_first/_last will be true; if "ordered" is false then all the
others will be false too. The intended usage is something like

  CASE WHEN pg_index_column_has_property(idx, attno, 'ordered_asc')
       THEN 'ASC'
       WHEN pg_index_column_has_property(idx, attno, 'ordered_desc')
       THEN 'DESC'
       ELSE ''  -- or NULL
  END

Comments?

-- 
Andrew (irc:RhodiumToad)

diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index ccb9b97..684f7b3 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -577,6 +577,89 @@
    </tgroup>
   </table>
 
+  <para>
+    Capability information formerly stored in <structname>pg_am</structname>
+    is now available via the functions
+    <function>pg_indexam_has_capability</function> and
+    <function>pg_index_has_capability</function>
+    (see <xref linkend="functions-info-catalog-table">). The following
+    boolean-valued capability names are currently supported:
+  </para>
+
+  <table>
+   <title>Capabilities</title>
+
+   <tgroup cols="2">
+    <thead>
+     <row>
+      <entry>Name</entry>
+      <entry>Description</entry>
+     </row>
+    </thead>
+    <tbody>
+     <row>
+      <entry><literal>amcanorder</literal></entry>
+      <entry>Does the access method support ordered scans sorted by the
+       indexed column's value?</entry>
+     </row>
+     <row>
+      <entry><literal>amcanorderbyop</literal></entry>
+      <entry>Does the access method support ordered scans sorted by the result
+       of an operator on the indexed column?</entry>
+     </row>
+     <row>
+      <entry><literal>amcanbackward</literal></entry>
+      <entry>Does the access method support backward scanning?</entry>
+     </row>
+     <row>
+      <entry><literal>amcanunique</literal></entry>
+      <entry>Does the access method support unique indexes?</entry>
+     </row>
+     <row>
+      <entry><literal>amcanmulticol</literal></entry>
+      <entry>Does the access method support multicolumn indexes?</entry>
+     </row>
+     <row>
+      <entry><literal>amoptionalkey</literal></entry>
+      <entry>Does the access method support a scan without any constraint
+       for the first index column?</entry>
+     </row>
+     <row>
+      <entry><literal>amsearcharray</literal></entry>
+      <entry>Does the access method support <literal>ScalarArrayOpExpr</> searches?</entry>
+     </row>
+     <row>
+      <entry><literal>amsearchnulls</literal></entry>
+      <entry>Does the access method support <literal>IS NULL</>/<literal>NOT NULL</> searches?</entry>
+     </row>
+     <row>
+      <entry><literal>amstorage</literal></entry>
+      <entry>Can index storage data type differ from column data type?</entry>
+     </row>
+     <row>
+      <entry><literal>amclusterable</literal></entry>
+      <entry>Can an index of this type be clustered on?</entry>
+     </row>
+     <row>
+      <entry><literal>ampredlocks</literal></entry>
+      <entry>Does an index of this type manage fine-grained predicate locks?</entry>
+     </row>
+     <row>
+      <entry><literal>amgettuple</literal></entry>
+      <entry>Does the access method provide an <function>amgettuple</function> function?</entry>
+     </row>
+     <row>
+      <entry><literal>amgetbitmap</literal></entry>
+      <entry>Does the access method provide an <function>amgetbitmap</function> function?</entry>
+     </row>
+     <row>
+      <entry><literal>amcanreturn</literal></entry>
+      <entry>Does the access method support index-only scans?</entry>
+     </row>
+    </tbody>
+   </tgroup>
+  </table>
+
  </sect1>
 
 
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 7830334..d2fe506 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -16290,6 +16290,18 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
    </indexterm>
 
    <indexterm>
+    <primary>pg_indexam_has_capability</primary>
+   </indexterm>
+
+   <indexterm>
+    <primary>pg_index_column_has_property</primary>
+   </indexterm>
+
+   <indexterm>
+    <primary>pg_index_has_capability</primary>
+   </indexterm>
+
+   <indexterm>
     <primary>pg_options_to_table</primary>
    </indexterm>
 
@@ -16477,6 +16489,21 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
               number of columns, pretty-printing is implied</entry>
       </row>
       <row>
+       <entry><literal><function>pg_indexam_has_capability(<parameter>am_oid</parameter>, <parameter>cap_name</>)</function></literal></entry>
+       <entry><type>boolean</type></entry>
+       <entry>Test whether an index access method has a specified capability</entry>
+      </row>
+      <row>
+       <entry><literal><function>pg_index_column_has_property(<parameter>index_oid</parameter>, <parameter>column_no</>, <parameter>prop_name</>)</function></literal></entry>
+       <entry><type>boolean</type></entry>
+       <entry>Test whether an index column has a specified property</entry>
+      </row>
+      <row>
+       <entry><literal><function>pg_index_has_capability(<parameter>index_oid</parameter>, <parameter>cap_name</>)</function></literal></entry>
+       <entry><type>boolean</type></entry>
+       <entry>Test whether the access method for the specified index has a specified capability</entry>
+      </row>
+      <row>
        <entry><literal><function>pg_options_to_table(<parameter>reloptions</parameter>)</function></literal></entry>
        <entry><type>setof record</type></entry>
        <entry>get the set of storage option name/value pairs</entry>
@@ -16620,6 +16647,73 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
   </para>
 
   <para>
+   <function>pg_indexam_has_capability</function> and
+   <function>pg_index_has_capability</function> return whether the specified
+   access method, or the access method for the specified index, advertises the
+   named capability. <literal>NULL</literal> is returned if the capability
+   name is not known; <literal>true</literal> if the capability is advertised,
+   <literal>false</literal> if it is not. Refer
+   to <xref linkend="catalog-pg-am"> for capability names and their meanings.
+  </para>
+
+  <para>
+   <function>pg_index_column_has_property</function> returns whether the
+   specified index column possesses the named property.
+   <literal>NULL</literal> is returned if the property name is not
+   known; <literal>true</literal> if the property is present,
+   <literal>false</literal> if it is not. Index column property names and the
+   matching clauses of <literal>CREATE INDEX</> are given in
+   <xref linkend="functions-info-index-column-props">.
+  </para>
+
+  <table id="functions-info-index-column-props">
+   <title>Index Column Properties</title>
+
+   <tgroup cols="3">
+    <thead>
+     <row>
+      <entry>Name</entry>
+      <entry>Clause</entry>
+      <entry>Description</entry>
+     </row>
+    </thead>
+    <tbody>
+     <row>
+      <entry><literal>ordered</literal></entry>
+      <entry></entry>
+      <entry>Does the access method support ordered scans sorted by the
+       column's value?</entry>
+     </row>
+     <row>
+      <entry><literal>ordered_asc</literal></entry>
+      <entry><literal>ASC</></entry>
+      <entry>Does the column sort in ascending order on a forward scan?
+      </entry>
+     </row>
+     <row>
+      <entry><literal>ordered_desc</literal></entry>
+      <entry><literal>DESC</></entry>
+      <entry>Does the column sort in descending order on a forward scan?
+      </entry>
+     </row>
+     <row>
+      <entry><literal>ordered_nulls_first</literal></entry>
+      <entry><literal>NULLS FIRST</></entry>
+      <entry>Does the column sort with nulls first on a forward scan?
+      </entry>
+     </row>
+     <row>
+      <entry><literal>ordered_nulls_last</literal></entry>
+      <entry><literal>NULLS LAST</></entry>
+      <entry>Does the column sort with nulls last on a forward scan?
+      </entry>
+     </row>
+
+    </tbody>
+   </tgroup>
+  </table>
+
+  <para>
    <function>pg_options_to_table</function> returns the set of storage
    option name/value pairs
    (<literal>option_name</>/<literal>option_value</>) when passed
diff --git a/src/backend/access/index/amapi.c b/src/backend/access/index/amapi.c
index d347ebc..8f9eb6b 100644
--- a/src/backend/access/index/amapi.c
+++ b/src/backend/access/index/amapi.c
@@ -16,7 +16,10 @@
 #include "access/amapi.h"
 #include "access/htup_details.h"
 #include "catalog/pg_am.h"
+#include "catalog/pg_class.h"
+#include "catalog/pg_index.h"
 #include "catalog/pg_opclass.h"
+#include "utils/elog.h"
 #include "utils/syscache.h"
 
 
@@ -119,3 +122,180 @@ amvalidate(PG_FUNCTION_ARGS)
 
 	PG_RETURN_BOOL(result);
 }
+
+
+/*
+ * Test capabilities of an index or index AM.
+ */
+static Datum
+indexam_capability(FunctionCallInfo fcinfo,
+				   Oid amoid, char *nameptr, int namelen)
+{
+	IndexAmRoutine *routine = NULL;
+	bool		ret;
+
+	if (namelen < 1 || namelen > 14)
+		PG_RETURN_NULL();
+
+	routine = GetIndexAmRoutineByAmId(amoid);
+
+	if (namelen == 10 && memcmp(nameptr, "amcanorder", 10) == 0)
+		ret = (routine->amcanorder) ? true : false;
+	else if (namelen == 14 && memcmp(nameptr, "amcanorderbyop", 14) == 0)
+		ret = (routine->amcanorderbyop) ? true : false;
+	else if (namelen == 13 && memcmp(nameptr, "amcanbackward", 13) == 0)
+		ret = (routine->amcanbackward) ? true : false;
+	else if (namelen == 11 && memcmp(nameptr, "amcanunique", 11) == 0)
+		ret = (routine->amcanunique) ? true : false;
+	else if (namelen == 13 && memcmp(nameptr, "amcanmulticol", 13) == 0)
+		ret = (routine->amcanmulticol) ? true : false;
+	else if (namelen == 13 && memcmp(nameptr, "amoptionalkey", 13) == 0)
+		ret = (routine->amoptionalkey) ? true : false;
+	else if (namelen == 13 && memcmp(nameptr, "amsearcharray", 13) == 0)
+		ret = (routine->amsearcharray) ? true : false;
+	else if (namelen == 13 && memcmp(nameptr, "amsearchnulls", 13) == 0)
+		ret = (routine->amsearchnulls) ? true : false;
+	else if (namelen == 9 && memcmp(nameptr, "amstorage", 9) == 0)
+		ret = (routine->amstorage) ? true : false;
+	else if (namelen == 13 && memcmp(nameptr, "amclusterable", 13) == 0)
+		ret = (routine->amclusterable) ? true : false;
+	else if (namelen == 11 && memcmp(nameptr, "ampredlocks", 11) == 0)
+		ret = (routine->ampredlocks) ? true : false;
+	else if (namelen == 11 && memcmp(nameptr, "amcanreturn", 11) == 0)
+		ret = (routine->amcanreturn) ? true : false;
+	else if (namelen == 10 && memcmp(nameptr, "amgettuple", 10) == 0)
+		ret = (routine->amgettuple) ? true : false;
+	else if (namelen == 11 && memcmp(nameptr, "amgetbitmap", 11) == 0)
+		ret = (routine->amgetbitmap) ? true : false;
+	else
+		PG_RETURN_NULL();
+
+	PG_RETURN_BOOL(ret);
+}
+
+/*
+ * Test capability of an AM specified by the AM Oid.
+ */
+Datum
+pg_indexam_has_capability(PG_FUNCTION_ARGS)
+{
+	Oid			amoid = PG_GETARG_OID(0);
+	text	   *name = PG_GETARG_TEXT_PP(1);
+	char	   *nameptr = VARDATA_ANY(name);
+	int			namelen = VARSIZE_ANY_EXHDR(name);
+
+	return indexam_capability(fcinfo, amoid, nameptr, namelen);
+}
+
+/*
+ * Test capability of the AM for an index specified by relation Oid.
+ */
+Datum
+pg_index_has_capability(PG_FUNCTION_ARGS)
+{
+	Oid			relid = PG_GETARG_OID(0);
+	text	   *name = PG_GETARG_TEXT_PP(1);
+	char	   *nameptr = VARDATA_ANY(name);
+	int			namelen = VARSIZE_ANY_EXHDR(name);
+	Oid			amoid;
+	HeapTuple	tuple;
+	Form_pg_class rd_rel;
+
+	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
+	if (!HeapTupleIsValid(tuple))
+		PG_RETURN_NULL();
+	rd_rel = (Form_pg_class) GETSTRUCT(tuple);
+	if (rd_rel->relkind != RELKIND_INDEX)
+		ereport(ERROR,
+				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+				 errmsg("relation %u is not an index", relid)));
+	amoid = rd_rel->relam;
+	ReleaseSysCache(tuple);
+
+	return indexam_capability(fcinfo, amoid, nameptr, namelen);
+}
+
+/*
+ * Test for index column properties
+ */
+Datum
+pg_index_column_has_property(PG_FUNCTION_ARGS)
+{
+	Oid			relid = PG_GETARG_OID(0);
+	int32		attno = PG_GETARG_INT32(1);
+	text	   *propname = PG_GETARG_TEXT_PP(2);
+	char	   *nameptr = VARDATA_ANY(propname);
+	int			namelen = VARSIZE_ANY_EXHDR(propname);
+	Oid			amoid;
+	HeapTuple	tuple;
+	Form_pg_class rd_rel;
+	Form_pg_index rd_index;
+	int16		natts;
+	Datum		indoptionDatum;
+	bool		isnull = false;
+	int2vector *indoption;
+	int16		indoption_val;
+	int16		iopt_test = 0;
+	int16		iopt_expect = 0;
+	IndexAmRoutine *routine = NULL;
+
+	tuple = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
+	if (!HeapTupleIsValid(tuple))
+		PG_RETURN_NULL();
+	rd_rel = (Form_pg_class) GETSTRUCT(tuple);
+	if (rd_rel->relkind != RELKIND_INDEX)
+		ereport(ERROR,
+				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+				 errmsg("relation %u is not an index", relid)));
+	amoid = rd_rel->relam;
+	natts = rd_rel->relnatts;
+	ReleaseSysCache(tuple);
+
+	if (attno < 1 || attno > natts)
+		PG_RETURN_NULL();
+
+	routine = GetIndexAmRoutineByAmId(amoid);
+
+	/*
+	 * Currently, the only properties of interest are known in the core code,
+	 * but in future it might be appropriate to punt unknown property names to
+	 * a function in the amhandler.
+	 */
+
+	if (namelen == 7 && memcmp(nameptr, "ordered", 7) == 0)
+		PG_RETURN_BOOL(routine->amcanorder);
+	else if (namelen == 11 && memcmp(nameptr, "ordered_asc", 11) == 0)
+		iopt_test = INDOPTION_DESC, iopt_expect = 0;
+	else if (namelen == 12 && memcmp(nameptr, "ordered_desc", 12) == 0)
+		iopt_test = INDOPTION_DESC, iopt_expect = INDOPTION_DESC;
+	else if (namelen == 19 && memcmp(nameptr, "ordered_nulls_first", 19) == 0)
+		iopt_test = INDOPTION_NULLS_FIRST, iopt_expect = INDOPTION_NULLS_FIRST;
+	else if (namelen == 18 && memcmp(nameptr, "ordered_nulls_last", 18) == 0)
+		iopt_test = INDOPTION_NULLS_FIRST, iopt_expect = 0;
+	else
+		PG_RETURN_NULL();
+
+	if (!routine->amcanorder)
+		PG_RETURN_BOOL(false);
+
+	tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(relid));
+	if (!HeapTupleIsValid(tuple))
+		PG_RETURN_NULL();
+	rd_index = (Form_pg_index) GETSTRUCT(tuple);
+
+	Assert(relid == rd_index->indexrelid);
+	Assert(natts == rd_index->indnatts);
+
+	indoptionDatum = SysCacheGetAttr(INDEXRELID, tuple,
+									 Anum_pg_index_indoption, &isnull);
+	Assert(!isnull);
+
+	indoption = ((int2vector *) DatumGetPointer(indoptionDatum));
+	indoption_val = indoption->values[attno - 1];
+	ReleaseSysCache(tuple);
+
+	if ((indoption_val & iopt_test) == iopt_expect)
+		PG_RETURN_BOOL(true);
+	else
+		PG_RETURN_BOOL(false);
+}
diff --git a/src/include/access/amapi.h b/src/include/access/amapi.h
index 35f1061..af4e195 100644
--- a/src/include/access/amapi.h
+++ b/src/include/access/amapi.h
@@ -171,4 +171,8 @@ extern IndexAmRoutine *GetIndexAmRoutineByAmId(Oid amoid);
 
 extern Datum amvalidate(PG_FUNCTION_ARGS);
 
+extern Datum pg_indexam_has_capability(PG_FUNCTION_ARGS);
+extern Datum pg_index_has_capability(PG_FUNCTION_ARGS);
+extern Datum pg_index_column_has_property(PG_FUNCTION_ARGS);
+
 #endif   /* AMAPI_H */
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 270dd21..0cbaab8 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -564,6 +564,11 @@ DESCR("spgist index access method handler");
 DATA(insert OID = 335 (  brinhandler	PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 325 "2281" _null_ _null_ _null_ _null_ _null_	brinhandler _null_ _null_ _null_ ));
 DESCR("brin index access method handler");
 
+DATA(insert OID = 336 (  pg_indexam_has_capability	PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "26 25" _null_ _null_ _null_ _null_ _null_	pg_indexam_has_capability _null_ _null_ _null_ ));
+DESCR("test capability of an index access method");
+DATA(insert OID = 337 (  pg_index_has_capability	PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 16 "26 25" _null_ _null_ _null_ _null_ _null_	pg_index_has_capability _null_ _null_ _null_ ));
+DESCR("test capability of an index");
+
 DATA(insert OID = 338 (  amvalidate		PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 16 "26" _null_ _null_ _null_ _null_ _null_	amvalidate _null_ _null_ _null_ ));
 DESCR("validate an operator class");
 DATA(insert OID = 3952 (  brin_summarize_new_values PGNSP PGUID 12 1 0 0 0 f f f f t f v s 1 0 23 "2205" _null_ _null_ _null_ _null_ _null_ brin_summarize_new_values _null_ _null_ _null_ ));
@@ -1988,6 +1993,9 @@ DESCR("result type of a function");
 DATA(insert OID = 3808 (  pg_get_function_arg_default	PGNSP PGUID 12 1 0 0 0 f f f f t f s s 2 0 25 "26 23" _null_ _null_ _null_ _null_ _null_ pg_get_function_arg_default _null_ _null_ _null_ ));
 DESCR("function argument default");
 
+DATA(insert OID = 4032 (  pg_index_column_has_property   PGNSP PGUID 12 1 0 0 0 f f f f t f s s 3 0 16 "26 23 25" _null_ _null_ _null_ _null_ _null_ pg_index_column_has_property _null_ _null_ _null_ ));
+DESCR("test boolean property of index column");
+
 DATA(insert OID = 1686 (  pg_get_keywords		PGNSP PGUID 12 10 400 0 0 f f f f t t s s 0 0 2249 "" "{25,18,25}" "{o,o,o}" "{word,catcode,catdesc}" _null_ _null_ pg_get_keywords _null_ _null_ _null_ ));
 DESCR("list of SQL keywords");
 
diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out
index 76593e1..d27a5f8 100644
--- a/src/test/regress/expected/create_index.out
+++ b/src/test/regress/expected/create_index.out
@@ -2953,6 +2953,89 @@ explain (costs off)
 (2 rows)
 
 --
+-- pg_index_column_has_property
+--
+CREATE INDEX onek_props1 ON onek (unique1 desc, unique2 asc, ten nulls first, hundred nulls last);
+select i, prop, pg_index_column_has_property(o, i, prop)
+  from (values ('onek_props1'::regclass)) v1(o),
+       (values (1,'ordered'),(2,'ordered_asc'),(3,'ordered_desc'),
+               (4,'ordered_nulls_first'),(5,'ordered_nulls_last')) v2(idx,prop),
+       generate_series(1,4) i
+ order by i, idx;
+ i |        prop         | pg_index_column_has_property 
+---+---------------------+------------------------------
+ 1 | ordered             | t
+ 1 | ordered_asc         | f
+ 1 | ordered_desc        | t
+ 1 | ordered_nulls_first | t
+ 1 | ordered_nulls_last  | f
+ 2 | ordered             | t
+ 2 | ordered_asc         | t
+ 2 | ordered_desc        | f
+ 2 | ordered_nulls_first | f
+ 2 | ordered_nulls_last  | t
+ 3 | ordered             | t
+ 3 | ordered_asc         | t
+ 3 | ordered_desc        | f
+ 3 | ordered_nulls_first | t
+ 3 | ordered_nulls_last  | f
+ 4 | ordered             | t
+ 4 | ordered_asc         | t
+ 4 | ordered_desc        | f
+ 4 | ordered_nulls_first | f
+ 4 | ordered_nulls_last  | t
+(20 rows)
+
+select prop, pg_index_column_has_property(o, 1, prop)
+  from (values ('gcircleind'::regclass)) v1(o),
+       (values (1,'ordered'),(2,'ordered_asc'),(3,'ordered_desc'),
+               (4,'ordered_nulls_first'),(5,'ordered_nulls_last')) v2(idx,prop)
+ order by idx;
+        prop         | pg_index_column_has_property 
+---------------------+------------------------------
+ ordered             | f
+ ordered_asc         | f
+ ordered_desc        | f
+ ordered_nulls_first | f
+ ordered_nulls_last  | f
+(5 rows)
+
+DROP INDEX onek_props1;
+--
+-- index AM capabilites
+--
+select cap,
+       pg_index_has_capability('onek_hundred'::regclass, cap) as btree,
+       pg_index_has_capability('hash_i4_index'::regclass, cap) as hash,
+       pg_index_has_capability('gcircleind'::regclass, cap) as gist,
+       pg_index_has_capability('sp_radix_ind'::regclass, cap) as spgist,
+       pg_index_has_capability('botharrayidx'::regclass, cap) as gin
+  from unnest(array['amcanorder','amcanorderbyop','amcanbackward',
+                    'amcanunique','amcanmulticol','amoptionalkey',
+                    'amsearcharray','amsearchnulls','amstorage',
+                    'amclusterable','ampredlocks','amcanreturn',
+                    'amgettuple','amgetbitmap'
+              ]) with ordinality as u(cap,ord)
+ order by ord;
+      cap       | btree | hash | gist | spgist | gin 
+----------------+-------+------+------+--------+-----
+ amcanorder     | t     | f    | f    | f      | f
+ amcanorderbyop | f     | f    | t    | f      | f
+ amcanbackward  | t     | t    | f    | f      | f
+ amcanunique    | t     | f    | f    | f      | f
+ amcanmulticol  | t     | f    | t    | f      | t
+ amoptionalkey  | t     | f    | t    | t      | t
+ amsearcharray  | t     | f    | f    | f      | f
+ amsearchnulls  | t     | f    | t    | t      | f
+ amstorage      | f     | f    | t    | f      | t
+ amclusterable  | t     | f    | t    | f      | f
+ ampredlocks    | t     | f    | f    | f      | f
+ amcanreturn    | t     | f    | t    | t      | f
+ amgettuple     | t     | t    | t    | t      | f
+ amgetbitmap    | t     | t    | t    | t      | t
+(14 rows)
+
+--
 -- REINDEX (VERBOSE)
 --
 CREATE TABLE reindex_verbose(id integer primary key);
diff --git a/src/test/regress/sql/create_index.sql b/src/test/regress/sql/create_index.sql
index 71f4f54..62c76e5 100644
--- a/src/test/regress/sql/create_index.sql
+++ b/src/test/regress/sql/create_index.sql
@@ -1011,6 +1011,43 @@ explain (costs off)
   select * from tenk1 where (thousand, tenthous) in ((1,1001), (null,null));
 
 --
+-- pg_index_column_has_property
+--
+CREATE INDEX onek_props1 ON onek (unique1 desc, unique2 asc, ten nulls first, hundred nulls last);
+
+select i, prop, pg_index_column_has_property(o, i, prop)
+  from (values ('onek_props1'::regclass)) v1(o),
+       (values (1,'ordered'),(2,'ordered_asc'),(3,'ordered_desc'),
+               (4,'ordered_nulls_first'),(5,'ordered_nulls_last')) v2(idx,prop),
+       generate_series(1,4) i
+ order by i, idx;
+
+select prop, pg_index_column_has_property(o, 1, prop)
+  from (values ('gcircleind'::regclass)) v1(o),
+       (values (1,'ordered'),(2,'ordered_asc'),(3,'ordered_desc'),
+               (4,'ordered_nulls_first'),(5,'ordered_nulls_last')) v2(idx,prop)
+ order by idx;
+
+DROP INDEX onek_props1;
+
+--
+-- index AM capabilites
+--
+select cap,
+       pg_index_has_capability('onek_hundred'::regclass, cap) as btree,
+       pg_index_has_capability('hash_i4_index'::regclass, cap) as hash,
+       pg_index_has_capability('gcircleind'::regclass, cap) as gist,
+       pg_index_has_capability('sp_radix_ind'::regclass, cap) as spgist,
+       pg_index_has_capability('botharrayidx'::regclass, cap) as gin
+  from unnest(array['amcanorder','amcanorderbyop','amcanbackward',
+                    'amcanunique','amcanmulticol','amoptionalkey',
+                    'amsearcharray','amsearchnulls','amstorage',
+                    'amclusterable','ampredlocks','amcanreturn',
+                    'amgettuple','amgetbitmap'
+              ]) with ordinality as u(cap,ord)
+ order by ord;
+
+--
 -- REINDEX (VERBOSE)
 --
 CREATE TABLE reindex_verbose(id integer primary key);
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to