Following issues are solved:

\dAf[+]  [AMPTRN [OPFPTRN]]  list operator families of access method. +
prints owner of operator family. (Table pg_opfamily)

\dAfp    [AMPTRN [OPFPTRN]]  list procedures of operator family related
to access method (Table pg_amproc)

 * Reorder "Left"/"Right" and "Strategy"/"Proc name" columns.
 * Include "Left"/"Right" columns into ORDER BY clause.
* Show procedure's argument types, because procedure's name does not completely identify procedure (for example, in_range() is used in several opclasses with different signatures). Or maybe show arguments only if procedure name is not
   unique?

\dAfo    [AMPTRN [OPFPTRN]]  list operators of family related to access
method (Table pg_amop)

 * Reorder "Left"/"Right" and "Strategy"/"Operator" columns.
 * Include "Left"/"Right" columns into ORDER BY clause.

\dAoc[+] [AMPTRN [OPCPTRN]]  list operator classes of index access
methods. + prints owner of operator class. (Table pg_opclass)

* Maybe it would be better to show stored type only if it differs from the
   indexed type?

\dip[S]  [PATTERN]           list indexes with properties (Table
pg_class)

\dicp[S] [IDXNAME [COLNAME]] show index column properties (Table
pg_class)

 * Fix duplicate rows that appear in the table for composite indices.
 * Include "Column #" into ORDER BY clause.
 * Rename column "Null first" to "Nulls First" or "NULLS LAST".
 * Maybe it is not necessary to show "Access method" column here?
* I think we should show column's properties in the separate table for each
   index, because it is not so easy to understand the combined table.


Following issues require discussion:
\dAp  
* Should we rename it to \dAip and include "index" word into the table header?
   As you know, we are going to support table AMs in the future.

\dAfo
* Operator's schema is shown only if operator is invisible for the current
   user -- I'm not sure if this is correct.
   \dAfo and \dAfp
   * Should we put info in separate table for each Operator family?


\dicp
* ASC, NULLS are shown as TRUE/FALSE only if the index is orderable, and as NULL if unorderable -- I'm not sure if this is correct. Maybe we should
   simply show these properties in the literal form, not as booleans
   (as strings 'ASC'/'DESC', 'NULLS FIRST'/'NULLS LAST')?


I also have a question about testing commands \dAf+ and \dAoc+: is it
good idea to test them by changing an owner of one operator family or
class to created new one, checking the output, and restoring the owner
back? Or we should create a new opclass or opfamily with proper owner.
Or maybe it is not necesary to test these commands?
diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 3ed9021..b699548 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -675,7 +675,7 @@
    search and ordering purposes.)
   </para>
 
-  <table>
+  <table id="catalog-pg-amop-table">
    <title><structname>pg_amop</structname> Columns</title>
 
    <tgroup cols="4">
@@ -818,7 +818,7 @@
    is one row for each support procedure belonging to an operator family.
   </para>
 
-  <table>
+  <table id="catalog-pg-amproc-table">
    <title><structname>pg_amproc</structname> Columns</title>
 
    <tgroup cols="4">
@@ -4458,7 +4458,7 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
    Operator classes are described at length in <xref linkend="xindex"/>.
   </para>
 
-  <table>
+  <table id="catalog-pg-opclass-table">
    <title><structname>pg_opclass</structname> Columns</title>
 
    <tgroup cols="4">
@@ -4720,7 +4720,7 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
    Operator families are described at length in <xref linkend="xindex"/>.
   </para>
 
-  <table>
+  <table id="catalog-pg-opfamily-table">
    <title><structname>pg_opfamily</structname> Columns</title>
 
    <tgroup cols="4">
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index b17039d..273c3f7 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -1203,6 +1203,95 @@ testdb=&gt;
         </para>
         </listitem>
       </varlistentry>
+      
+      <varlistentry>
+        <term>
+          <literal>\dAf
+          [ <link linkend="app-psql-patterns"><replaceable class="parameter">access-method-pattern</replaceable></link> 
+            [<link linkend="app-psql-patterns"><replaceable class="parameter">operator-family-pattern</replaceable></link>]]
+          </literal>
+        </term>
+
+        <listitem>
+        <para>
+        Lists operator families (<xref linkend="catalog-pg-opfamily-table"/>). If <replaceable class="parameter">access-method-pattern</replaceable> is specified, only
+        families whose access method name matches the pattern are shown.
+        If <replaceable class="parameter">operator-family-pattern</replaceable> is specified, only
+        opereator families associated with whose name matches the pattern are shown.
+        If <literal>+</literal> is appended to the command name, each operator
+        family is listed with it's owner.
+        </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <literal>\dAfo
+            [<link linkend="app-psql-patterns"><replaceable class="parameter">access-method-pattern</replaceable></link>
+              [<link linkend="app-psql-patterns"><replaceable class="parameter">operator-family-pattern</replaceable></link>]]
+          </literal>
+        </term>
+
+        <listitem>
+        <para>
+        Lists operators (<xref linkend="catalog-pg-amop-table"/>) associated with access method operator families.
+        If <replaceable class="parameter">access-method-patttern</replaceable> is specified,
+        only operators associated with access method whose name matches pattern are shown.
+        If <replaceable class="parameter">operator-family-pattern</replaceable> is specified, only
+        opereators associated with families whose name matches the pattern are shown.
+        </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <literal>\dAfp
+            [<link linkend="app-psql-patterns"><replaceable class="parameter">access-method-pattern</replaceable></link>
+              [<link linkend="app-psql-patterns"><replaceable class="parameter">operator-family-pattern</replaceable></link>]]
+          </literal>
+        </term>
+        <listitem>
+        <para>
+        List procedures (<xref linkend="catalog-pg-amproc-table"/>) accociated with access method operator families.
+        If <replaceable class="parameter">access-method-patttern</replaceable> is specified,
+        only procedures associated with access method whose name matches pattern are shown.
+        If <replaceable class="parameter">operator-family-pattern</replaceable> is specified, only
+        procedures associated with families whose name matches the pattern are shown.
+        </para>
+        </listitem>
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <literal>\dAop
+            [<link linkend="app-psql-patterns"><replaceable class="parameter">access-method-pattern</replaceable></link>
+              [<link linkend="app-psql-patterns"><replaceable class="parameter">operator-class-pattern</replaceable></link>]]
+          </literal>
+        </term>
+        <listitem>
+        <para>
+        Shows index access method operator classes listed in <xref linkend="catalog-pg-opclass-table"/>.
+        If <replaceable class="parameter">access-method-patttern</replaceable> is specified,
+        only operator classes associated with access method whose name matches pattern are shown.
+        If <replaceable class="parameter">operator-class-pattern</replaceable> is specified, only
+        procedures associated with families whose name matches the pattern are shown.
+        </para>
+        </listitem>
+      </varlistentry>
+
+
+      <varlistentry>
+        <term><literal>\dAp [ <link linkend="app-psql-patterns"><replaceable class="parameter">pattern</replaceable></link> ]</literal></term>
+
+        <listitem>
+        <para>
+        Shows access method properties listed in <xref
+         linkend="functions-info-indexam-props"/>. If <replaceable
+        class="parameter">pattern</replaceable> is specified, only access
+        methods whose names match the pattern are shown.
+        </para>
+        </listitem>
+      </varlistentry>
 
       <varlistentry>
         <term><literal>\db[+] [ <link linkend="app-psql-patterns"><replaceable class="parameter">pattern</replaceable></link> ]</literal></term>
