Dear hackers,

Please find attached the patch to add a new metacommand (\dh) to psql.
I find the functionality very useful for my day-to-day job, and decided
to add it to psql source code. Summary of the command, justification
for adding the functionality, as well as design choices are listed
below.

Best Regards,
Sadeq Dousti
Tech Lead and Staff Software Engineer at Trade Republic Bank GmbH

================

Summary
------------
The \dh command provides a concise overview of high-level (root)
relations, including tables and indexes. This helps DBAs and developers
quickly identify the core structure of a database, particularly in
environments with extensive partitioning. It offers two variants: \dht
for only showing root tables, and \dhi for only showing root indexes.
By adding the + option, additional details such as the total sizes of
the relations are also displayed.


Reference
------------
Commit 1c5d927 (psql \dP metacommand) is used as the basis for this
patch.

Justification
------------
In databases with partitioned tables, standard listing commands such as
\dt can produce long and cluttered outputs due to the large number of
partitions. The \dh command filters the output to show only root tables
(both regular and partitioned) and high-level indexes, improving
readability and usability.

This enhancement allows users to:

* Quickly scan the primary structure of a database without being
  overwhelmed by partitions.
* View table ownership and optionally include size information.
* Identify which indexes belong to which tables, along with
  descriptions.


Comparison Example
------------
Using \dt in a partitioned database results in an extensive list that
includes all partitions:


postgres=# \dt
              List of tables
 Schema | Name |       Type        | Owner
--------+------+-------------------+-------
 public | t    | table             | sadeq
 public | z    | partitioned table | sadeq
 public | z_1  | table             | sadeq
 public | z_2  | table             | sadeq
 public | z_3  | table             | sadeq
 public | z_4  | table             | sadeq
 public | z_5  | table             | sadeq
 public | z_6  | table             | sadeq
 public | z_7  | table             | sadeq
 public | z_8  | table             | sadeq
 public | z_9  | table             | sadeq
 public | z_10 | table             | sadeq
 public | z_11 | table             | sadeq
 public | z_12 | table             | sadeq
 public | z_13 | table             | sadeq
 public | z_14 | table             | sadeq
 public | z_15 | table             | sadeq


The \dh command simplifies this view by displaying only the root tables:

postgres=# \dht
  List of root tables
 Schema | Name | Owner
--------+------+-------
 public | t    | sadeq
 public | z    | sadeq


Design Decision: Introduction of the New Command \dh
------------
In the development of the \dh command to list high-level (root) tables
and indexes, it was initially considered to extend the existing \dP
command to support this functionality. However, after evaluating the
existing codebase, it became clear that adding this feature to \dP
would introduce significant complexity and reduce code readability.
Specifically, the following points led to the decision to implement a
new command instead of extending \dP or \d variant:

1. Functionality Mismatch: The \dP command is designed to display
   partitioned tables. Modifying it to also show non-partitioned table
   can potentially confuse the user.


2. Additional Branching and Readability: Introducing additional
   functionality to support high-level (root) relations would require a
   substantial amount of branching logic, making the code more
   difficult to follow and potentially error-prone.

3. Consistency with Existing \d Variants: Other \d variants exhibit a
   high degree of functional separation, with each command serving a
   unique role related to a specific type of database object. The logic
   for \dh is closer to \dP than any other \d variant, and it's already
   ruled out for the sake of readability.

Given these factors, the decision was made to introduce a new command,
\dh, to provide a concise overview of root tables and indexes. This
approach ensures clarity, avoids unnecessary complexity, and maintains
consistency with the overall design philosophy of psql metacommands.


Further Details
------------
* Patch is against the master branch
* Code compiles successfully. New functionality is tested manually with
  success
* Regression tests are added, and all existing and new tests pass
* Documentation (psql-ref.sgml) is updated with details for \dh
From 37c70da316ac072ef160e43406906696f1c5787c Mon Sep 17 00:00:00 2001
From: Sadeq Dousti <3616518+msdou...@users.noreply.github.com>
Date: Sat, 22 Feb 2025 23:16:44 +0100
Subject: [PATCH] psql \dh: list high-level tables and indexes