@@ -1351,6 +1440,35 @@ testdb=&gt;
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><literal>\dip [ <link linkend="app-psql-patterns"><replaceable class="parameter">pattern</replaceable></link> ]</literal></term>
+
+        <listitem>
+        <para>
+        Shows index properties listed in <xref
+        linkend="functions-info-index-props"/>. If <replaceable
+        class="parameter">pattern</replaceable> is specified, only access
+        methods whose names match the pattern are shown.
+        </para>
+        </listitem>        
+      </varlistentry>
+
+      <varlistentry>
+        <term>
+          <literal>\dicp [ <link linkend="app-psql-patterns"><replaceable class="parameter">index-name-pattern</replaceable></link>
+                              [ <link linkend="app-psql-patterns"><replaceable class="parameter">column-name-pattern</replaceable></link> ]]
+          </literal>
+        </term>
+
+        <listitem>
+        <para>
+        Shows index column properties listed in <xref
+        linkend="functions-info-index-column-props"/>. If <replaceable
+        class="parameter">column_name</replaceable> is specified, only column
+        with such name is shown.
+        </para>
+        </listitem>
+      </varlistentry>
 
       <varlistentry>
         <term><literal>\des[+] [ <link linkend="app-psql-patterns"><replaceable class="parameter">pattern</replaceable></link> ]</literal></term>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 4c85f43..2d21911 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -723,7 +723,22 @@ exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd)
 					success = listTables("tvmsE", NULL, show_verbose, show_system);
 				break;
 			case 'A':
-				success = describeAccessMethods(pattern, show_verbose);
+				{
+				char *pattern2 = psql_scan_slash_option(scan_state, OT_NORMAL, NULL, true);
+				if (strncmp(cmd, "dAp", 3) == 0)
+					success = describeAccessMethodProperties(pattern);
+				else if (strncmp(cmd, "dAfo", 4) == 0)
+					success = listFamilyClassOperators(pattern, pattern2);
+				else if (strncmp(cmd, "dAfp", 4) == 0)
+					success = listOperatorFamilyProcedures(pattern, pattern2);
+				else if (strncmp(cmd, "dAf", 3) == 0)
+					success = listAccessMethodOperatorFamilies(pattern, pattern2, show_verbose);
+				else if (strncmp(cmd, "dAoc", 4) == 0)
+					success = describeAccessMethodOperatorClasses(pattern, pattern2, show_verbose);
+				else
+					success = describeAccessMethods(pattern, show_verbose);
+				free(pattern2);
+				}
 				break;
 			case 'a':
 				success = describeAggregates(pattern, show_verbose, show_system);
@@ -792,6 +807,23 @@ exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd)
 			case 'v':
 			case 'm':
 			case 'i':
+				if (strncmp(cmd, "dip", 3) == 0)
+				{
+					success = describeIndexProperties(pattern, show_system);
+					break;
+				}
+				else if (strncmp(cmd, "dicp", 4) == 0)
+				{
+					char	   *column_pattern = NULL;
+
+					if (pattern)
+						column_pattern = psql_scan_slash_option(scan_state,
+																OT_NORMAL, NULL, true);
+
+					success = describeIndexColumnProperties(pattern, column_pattern, show_system);
+					free(column_pattern);
+					break;
+				}
 			case 's':
 			case 'E':
 				success = listTables(&cmd[1], pattern, show_verbose, show_system);
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 6e08515..a37f66b 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -43,7 +43,9 @@ static bool describeOneTSConfig(const char *oid, const char *nspname,
 					const char *pnspname, const char *prsname);
 static void printACLColumn(PQExpBuffer buf, const char *colname);
 static bool listOneExtensionContents(const char *extname, const char *oid);
-
+static bool describeOneIndexColumnProperties(const char *oid, const char *nspname,
+								 			 const char *idxname, const char *amname,
+								 			 const char *tabname, const char *column_pattern);
 
 /*----------------
  * Handlers for various slash commands displaying some sort of list
@@ -5505,3 +5507,559 @@ printACLColumn(PQExpBuffer buf, const char *colname)
 						  "pg_catalog.array_to_string(%s, '\\n') AS \"%s\"",
 						  colname, gettext_noop("Access privileges"));
 }
+
+/*
+ * \dip
+ * Takes an optional regexp to select particular index. Describes index proerties
+ */
+bool
+describeIndexProperties(const char *pattern, bool showSystem)
+{
+	PQExpBufferData buf;
+	PGresult   *res;
+	printQueryOpt myopt = pset.popt;
+
+	/* what for ? */
+	static const bool translate_columns[] = {false, false, false, false, false, false, false};
+
+	initPQExpBuffer(&buf);
+
+	printfPQExpBuffer(&buf,
+					  "SELECT"
+					  "  n.nspname as \"%s\",\n"
+					  "  c.relname as \"%s\",\n"
+					  "  am.amname as \"%s\",\n"
+					  "  pg_index_has_property(c.relname::regclass, 'clusterable') as \"%s\",\n"
+					  "  pg_index_has_property(c.relname::regclass, 'index_scan') as \"%s\",\n"
+					  "  pg_index_has_property(c.relname::regclass, 'bitmap_scan') as \"%s\",\n"
+					  "  pg_index_has_property(c.relname::regclass, 'backward_scan') as \"%s\"\n"
+					  "FROM pg_class c\n"
+					  "  LEFT JOIN pg_namespace n ON n.oid = c.relnamespace\n"
+					  "  LEFT JOIN pg_am am ON am.oid = c.relam\n"
+					  "WHERE c.relkind='i'\n"
+					  "  AND n.nspname !~ 'pg_toast'\n",
+					  gettext_noop("Schema"),
+					  gettext_noop("Name"),
+					  gettext_noop("Access method"),
+					  gettext_noop("Clusterable"),
+					  gettext_noop("Index scan"),
+					  gettext_noop("Bitmap scan"),
+					  gettext_noop("Backward scan"));
+
+	if (!showSystem && !pattern)
+		appendPQExpBufferStr(&buf,
+							 "  AND n.nspname <> 'pg_catalog'\n"
+							 "  AND n.nspname <> 'information_schema'\n");
+
+	processSQLNamePattern(pset.db, &buf, pattern, true, false,
+						  "n.nspname", "c.relname", NULL, NULL);
+
+	appendPQExpBufferStr(&buf, "ORDER BY 1;");
+	res = PSQLexec(buf.data);
+	termPQExpBuffer(&buf);
+	if (!res)
+		return false;
+
+	myopt.nullPrint = NULL;
+	myopt.title = _("Index properties");
+	myopt.translate_header = true;
+	myopt.translate_columns = translate_columns;
+	myopt.n_translate_columns = lengthof(translate_columns);
+
+	printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+
+	PQclear(res);
+	return true;
+}
+
+/* \dAp
+ *	Takes an optional regexp to select particular access methods
+ */
+bool
+describeAccessMethodProperties(const char *pattern)
+{
+	PQExpBufferData buf;
+	PGresult   *res;
+	printQueryOpt myopt = pset.popt;
+	static const bool translate_columns[] = {false, false, false, false, true};
+
+	if (pset.sversion < 90600)
+	{
+		char		sverbuf[32];
+
+		psql_error("The server (version %s) does not support access methods.\n",
+				   formatPGVersionNumber(pset.sversion, false,
+										 sverbuf, sizeof(sverbuf)));
+		return true;
+	}
+
+	initPQExpBuffer(&buf);
+
+	printfPQExpBuffer(&buf,
+					  "SELECT a.amname AS \"%s\",\n"
+					  "  pg_indexam_has_property(a.oid, 'can_order') AS \"%s\",\n"
+					  "  pg_indexam_has_property(a.oid, 'can_unique') AS \"%s\",\n"
+					  "  pg_indexam_has_property(a.oid, 'can_multi_col') AS \"%s\",\n"
+					  "  pg_indexam_has_property(a.oid, 'can_exclude') AS \"%s\"",
+					  gettext_noop("AM Name"),
+					  gettext_noop("Can order"),
+					  gettext_noop("Can unique"),
+					  gettext_noop("Can multi col"),
+					  gettext_noop("Can exclude"));
+
+	appendPQExpBufferStr(&buf,
+						 "\nFROM pg_am a\n");
+
+	processSQLNamePattern(pset.db, &buf, pattern, false, false,
+						  NULL, "amname", NULL, NULL);
+
+	appendPQExpBufferStr(&buf, "ORDER BY 1;");
+	res = PSQLexec(buf.data);
+	termPQExpBuffer(&buf);
+	if (!res)
+		return false;
+
+	myopt.nullPrint = NULL;
+	myopt.title = _("Access method properties");
+	myopt.translate_header = true;
+	myopt.translate_columns = translate_columns;
+	myopt.n_translate_columns = lengthof(translate_columns);
+
+	printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+
+	PQclear(res);
+	return true;
+}
+
+/* \dAf */
+bool
+listAccessMethodOperatorFamilies(const char *access_method_pattern, const char *family_pattern, bool verbose)
+{
+	PQExpBufferData buf;
+	PGresult	   *res;
+	printQueryOpt	myopt = pset.popt;
+	bool			have_where = false;
+	static const bool translate_columns[] = {false, false, false, false};
+
+	initPQExpBuffer(&buf);
+
+	printfPQExpBuffer(&buf,
+					  "SELECT\n"
+					  "  am.amname AS \"%s\",\n"
+					  "  ns.nspname AS \"%s\",\n"
+					  "  of.opfname AS \"%s\"\n",
+					  gettext_noop("Access method"),
+					  gettext_noop("Operator family schema"),
+					  gettext_noop("Operator family name"));
+	if (verbose)
+		appendPQExpBuffer(&buf,
+					  ",  usr.usename AS \"%s\"\n",
+					  gettext_noop("Owner"));
+	appendPQExpBuffer(&buf,
+					  "  FROM pg_opfamily of\n"
+					  "  LEFT JOIN pg_am am ON am.oid = of.opfmethod\n"
+					  "  LEFT JOIN pg_namespace ns ON of.opfnamespace = ns.oid\n");
+	if (verbose)
+		appendPQExpBuffer(&buf,
+						"  LEFT JOIN pg_user usr ON of.opfowner = usr.usesysid\n"
+						);
+	if (access_method_pattern)
+		have_where = processSQLNamePattern(pset.db, &buf, access_method_pattern, false, false,
+							  "am.amname", "am.amname", NULL, NULL);
+	if (family_pattern)
+		processSQLNamePattern(pset.db, &buf, family_pattern, have_where, false,
+							  "ns.nspname", "of.opfname", NULL, NULL);
+
+	appendPQExpBufferStr(&buf, "ORDER BY 1, 2;");
+
+	res = PSQLexec(buf.data);
+	termPQExpBuffer(&buf);
+	if (!res)
+		return false;
+
+	myopt.nullPrint = NULL;
+	myopt.title = _("List of operator families");
+	myopt.translate_header = true;
+	myopt.translate_columns = translate_columns;
+	myopt.n_translate_columns = lengthof(translate_columns);
+
+	printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+
+	PQclear(res);
+	return true;
+
+}
+
+/* \dAfo */
+bool
+listFamilyClassOperators(const char *access_method_pattern, const char *family_pattern)
+{
+	PQExpBufferData buf;
+	PGresult	   *res;
+	printQueryOpt	myopt = pset.popt;
+	bool			have_where = false;
+
+	static const bool translate_columns[] = {false, false, false, false, false, false, false, false, false};
+
+	initPQExpBuffer(&buf);
+
+	printfPQExpBuffer(&buf,
+					  "SELECT DISTINCT\n"
+					  "  am.amname AS \"%s\",\n"
+					  "  nsf.nspname AS \"%s\",\n"
+					  "  of.opfname AS \"%s\",\n"
+					  "  format_type(o.amoplefttype , NULL) AS \"%s\",\n"
+					  "  format_type(o.amoprighttype , NULL) AS \"%s\",\n"
+					  "  o.amopstrategy AS \"%s\",\n"
+					  "  CASE WHEN pg_operator_is_visible(op.oid) \n"
+					  "    THEN op.oprname::text \n"
+					  "    ELSE o.amopopr::pg_catalog.regoper::text \n"
+					  "  END AS \"%s\",\n"
+					  "  CASE o.amoppurpose\n"
+					  "    WHEN 'o' THEN 'ordering'\n"
+					  "    WHEN 's' THEN 'search'\n"
+					  "  END AS \"%s\",\n"
+					  "  ofs.opfname AS \"%s\"\n"
+					  "FROM pg_amop o\n"
+					  "  LEFT JOIN pg_operator op ON op.oid = o.amopopr\n"
+					  "  LEFT JOIN pg_opfamily of ON of.oid = o.amopfamily\n"
+					  "  LEFT JOIN pg_opfamily ofs ON ofs.oid = o.amopsortfamily\n"
+					  "  LEFT JOIN pg_am am ON am.oid = of.opfmethod AND am.oid = o.amopmethod\n"
+					  "  LEFT JOIN pg_namespace nsf ON of.opfnamespace = nsf.oid\n",
+					  gettext_noop("AM"),
+					  gettext_noop("Opfamily Schema"),
+					  gettext_noop("Opfamily Name"),
+					  gettext_noop("Left type"),
+					  gettext_noop("Right type"),
+					  gettext_noop("Strategy"),
+					  gettext_noop("Operator"),
+					  gettext_noop("Purpose"),
+					  gettext_noop("Sort family"));
+
+	if (access_method_pattern)
+		have_where = processSQLNamePattern(pset.db, &buf, access_method_pattern,
+										   false, false, NULL, "am.amname",
+										   NULL, NULL);
+
+	if (family_pattern)
+		processSQLNamePattern(pset.db, &buf, family_pattern, have_where, false,
+							  "nsf.nspname", "of.opfname", NULL, NULL);
+
+	appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 3, 4, 5, 6;");
+
+	res = PSQLexec(buf.data);
+	termPQExpBuffer(&buf);
+	if (!res)
+		return false;
+
+	myopt.nullPrint = NULL;
+	myopt.title = _("List operators of family related to access method");
+	myopt.translate_header = true;
+	myopt.translate_columns = translate_columns;
+	myopt.n_translate_columns = lengthof(translate_columns);
+
+	printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+
+	PQclear(res);
+	return true;
+}
+
+/* \dAfp */
+bool
+listOperatorFamilyProcedures(const char *access_method_pattern, const char *family_pattern)
+{
+	PQExpBufferData buf;
+	PGresult	   *res;
+	printQueryOpt	myopt = pset.popt;
+	bool			have_where = false;
+	static const bool translate_columns[] = {false, false, false, false, false, false, false};
+
+	initPQExpBuffer(&buf);
+
+	printfPQExpBuffer(&buf,
+					  "SELECT DISTINCT\n"
+					  "  am.amname AS \"%s\",\n"
+					  "  ns.nspname AS \"%s\",\n"
+					  "  of.opfname AS \"%s\",\n"
+					  "  format_type(ap.amproclefttype, NULL) AS \"%s\",\n"
+					  "  format_type(ap.amprocrighttype, NULL) AS \"%s\",\n"
+					  "  ap.amprocnum AS \"%s\",\n"
+					  "  ap.amproc::pg_catalog.regproc::text || '(' || pg_get_function_arguments(ap.amproc) || ')' AS \"%s\"\n"
+					  "FROM pg_amproc ap\n"
+					  "  LEFT JOIN pg_opfamily of ON of.oid = ap.amprocfamily\n"
+					  "  LEFT JOIN pg_am am ON am.oid = of.opfmethod\n"
+					  "  LEFT JOIN pg_namespace ns ON of.opfnamespace = ns.oid\n",
+					  gettext_noop("AM"),
+					  gettext_noop("Family schema"),
+					  gettext_noop("Family name"),
+					  gettext_noop("Left"),
+					  gettext_noop("Right"),
+					  gettext_noop("Number"),
+					  gettext_noop("Proc name"));
+
+	if (access_method_pattern)
+		have_where = processSQLNamePattern(pset.db, &buf, access_method_pattern, false, false,
+							  NULL, "am.amname", NULL,
+							  NULL);
+	if (family_pattern)
+		processSQLNamePattern(pset.db, &buf, family_pattern, have_where, false,
+							  "ns.nspname", "of.opfname", NULL,
+							  NULL);
+
+	appendPQExpBufferStr(&buf,
+						 "ORDER BY 1, 2, 3, 4, 5, 6;");
+
+	res = PSQLexec(buf.data);
+	termPQExpBuffer(&buf);
+	if (!res)
+		return false;
+
+	myopt.nullPrint = NULL;
+	myopt.title = _("List of operator family procedures");
+	myopt.translate_header = true;
+	myopt.translate_columns = translate_columns;
+	myopt.n_translate_columns = lengthof(translate_columns);
+
+	printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+
+	PQclear(res);
+	return true;
+}
+
+/* \dicp */
+bool
+describeIndexColumnProperties(const char *index_pattern, const char *column_pattern, bool showSystem)
+{
+	PQExpBufferData buf;
+	PGresult	   *res;
+	int				i;
+
+	initPQExpBuffer(&buf);
+
+	printfPQExpBuffer(&buf,
+					  "SELECT DISTINCT c.oid,\n"
+					  "  n.nspname,\n"
+					  "  c.relname,\n"
+					  "  am.amname,\n"
+					  "  c2.relname\n"
+					  "FROM pg_catalog.pg_class c\n"
+					  "  LEFT JOIN pg_catalog.pg_namespace n ON n.oid = relnamespace\n"
+					  "  LEFT JOIN pg_am am ON am.oid = c.relam\n"
+					  "  LEFT JOIN pg_catalog.pg_index i ON i.indexrelid = c.oid\n"
+					  "  LEFT JOIN pg_catalog.pg_class c2 ON i.indrelid = c2.oid\n"
+					  "WHERE c.relkind='i'\n");
+
+	if (!showSystem && !index_pattern)
+		appendPQExpBufferStr(&buf, "AND n.nspname <> 'pg_catalog'\n"
+								   "AND n.nspname <> 'information_schema'\n");
+
+	processSQLNamePattern(pset.db, &buf, index_pattern, true, false,
+						  "n.nspname", "c.relname", NULL,
+						  "pg_catalog.pg_table_is_visible(c.oid)");
+
+	appendPQExpBufferStr(&buf, "ORDER BY 2, 3;");
+
+	res = PSQLexec(buf.data);
+	termPQExpBuffer(&buf);
+	if (!res)
+		return false;
+
+	if (PQntuples(res) == 0)
+	{
+		if (!pset.quiet)
+		{
+			if (column_pattern)
+				psql_error("Did not find any index \"%s\" with column \"%s\"\n",
+						   index_pattern, column_pattern);
+			else if (index_pattern)
+				psql_error("Did not find any index named \"%s\"\n",
+						   index_pattern);
+			else
+				psql_error("Did not find any relations.\n");
+		}
+		PQclear(res);
+		return false;
+	}
+
+	for (i = 0; i < PQntuples(res); i++)
+	{
+		const char *oid = PQgetvalue(res, i, 0);
+		const char *nspname = PQgetvalue(res, i, 1);
+		const char *idxname = PQgetvalue(res, i, 2);
+		const char *amname = PQgetvalue(res, i, 3);
+		const char *tabname = PQgetvalue(res, i, 4);
+
+		if (!describeOneIndexColumnProperties(oid, nspname, idxname, amname,
+											  tabname, column_pattern))
+		{
+			PQclear(res);
+			return false;
+		}
+		if (cancel_pressed)
+		{
+			PQclear(res);
+			return false;
+		}
+	}
+
+	PQclear(res);
+	return true;
+}
+
+static bool
+describeOneIndexColumnProperties(const char *oid, 
+								 const char *nspname,
+								 const char *idxname,
+								 const char *amname,
+								 const char *tabname,
+								 const char *column_pattern)
+{
+	PQExpBufferData buf;
+	PGresult	   *res;
+	printQueryOpt   myopt = pset.popt;
+	char		   *footers[3] = {NULL, NULL};
+	static const bool translate_columns[] = {false, false, false, false, false, false, false, false, false, false};
+
+	initPQExpBuffer(&buf);
+
+	printfPQExpBuffer(&buf,
+					  "SELECT "
+					  "  a.attname AS \"%s\","
+					  "  pg_get_indexdef(i.indexrelid, a.attnum, true) AS \"%s\",\n"
+					  "  o.opcname AS \"%s\","
+					  "  CASE\n"
+					  "    WHEN pg_index_column_has_property(c.relname::regclass, a.attnum, 'orderable') = true \n"
+					  "    THEN pg_index_column_has_property(c.relname::regclass, a.attnum, 'asc')\n"
+					  "    ELSE NULL"
+					  "  END  AS \"%s\","
+					  "  CASE\n"
+					  "    WHEN pg_index_column_has_property(c.relname::regclass, a.attnum, 'orderable') = true \n"
+					  "    THEN pg_index_column_has_property(c.relname::regclass, a.attnum, 'nulls_first')\n"
+					  "    ELSE NULL"
+					  "  END  AS \"%s\","
+					  "  pg_index_column_has_property(c.relname::regclass, a.attnum, 'orderable') AS \"%s\",\n"
+					  "  pg_index_column_has_property(c.relname::regclass, a.attnum, 'distance_orderable') AS \"%s\",\n"
+					  "  pg_index_column_has_property(c.relname::regclass, a.attnum, 'returnable') AS \"%s\",\n"
+					  "  pg_index_column_has_property(c.relname::regclass, a.attnum, 'search_array') AS \"%s\",\n"
+					  "  pg_index_column_has_property(c.relname::regclass, a.attnum, 'search_nulls') AS \"%s\"\n"
+					  "FROM pg_class c\n"
+					  "  LEFT JOIN pg_catalog.pg_namespace n ON n.oid = relnamespace\n"
+					  "  LEFT JOIN pg_catalog.pg_index i ON i.indexrelid = c.oid\n"
+					  "  LEFT JOIN pg_catalog.pg_class c2 ON i.indrelid = c2.oid\n"
+					  "  LEFT JOIN pg_catalog.pg_attribute a ON a.attrelid = c.oid\n"
+					  "  LEFT JOIN pg_catalog.pg_type t ON t.oid = a.atttypid\n"
+					  "  LEFT JOIN information_schema.columns ic ON ic.table_name = c2.relname AND ic.ordinal_position = i.indkey[a.attnum - 1] \n"
+					  "  LEFT JOIN pg_opclass o ON o.oid = (indclass::oid[])[a.attnum - 1]\n"
+					  "WHERE c.oid = %s",
+					  gettext_noop("Column name"),
+					  gettext_noop("Expr"),
+					  gettext_noop("Opclass"),
+					  gettext_noop("ASC"),
+					  gettext_noop("Nulls first"),
+					  gettext_noop("Orderable"),
+					  gettext_noop("Distance orderable"),
+					  gettext_noop("Returnable"),
+					  gettext_noop("Search array"),
+					  gettext_noop("Search nulls"),
+					  oid);
+
+	if (column_pattern)
+		processSQLNamePattern(pset.db, &buf, column_pattern, true, false,
+								NULL, "ic.column_name", NULL, NULL);
+	appendPQExpBufferStr(&buf, "ORDER BY a.attnum");
+
+	res = PSQLexec(buf.data);
+	termPQExpBuffer(&buf);
+	if (!res)
+		return false;
+	if(PQntuples(res) == 0)
+	{
+		PQclear(res);
+		return true;
+	}
+
+	myopt.nullPrint = NULL;
+	myopt.title = psprintf(_("Index %s.%s"), nspname, idxname);
+	footers[0] = psprintf(_("Table: %s"), tabname);
+	footers[1] = psprintf(_("Access method: %s"),amname);
+	myopt.footers = footers;
+	myopt.topt.default_footer = false;
+	myopt.translate_header = true;
+	myopt.translate_columns = translate_columns;
+	myopt.n_translate_columns = lengthof(translate_columns);
+
+	printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+	PQclear(res);
+	return true;
+}
+
+/*
+ * \dAoc
+ * List index access method operator classes.
+ * Takes an optional regexp to select particular access method and operator class.
+ */
+bool
+describeAccessMethodOperatorClasses(const char *access_method_pattern, const char *opclass_pattern, bool verbose)
+{
+	PQExpBufferData buf;
+	PGresult	   *res;
+	printQueryOpt	myopt = pset.popt;
+	bool			have_where = false;
+	static const bool translate_columns[] = {false, false, false, false, false, false, false, false};
+
+	initPQExpBuffer(&buf);
+
+	printfPQExpBuffer(&buf,
+					  "SELECT"
+					  "  am.amname AS \"%s\",\n"
+					  "  n.nspname AS \"%s\",\n"
+					  "  c.opcname AS \"%s\",\n",
+					  gettext_noop("Access method"),
+					  gettext_noop("Schema"),
+					  gettext_noop("Name"));
+	if (verbose)
+		appendPQExpBuffer(&buf,
+					  "  pg_catalog.pg_get_userbyid(c.opcowner) AS \"%s\",\n",
+					  gettext_noop("Owner"));
+	appendPQExpBuffer(&buf,
+					  "  of.opfname AS \"%s\",\n"
+					  "  c.opcintype::regtype AS \"%s\",\n"
+					  "  c.opcdefault AS \"%s\",\n"
+					  "  (CASE WHEN c.opckeytype = 0 OR c.opckeytype = c.opcintype\n"
+					  "    THEN NULL\n"
+					  "    ELSE c.opckeytype\n"
+					  "  END)::regtype::regtype AS \"%s\"\n"
+					  "FROM pg_opclass c\n"
+					  "  LEFT JOIN pg_am am on am.oid = c.opcmethod\n"
+					  "  LEFT JOIN pg_namespace n ON n.oid = c.opcnamespace\n"
+					  "  LEFT JOIN pg_opfamily of ON of.oid = c.opcfamily\n",
+					  gettext_noop("Family"),
+					  gettext_noop("Indexed type"),
+					  gettext_noop("Is default"),
+					  gettext_noop("Stored type"));
+
+	if (access_method_pattern)
+		have_where = processSQLNamePattern(pset.db, &buf, access_method_pattern,
+									false, false, NULL, "am.amname", NULL, NULL);
+	if (opclass_pattern)
+		processSQLNamePattern(pset.db, &buf, opclass_pattern, have_where, false,
+							  "n.nspname", "c.opcname", NULL,
+							  NULL);
+
+	appendPQExpBufferStr(&buf, "ORDER BY 1,2,3;");
+	res = PSQLexec(buf.data);
+	termPQExpBuffer(&buf);
+	if (!res)
+		return false;
+
+	myopt.nullPrint = NULL;
+	myopt.title = _("Index access method operator classes");
+	myopt.translate_header = true;
+	myopt.translate_columns = translate_columns;
+	myopt.n_translate_columns = lengthof(translate_columns);
+
+	printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+
+	PQclear(res);
+	return true;
+}
diff --git a/src/bin/psql/describe.h b/src/bin/psql/describe.h
index a4cc5ef..b145f20 100644
--- a/src/bin/psql/describe.h
+++ b/src/bin/psql/describe.h
@@ -111,4 +111,25 @@ bool		describePublications(const char *pattern);
 /* \dRs */
 bool		describeSubscriptions(const char *pattern, bool verbose);
 