---
 doc/src/sgml/ref/psql-ref.sgml     |  22 ++++
 src/bin/psql/command.c             |  18 +++
 src/bin/psql/describe.c            | 196 +++++++++++++++++++++++++++++
 src/bin/psql/describe.h            |   3 +
 src/bin/psql/help.c                |   1 +
 src/bin/psql/tab-complete.in.c     |  43 ++++++-
 src/test/regress/expected/psql.out |  59 +++++++++
 src/test/regress/sql/psql.sql      |  13 ++
 8 files changed, 354 insertions(+), 1 deletion(-)

diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index 3edbd65e46..b1ed4a3bfa 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -1871,6 +1871,28 @@ SELECT $1 \parse stmt1
         </listitem>
       </varlistentry>
 
+      <varlistentry>
+        <term><literal>\dh[it+] [ <link linkend="app-psql-patterns"><replaceable class="parameter">pattern</replaceable></link> ]</literal></term>
+        <listitem>
+        <para>
+        Lists high-level (root) relations. This means relations that are
+        either not partitioned, or partitioned and have no parent.
+        If <replaceable class="parameter">pattern</replaceable>
+        is specified, only entries whose name matches the pattern are listed.
+        The modifiers <literal>t</literal> (tables) and <literal>i</literal>
+        (indexes) can be appended to the command, filtering the kind of
+        relations to list.  By default, high-level tables and indexes are
+        listed.
+        </para>
+
+        <para>
+        If <literal>+</literal> is appended to the command, the size of the
+        relation (when it's not partitioned), or the sum of the sizes of
+        the table's partitions (when the relation is partitioned) is also
+        displayed, along with the associated description.
+        </para>
+        </listitem>
+      </varlistentry>
 
       <varlistentry id="app-psql-meta-command-dl-lc">
         <term><literal>\dl[x+]</literal></term>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 0f27bf7a91..9fff186401 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -1117,6 +1117,24 @@ exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd)
 				/* no longer distinct from \du */
 				success = describeRoles(pattern, show_verbose, show_system);
 				break;
+			case 'h':
+				/* high-level (i.e., root) tables and indexes */
+				{
+					switch (cmd[2])
+					{
+						case '\0':
+						case '+':
+						case 't':
+						case 'i':
+						case 'x':
+							success = listRootTables(&cmd[2], pattern, show_verbose);
+							break;
+						default:
+							status = PSQL_CMD_UNKNOWN;
+							break;
+					}
+				}
+				break;
 			case 'l':
 				success = listLargeObjects(show_verbose);
 				break;
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index e6cf468ac9..3327065051 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -4247,6 +4247,202 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys
 	return true;
 }
 