+/* \dAf */
+extern bool listAccessMethodOperatorFamilies(const char *access_method_pattern, const char *family_pattern, bool verbose);
+
+/* \dAfp */
+extern bool listOperatorFamilyProcedures(const char *access_method_pattern, const char *family_pattern);
+
+/* \dAfo */
+extern bool listFamilyClassOperators(const char *accessMethod_pattern, const char *family_pattern);
+
+/* \dAp */
+extern bool describeAccessMethodProperties(const char *pattern);
+
+/* \dip */
+extern bool describeIndexProperties(const char *pattern, bool showSystem);
+
+/* \dicp */
+extern bool describeIndexColumnProperties(const char *indexPattern, const char *columnPattern, bool showSystem);
+
+/* \dAoc */
+extern bool describeAccessMethodOperatorClasses(const char *access_method_pattern, const char *opclass_pattern, bool verbose);
+
 #endif							/* DESCRIBE_H */
diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c
index 702e742..dbe62e8 100644
--- a/src/bin/psql/help.c
+++ b/src/bin/psql/help.c
@@ -224,6 +224,11 @@ slashUsage(unsigned short int pager)
 	fprintf(output, _("  \\d[S+]  NAME           describe table, view, sequence, or index\n"));
 	fprintf(output, _("  \\da[S]  [PATTERN]      list aggregates\n"));
 	fprintf(output, _("  \\dA[+]  [PATTERN]      list access methods\n"));
+	fprintf(output, _("  \\dAf[+] [AMPTRN [OPFPTRN]] list operator families of access method\n"));
+	fprintf(output, _("  \\dAfp   [AMPTRN [OPFPTRN]] list procedures of operator family related to access method\n"));
+	fprintf(output, _("  \\dAfo   [AMPTRN [OPFPTRN]] list operators of family related to access method\n"));
+	fprintf(output, _("  \\dAoc[+][AMPTRN [OPCPTRN]] list operator classes of index access methods\n"));
+	fprintf(output, _("  \\dAp    [PATTERN]      list access methods with properties\n"));
 	fprintf(output, _("  \\db[+]  [PATTERN]      list tablespaces\n"));
 	fprintf(output, _("  \\dc[S+] [PATTERN]      list conversions\n"));
 	fprintf(output, _("  \\dC[+]  [PATTERN]      list casts\n"));
@@ -242,6 +247,8 @@ slashUsage(unsigned short int pager)
 	fprintf(output, _("  \\dFt[+] [PATTERN]      list text search templates\n"));
 	fprintf(output, _("  \\dg[S+] [PATTERN]      list roles\n"));
 	fprintf(output, _("  \\di[S+] [PATTERN]      list indexes\n"));
+	fprintf(output, _("  \\dip[S] [PATTERN]      list indexes with properties\n"));
+	fprintf(output, _("  \\dicp[S] [IDXNAME [COLNAME]] show index column properties\n"));
 	fprintf(output, _("  \\dl                    list large objects, same as \\lo_list\n"));
 	fprintf(output, _("  \\dL[S+] [PATTERN]      list procedural languages\n"));
 	fprintf(output, _("  \\dm[S+] [PATTERN]      list materialized views\n"));
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index bb696f8..9d32d69 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -638,6 +638,23 @@ static const SchemaQuery Query_for_list_of_constraints_with_schema = {
 	NULL
 };
 