+/*
+ * \dh
+ * Takes an optional regexp to select particular relations
+ *
+ * As with \d, you can specify the kinds of relations you want:
+ *
+ * t for tables
+ * i for indexes
+ *
+ * and you can mix and match them in any order.
+ */
+bool
+listRootTables(const char *reltypes, const char *pattern, bool verbose)
+{
+	bool		showTables = strchr(reltypes, 't') != NULL;
+	bool		showIndexes = strchr(reltypes, 'i') != NULL;
+	PQExpBufferData buf;
+	PQExpBufferData title;
+	PGresult   *res;
+	printQueryOpt myopt = pset.popt;
+	bool		translate_columns[] = {false, false, false, false, false, false, false, false};
+	const char *tabletitle;
+	bool		mixed_output = false;
+
+	/*
+	 * Note: Declarative table partitioning is only supported as of Pg 10.0.
+	 */
+	if (pset.sversion < 100000)
+	{
+		char		sverbuf[32];
+
+		pg_log_error("The server (version %s) does not support declarative table partitioning.",
+					 formatPGVersionNumber(pset.sversion, false,
+										   sverbuf, sizeof(sverbuf)));
+		return true;
+	}
+
+	/* If no relation kind was selected, show them all */
+	if (!showTables && !showIndexes)
+		showTables = showIndexes = true;
+
+	if (showIndexes && !showTables)
+		tabletitle = _("List of root indexes");	/* \dhi */
+	else if (showTables && !showIndexes)
+		tabletitle = _("List of root tables");	/* \dht */
+	else
+	{
+		/* show all kinds */
+		tabletitle = _("List of root relations");
+		mixed_output = true;
+	}
+
+	initPQExpBuffer(&buf);
+
+	printfPQExpBuffer(&buf,
+					  "SELECT n.nspname as \"%s\",\n"
+					  "  c.relname as \"%s\",\n"
+					  "  pg_catalog.pg_get_userbyid(c.relowner) as \"%s\"",
+					  gettext_noop("Schema"),
+					  gettext_noop("Name"),
+					  gettext_noop("Owner"));
+
+	if (mixed_output)
+	{
+		appendPQExpBuffer(&buf,
+						  ",\n  CASE c.relkind"
+						  " WHEN " CppAsString2(RELKIND_RELATION) " THEN '%s'"
+						  " WHEN " CppAsString2(RELKIND_PARTITIONED_TABLE) " THEN '%s'"
+						  " WHEN " CppAsString2(RELKIND_INDEX) " THEN '%s'"
+						  " WHEN " CppAsString2(RELKIND_PARTITIONED_INDEX) " THEN '%s'"
+						  " END as \"%s\"",
+						  gettext_noop("table"),
+						  gettext_noop("partitioned table"),
+						  gettext_noop("index"),
+						  gettext_noop("partitioned index"),
+						  gettext_noop("Type"));
+
+		translate_columns[3] = true;
+	}
+
+	if (showIndexes)
+		appendPQExpBuffer(&buf,
+						  ",\n c2.oid::pg_catalog.regclass as \"%s\"",
+						  gettext_noop("Table"));
+
+	if (verbose)
+	{
+		/*
+		 * Table access methods were introduced in v12, and can be set on
+		 * partitioned tables since v17.
+		 */
+		appendPQExpBuffer(&buf, ",\n  am.amname as \"%s\"",
+						  gettext_noop("Access method"));
+
+		/* Sizes of all partitions are considered in this case. */
+		appendPQExpBuffer(&buf,
+							",\n  pg_catalog.pg_size_pretty(GREATEST(pg_catalog.pg_table_size(c.oid), s.tps)) as \"%s\"",
+							gettext_noop("Total size"));
+
+		appendPQExpBuffer(&buf,
+						  ",\n  pg_catalog.obj_description(c.oid, 'pg_class') as \"%s\"",
+						  gettext_noop("Description"));
+	}
+
+	appendPQExpBufferStr(&buf,
+						 "\nFROM pg_catalog.pg_class c"
+						 "\n     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace");
+
+	if (showIndexes)
+		appendPQExpBufferStr(&buf,
+							 "\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");
+
+	if (verbose)
+	{
+		appendPQExpBufferStr(&buf,
+							 "\n     LEFT JOIN pg_catalog.pg_am am ON c.relam = am.oid");
+
+		if (pset.sversion < 120000)
+		{
+			appendPQExpBufferStr(&buf,
+								 ",\n     LATERAL (WITH RECURSIVE d\n"
+								 "                AS (SELECT inhrelid AS oid, 1 AS level\n"
+								 "                      FROM pg_catalog.pg_inherits\n"
+								 "                     WHERE inhparent = c.oid\n"
+								 "                    UNION ALL\n"
+								 "                    SELECT inhrelid, level + 1\n"
+								 "                      FROM pg_catalog.pg_inherits i\n"
+								 "                           JOIN d ON i.inhparent = d.oid)\n"
+								 "                SELECT sum(pg_catalog.pg_table_size(d.oid)) AS tps\n"
+								 "               FROM d) s");
+		}
+		else
+		{
+			/* PostgreSQL 12 has pg_partition_tree function */
+			appendPQExpBufferStr(&buf,
+								 ",\n     LATERAL (SELECT sum(pg_catalog.pg_table_size(ppt.relid)) AS tps"
+								 "\n              FROM pg_catalog.pg_partition_tree(c.oid) ppt) s");
+		}
+	}
+
+	appendPQExpBufferStr(&buf, "\nWHERE c.relkind IN (");
+	if (showTables)
+	{
+		appendPQExpBufferStr(&buf, CppAsString2(RELKIND_RELATION) ",");
+		appendPQExpBufferStr(&buf, CppAsString2(RELKIND_PARTITIONED_TABLE) ",");
+	}
+	if (showIndexes)
+	{
+		appendPQExpBufferStr(&buf, CppAsString2(RELKIND_INDEX) ",");
+		appendPQExpBufferStr(&buf, CppAsString2(RELKIND_PARTITIONED_INDEX) ",");
+	}
+	appendPQExpBufferStr(&buf, "''");	/* dummy */
+	appendPQExpBufferStr(&buf, ")\n");
+
+	appendPQExpBufferStr(&buf, " AND NOT c.relispartition\n");
+
+	if (!pattern)
+		appendPQExpBufferStr(&buf, "      AND n.nspname <> 'pg_catalog'\n"
+							 "      AND n.nspname !~ '^pg_toast'\n"
+							 "      AND n.nspname <> 'information_schema'\n");
+
+	if (!validateSQLNamePattern(&buf, pattern, true, false,
+								"n.nspname", "c.relname", NULL,
+								"pg_catalog.pg_table_is_visible(c.oid)",
+								NULL, 3))
+	{
+		termPQExpBuffer(&buf);
+		return false;
+	}
+
+	appendPQExpBuffer(&buf, "ORDER BY \"Schema\", %s\"Name\";",
+					  mixed_output ? "\"Type\" DESC, " : "");
+
+	res = PSQLexec(buf.data);
+	termPQExpBuffer(&buf);
+	if (!res)
+		return false;
+
+	initPQExpBuffer(&title);
+	appendPQExpBufferStr(&title, tabletitle);
+
+	myopt.title = title.data;
+	myopt.translate_header = true;
+	myopt.translate_columns = translate_columns;
+	myopt.n_translate_columns = lengthof(translate_columns);
+
+	printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+
+	termPQExpBuffer(&title);
+
+	PQclear(res);
+	return true;
+}
+
+
 /*
  * \dP
  * Takes an optional regexp to select particular relations
diff --git a/src/bin/psql/describe.h b/src/bin/psql/describe.h
index 18ecaa6094..6abd7ba31b 100644
--- a/src/bin/psql/describe.h
+++ b/src/bin/psql/describe.h
@@ -70,6 +70,9 @@ extern bool listAllDbs(const char *pattern, bool verbose);
 /* \dt, \di, \ds, \dS, etc. */
 extern bool listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSystem);
 