+static const SchemaQuery Query_for_list_of_operator_families = {
+	/* min_server_version */
+	0,
+	/* catname */
+	"pg_catalog.pg_opfamily c",
+	/* selcondition */
+	NULL,
+	/* viscondition */
+	"true",
+	/* namespace */
+	"c.opfnamespace",
+	/* result */
+	"pg_catalog.quote_ident(c.opfname)",
+	/* qualresult */
+	NULL
+};
+
 /* Relations supporting INSERT, UPDATE or DELETE */
 static const SchemaQuery Query_for_list_of_updatables = {
 	/* min_server_version */
@@ -1618,7 +1635,7 @@ psql_completion(const char *text, int start, int end)
 		"\\a",
 		"\\connect", "\\conninfo", "\\C", "\\cd", "\\copy",
 		"\\copyright", "\\crosstabview",
-		"\\d", "\\da", "\\dA", "\\db", "\\dc", "\\dC", "\\dd", "\\ddp", "\\dD",
+		"\\d", "\\da", "\\dA", "\\dAp", "\\dAfo", "\\dAfp", "\\dAf", "\\dAoc", "\\dicp", "\\dip", "\\db", "\\dc", "\\dC", "\\dd", "\\ddp", "\\dD",
 		"\\des", "\\det", "\\deu", "\\dew", "\\dE", "\\df",
 		"\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl", "\\dL",
 		"\\dm", "\\dn", "\\do", "\\dO", "\\dp",
@@ -3635,6 +3652,10 @@ psql_completion(const char *text, int start, int end)
 	}
 	else if (TailMatchesCS1("\\da*"))
 		COMPLETE_WITH_VERSIONED_SCHEMA_QUERY(Query_for_list_of_aggregates, NULL);
+	else if (TailMatchesCS1("\\dAf*"))
+		COMPLETE_WITH_QUERY(Query_for_list_of_access_methods);
+	else if (TailMatchesCS2("\\dAf*", MatchAny))
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_operator_families, NULL);
 	else if (TailMatchesCS1("\\dA*"))
 		COMPLETE_WITH_QUERY(Query_for_list_of_access_methods);
 	else if (TailMatchesCS1("\\db*"))
diff --git a/src/test/regress/expected/indexing.out b/src/test/regress/expected/indexing.out
index b9297c9..7488f4e 100644
--- a/src/test/regress/expected/indexing.out
+++ b/src/test/regress/expected/indexing.out
@@ -1349,3 +1349,28 @@ insert into covidxpart values (4, 1);
 insert into covidxpart values (4, 1);
 ERROR:  duplicate key value violates unique constraint "covidxpart4_a_b_idx"
 DETAIL:  Key (a)=(4) already exists.
+-- Test psql command for displaying information about indexes.
+\dip brinidx
+                                     Index properties
+ Schema |  Name   | Access method | Clusterable | Index scan | Bitmap scan | Backward scan 
+--------+---------+---------------+-------------+------------+-------------+---------------
+ public | brinidx | brin          | f           | f          | t           | f
+(1 row)
+
+\dicp botharrayidx 
+                                                   Index public.botharrayidx
+ Column name | Expr |  Opclass  | ASC | Nulls first | Orderable | Distance orderable | Returnable | Search array | Search nulls 
+-------------+------+-----------+-----+-------------+-----------+--------------------+------------+--------------+--------------
+ i           | i    | array_ops |     |             | f         | f                  | f          | f            | f
+ t           | t    | array_ops |     |             | f         | f                  | f          | f            | f
+Table: array_index_op_test
+Access method: gin
+
+\dicp botharrayidx t
+                                                   Index public.botharrayidx
+ Column name | Expr |  Opclass  | ASC | Nulls first | Orderable | Distance orderable | Returnable | Search array | Search nulls 
+-------------+------+-----------+-----+-------------+-----------+--------------------+------------+--------------+--------------
+ t           | t    | array_ops |     |             | f         | f                  | f          | f            | f
+Table: array_index_op_test
+Access method: gin
+
diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out
index 3818cfe..78c72da 100644
--- a/src/test/regress/expected/psql.out
+++ b/src/test/regress/expected/psql.out
@@ -3243,3 +3243,158 @@ last error message: division by zero
 \echo 'last error code:' :LAST_ERROR_SQLSTATE
 last error code: 22012
 \unset FETCH_COUNT