+/* \dh */
+extern bool listRootTables(const char *reltypes, const char *pattern, bool verbose);
+
 /* \dP */
 extern bool listPartitionedTables(const char *reltypes, const char *pattern, bool verbose);
 
diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c
index 714b861923..3f75be4644 100644
--- a/src/bin/psql/help.c
+++ b/src/bin/psql/help.c
@@ -254,6 +254,7 @@ slashUsage(unsigned short int pager)
 	HELP0("  \\dFp[x+] [PATTERN]     list text search parsers\n");
 	HELP0("  \\dFt[x+] [PATTERN]     list text search templates\n");
 	HELP0("  \\dg[Sx+] [PATTERN]     list roles\n");
+	HELP0("  \\dh[tix+] [PATTERN]    list high-level (root) relations\n");
 	HELP0("  \\di[Sx+] [PATTERN]     list indexes\n");
 	HELP0("  \\dl[x+]                list large objects, same as \\lo_list\n");
 	HELP0("  \\dL[Sx+] [PATTERN]     list procedural languages\n");
diff --git a/src/bin/psql/tab-complete.in.c b/src/bin/psql/tab-complete.in.c
index 8432be641a..2e0ff93b69 100644
--- a/src/bin/psql/tab-complete.in.c
+++ b/src/bin/psql/tab-complete.in.c
@@ -691,6 +691,16 @@ static const SchemaQuery Query_for_list_of_partitioned_tables = {
 	.result = "c.relname",
 };
 