+-- check printing info about access methods
+\dA
+List of access methods
+  Name  | Type  
+--------+-------
+ brin   | Index
+ btree  | Index
+ gin    | Index
+ gist   | Index
+ hash   | Index
+ spgist | Index
+(6 rows)
+
+\dA gin
+List of access methods
+ Name | Type  
+------+-------
+ gin  | Index
+(1 row)
+
+\dA foo
+List of access methods
+ Name | Type 
+------+------
+(0 rows)
+
+\dAp gin
+                    Access method properties
+ AM Name | Can order | Can unique | Can multi col | Can exclude 
+---------+-----------+------------+---------------+-------------
+ gin     | f         | f          | t             | f
+(1 row)
+
+\dAp foo
+                    Access method properties
+ AM Name | Can order | Can unique | Can multi col | Can exclude 
+---------+-----------+------------+---------------+-------------
+(0 rows)
+
+\dAf gin
+                   List of operator families
+ Access method | Operator family schema | Operator family name 
+---------------+------------------------+----------------------
+ gin           | pg_catalog             | array_ops
+ gin           | pg_catalog             | tsvector_ops
+ gin           | pg_catalog             | jsonb_ops
+ gin           | pg_catalog             | jsonb_path_ops
+(4 rows)
+
+\dAf foo
+                   List of operator families
+ Access method | Operator family schema | Operator family name 
+---------------+------------------------+----------------------
+(0 rows)
+
+\dAfo brin uuid_minmax_ops
+                                List operators of family related to access method
+  AM  | Opfamily Schema |  Opfamily Name  | Left type | Right type | Strategy | Operator | Purpose | Sort family 
+------+-----------------+-----------------+-----------+------------+----------+----------+---------+-------------
+ brin | pg_catalog      | uuid_minmax_ops | uuid      | uuid       |        1 | <        | search  | 
+ brin | pg_catalog      | uuid_minmax_ops | uuid      | uuid       |        2 | <=       | search  | 
+ brin | pg_catalog      | uuid_minmax_ops | uuid      | uuid       |        3 | =        | search  | 
+ brin | pg_catalog      | uuid_minmax_ops | uuid      | uuid       |        4 | >=       | search  | 
+ brin | pg_catalog      | uuid_minmax_ops | uuid      | uuid       |        5 | >        | search  | 
+(5 rows)
+
+\dAfo brin bar
+                              List operators of family related to access method
+ AM | Opfamily Schema | Opfamily Name | Left type | Right type | Strategy | Operator | Purpose | Sort family 
+----+-----------------+---------------+-----------+------------+----------+----------+---------+-------------
+(0 rows)
+
+\dAfo foo bar
+                              List operators of family related to access method
+ AM | Opfamily Schema | Opfamily Name | Left type | Right type | Strategy | Operator | Purpose | Sort family 
+----+-----------------+---------------+-----------+------------+----------+----------+---------+-------------
+(0 rows)
+
+\dAfo * pg_catalog.jsonb_path_ops
+                               List operators of family related to access method
+ AM  | Opfamily Schema | Opfamily Name  | Left type | Right type | Strategy | Operator | Purpose | Sort family 
+-----+-----------------+----------------+-----------+------------+----------+----------+---------+-------------
+ gin | pg_catalog      | jsonb_path_ops | jsonb     | jsonb      |        7 | @>       | search  | 
+(1 row)
+
+\dAfp brin uuid_minmax_ops
+                                               List of operator family procedures
+  AM  | Family schema |   Family name   | Left | Right | Number |                           Proc name                           
+------+---------------+-----------------+------+-------+--------+---------------------------------------------------------------
+ brin | pg_catalog    | uuid_minmax_ops | uuid | uuid  |      1 | brin_minmax_opcinfo(internal)
+ brin | pg_catalog    | uuid_minmax_ops | uuid | uuid  |      2 | brin_minmax_add_value(internal, internal, internal, internal)
+ brin | pg_catalog    | uuid_minmax_ops | uuid | uuid  |      3 | brin_minmax_consistent(internal, internal, internal)
+ brin | pg_catalog    | uuid_minmax_ops | uuid | uuid  |      4 | brin_minmax_union(internal, internal, internal)
+(4 rows)
+
+\dAfp brin bar
+                  List of operator family procedures
+ AM | Family schema | Family name | Left | Right | Number | Proc name 
+----+---------------+-------------+------+-------+--------+-----------
+(0 rows)
+
+\dAfp foo bar
+                  List of operator family procedures
+ AM | Family schema | Family name | Left | Right | Number | Proc name 
+----+---------------+-------------+------+-------+--------+-----------
+(0 rows)
+
+\dAfp * pg_catalog.uuid_ops
+                               List of operator family procedures
+  AM   | Family schema | Family name | Left | Right | Number |            Proc name             
+-------+---------------+-------------+------+-------+--------+----------------------------------
+ btree | pg_catalog    | uuid_ops    | uuid | uuid  |      1 | uuid_cmp(uuid, uuid)
+ btree | pg_catalog    | uuid_ops    | uuid | uuid  |      2 | uuid_sortsupport(internal)
+ hash  | pg_catalog    | uuid_ops    | uuid | uuid  |      1 | uuid_hash(uuid)
+ hash  | pg_catalog    | uuid_ops    | uuid | uuid  |      2 | uuid_hash_extended(uuid, bigint)
+(4 rows)
+
+\dAoc brin pg*.oid*
+                                  Index access method operator classes
+ Access method |   Schema   |      Name      |     Family     | Indexed type | Is default | Stored type 
+---------------+------------+----------------+----------------+--------------+------------+-------------
+ brin          | pg_catalog | oid_minmax_ops | oid_minmax_ops | oid          | t          | 
+(1 row)
+
+\dA+
+                        List of access methods
+  Name  | Type  |   Handler   |              Description               
+--------+-------+-------------+----------------------------------------
+ brin   | Index | brinhandler | block range index (BRIN) access method
+ btree  | Index | bthandler   | b-tree index access method
+ gin    | Index | ginhandler  | GIN index access method
+ gist   | Index | gisthandler | GiST index access method
+ hash   | Index | hashhandler | hash index access method
+ spgist | Index | spghandler  | SP-GiST index access method
+(6 rows)
+
+\dA+ gin
+               List of access methods
+ Name | Type  |  Handler   |       Description       
+------+-------+------------+-------------------------
+ gin  | Index | ginhandler | GIN index access method
+(1 row)
+
+\dA+ foo
+       List of access methods
+ Name | Type | Handler | Description 
+------+------+---------+-------------
+(0 rows)
+
+\dAf+ foo
+                       List of operator families
+ Access method | Operator family schema | Operator family name | Owner 
+---------------+------------------------+----------------------+-------
+(0 rows)
+
diff --git a/src/test/regress/sql/indexing.sql b/src/test/regress/sql/indexing.sql
index 2091a87..4b5ce65 100644
--- a/src/test/regress/sql/indexing.sql
+++ b/src/test/regress/sql/indexing.sql
@@ -730,3 +730,8 @@ create unique index on covidxpart4 (a);
 alter table covidxpart attach partition covidxpart4 for values in (4);
 insert into covidxpart values (4, 1);
 insert into covidxpart values (4, 1);
+
+-- Test psql command for displaying information about indexes.
+\dip brinidx
+\dicp botharrayidx 
+\dicp botharrayidx t
diff --git a/src/test/regress/sql/psql.sql b/src/test/regress/sql/psql.sql
index b45da9b..ec5a673 100644
--- a/src/test/regress/sql/psql.sql
+++ b/src/test/regress/sql/psql.sql
@@ -688,3 +688,26 @@ select 1/(15-unique2) from tenk1 order by unique2 limit 19;
 \echo 'last error code:' :LAST_ERROR_SQLSTATE
 
 \unset FETCH_COUNT
+
+-- check printing info about access methods
+\dA
+\dA gin
+\dA foo
+\dAp gin
+\dAp foo
+\dAf gin
+\dAf foo
+\dAfo brin uuid_minmax_ops
+\dAfo brin bar
+\dAfo foo bar
+\dAfo * pg_catalog.jsonb_path_ops
+\dAfp brin uuid_minmax_ops
+\dAfp brin bar
+\dAfp foo bar
+\dAfp * pg_catalog.uuid_ops
+\dAoc brin pg*.oid*
+
+\dA+
+\dA+ gin
+\dA+ foo
+\dAf+ foo

Reply via email to