+static const SchemaQuery Query_for_list_of_root_tables = {
+	.catname = "pg_catalog.pg_class c",
+	.selcondition = "c.relispartition = false AND "
+	"c.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
+	CppAsString2(RELKIND_PARTITIONED_TABLE) ")",
+	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
+	.namespace = "c.relnamespace",
+	.result = "c.relname",
+};
+
 static const SchemaQuery Query_for_list_of_tables_for_constraint = {
 	.catname = "pg_catalog.pg_class c, pg_catalog.pg_constraint con",
 	.selcondition = "c.oid=con.conrelid and c.relkind IN ("
@@ -795,6 +805,16 @@ static const SchemaQuery Query_for_list_of_partitioned_indexes = {
 	.result = "c.relname",
 };
 
+static const SchemaQuery Query_for_list_of_root_indexes = {
+	.catname = "pg_catalog.pg_class c",
+	.selcondition = "c.relispartition = false AND "
+	"c.relkind IN (" CppAsString2(RELKIND_INDEX) ", "
+	CppAsString2(RELKIND_PARTITIONED_INDEX) ")",
+	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
+	.namespace = "c.relnamespace",
+	.result = "c.relname",
+};
+
 
 /* All relations */
 static const SchemaQuery Query_for_list_of_relations = {
@@ -814,6 +834,19 @@ static const SchemaQuery Query_for_list_of_partitioned_relations = {
 	.result = "c.relname",
 };
 
+/* root relations */
+static const SchemaQuery Query_for_list_of_root_relations = {
+	.catname = "pg_catalog.pg_class c",
+	.selcondition = "c.relispartition = false AND "
+	"c.relkind IN (" CppAsString2(RELKIND_RELATION) ", "
+	CppAsString2(RELKIND_PARTITIONED_TABLE) ", "
+	CppAsString2(RELKIND_INDEX) ", "
+	CppAsString2(RELKIND_PARTITIONED_INDEX) ")",
+	.viscondition = "pg_catalog.pg_table_is_visible(c.oid)",
+	.namespace = "c.relnamespace",
+	.result = "c.relname",
+};
+
 static const SchemaQuery Query_for_list_of_operator_families = {
 	.catname = "pg_catalog.pg_opfamily c",
 	.viscondition = "pg_catalog.pg_opfamily_is_visible(c.oid)",
@@ -1880,7 +1913,8 @@ psql_completion(const char *text, int start, int end)
 		"\\d", "\\da", "\\dA", "\\dAc", "\\dAf", "\\dAo", "\\dAp",
 		"\\db", "\\dc", "\\dconfig", "\\dC", "\\dd", "\\ddp", "\\dD",
 		"\\des", "\\det", "\\deu", "\\dew", "\\dE", "\\df",
-		"\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl", "\\dL",
+		"\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\dh", "\\dhi", "\\dht",
+		"\\di", "\\dl", "\\dL",
 		"\\dm", "\\dn", "\\do", "\\dO", "\\dp", "\\dP", "\\dPi", "\\dPt",
 		"\\drds", "\\drg", "\\dRs", "\\dRp", "\\ds",
 		"\\dt", "\\dT", "\\dv", "\\du", "\\dx", "\\dX", "\\dy",
@@ -5269,8 +5303,15 @@ match_previous_words(int pattern_id,
 	else if (TailMatchesCS("\\dFt*"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_ts_templates);
 	/* must be at end of \dF alternatives: */
+
 	else if (TailMatchesCS("\\dF*"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_ts_configurations);
+	else if (TailMatchesCS("\\dhi*"))
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_root_indexes);
+	else if (TailMatchesCS("\\dht*"))
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_root_tables);
+	else if (TailMatchesCS("\\dh*"))
+		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_root_relations);
 
 	else if (TailMatchesCS("\\di*"))
 		COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_indexes);
diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out
index 6543e90de7..7ba2fff391 100644
--- a/src/test/regress/expected/psql.out
+++ b/src/test/regress/expected/psql.out
@@ -5017,6 +5017,33 @@ create index testpart_orange_index on testpart_orange(logdate);
  testpart | testpart_apple_index | regress_partitioning_role |             | testpart_apple
 (1 row)
 
+-- only root relations should be displayed
+\dh test*apple*
+                                       List of root relations
+  Schema  |         Name          |           Owner           |       Type        |      Table      
+----------+-----------------------+---------------------------+-------------------+-----------------
+ testpart | testtable_apple       | regress_partitioning_role | table             | 
+ testpart | testpart_apple        | regress_partitioning_role | partitioned table | 
+ testpart | testpart_apple_index  | regress_partitioning_role | partitioned index | testpart_apple
+ testpart | testtable_apple_index | regress_partitioning_role | index             | testtable_apple
+(4 rows)
+
+\dht test*apple*
+                  List of root tables
+  Schema  |      Name       |           Owner           
+----------+-----------------+---------------------------
+ testpart | testpart_apple  | regress_partitioning_role
+ testpart | testtable_apple | regress_partitioning_role
+(2 rows)
+
+\dhi test*apple*
+                              List of root indexes
+  Schema  |         Name          |           Owner           |      Table      
+----------+-----------------------+---------------------------+-----------------
+ testpart | testpart_apple_index  | regress_partitioning_role | testpart_apple
+ testpart | testtable_apple_index | regress_partitioning_role | testtable_apple
+(2 rows)
+
 drop table testtable_apple;
 drop table testtable_orange;
 drop table testpart_apple;
@@ -5038,6 +5065,7 @@ create table child_30_35 partition of child_30_40
 create table child_35_40 partition of child_30_40
    for values from (35) to (40);
 insert into parent_tab values (generate_series(30,39));
+-- only partition related object should be displayed
 \dPt
             List of partitioned tables
   Schema  |    Name    |           Owner           
@@ -5106,6 +5134,37 @@ insert into parent_tab values (generate_series(30,39));
  testpart | child_30_40_id_idx | regress_partitioning_role | partitioned index | parent_index | child_30_40
 (4 rows)
 
+-- only root relations should be displayed
+\dht
+                List of root tables
+  Schema  |    Name    |           Owner           
+----------+------------+---------------------------
+ testpart | parent_tab | regress_partitioning_role
+(1 row)
+
+\dhi
+                       List of root indexes
+  Schema  |     Name     |           Owner           |   Table    
+----------+--------------+---------------------------+------------
+ testpart | parent_index | regress_partitioning_role | parent_tab
+(1 row)
+
+\dh testpart.*
+                                List of root relations
+  Schema  |     Name     |           Owner           |       Type        |   Table    
+----------+--------------+---------------------------+-------------------+------------
+ testpart | parent_tab   | regress_partitioning_role | partitioned table | 
+ testpart | parent_index | regress_partitioning_role | partitioned index | parent_tab
+(2 rows)
+
+\dh
+                                List of root relations
+  Schema  |     Name     |           Owner           |       Type        |   Table    
+----------+--------------+---------------------------+-------------------+------------
+ testpart | parent_tab   | regress_partitioning_role | partitioned table | 
+ testpart | parent_index | regress_partitioning_role | partitioned index | parent_tab
+(2 rows)
+
 drop table parent_tab cascade;
 drop schema testpart;
 set search_path to default;
diff --git a/src/test/regress/sql/psql.sql b/src/test/regress/sql/psql.sql
index 97d1be3aac..5606f70a10 100644
--- a/src/test/regress/sql/psql.sql
+++ b/src/test/regress/sql/psql.sql
@@ -1257,6 +1257,11 @@ create index testpart_orange_index on testpart_orange(logdate);
 \dPt test*apple*
 \dPi test*apple*
 
+-- only root relations should be displayed
+\dh test*apple*
+\dht test*apple*
+\dhi test*apple*
+
 drop table testtable_apple;
 drop table testtable_orange;
 drop table testpart_apple;
@@ -1280,6 +1285,7 @@ create table child_35_40 partition of child_30_40
    for values from (35) to (40);
 insert into parent_tab values (generate_series(30,39));
 
+-- only partition related object should be displayed
 \dPt
 \dPi
 
@@ -1291,6 +1297,13 @@ insert into parent_tab values (generate_series(30,39));
 \dPn
 \dPn testpart.*
 
+-- only root relations should be displayed
+\dht
+\dhi
+
+\dh testpart.*
+\dh
+
 drop table parent_tab cascade;
 
 drop schema testpart;
-- 
2.39.5 (Apple Git-154)

Reply via email to