Hi

I am sending a prototype of patch. Now, it calculates size of partitioned
tables with recursive query. When any more simple method will be possible,
the size calculation will be changed.

postgres=# \dt+
                       List of relations
+--------+------------+-------+-------+---------+-------------+
| Schema |    Name    | Type  | Owner |  Size   | Description |
+--------+------------+-------+-------+---------+-------------+
| public | data       | table | pavel | 0 bytes |             |
| public | data_2016  | table | pavel | 15 MB   |             |
| public | data_2017  | table | pavel | 15 MB   |             |
| public | data_other | table | pavel | 11 MB   |             |
+--------+------------+-------+-------+---------+-------------+
(4 rows)

postgres=# \dP+
          List of partitioned tables
+--------+------+-------+-------+-------------+
| Schema | Name | Owner | Size  | Description |
+--------+------+-------+-------+-------------+
| public | data | pavel | 42 MB |             |
+--------+------+-------+-------+-------------+
(1 row)

Regards

Pavel

p.s. Another patch can be replacement of relation type from "table" to
"partitioned table"

postgres=# \dt+
                             List of relations
+--------+------------+-------------------+-------+---------+-------------+
| Schema |    Name    |       Type        | Owner |  Size   | Description |
+--------+------------+-------------------+-------+---------+-------------+
| public | data       | partitioned table | pavel | 0 bytes |             |
| public | data_2016  | table             | pavel | 15 MB   |             |
| public | data_2017  | table             | pavel | 15 MB   |             |
| public | data_other | table             | pavel | 11 MB   |             |
+--------+------------+-------------------+-------+---------+-------------+
(4 rows)

A patch is simple for this case

diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index c3bdf8555d..491e58eb29 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -3490,8 +3490,8 @@ listTables(const char *tabtypes, const char *pattern,
bool verbose, bool showSys
                      gettext_noop("sequence"),
                      gettext_noop("special"),
                      gettext_noop("foreign table"),
-                     gettext_noop("table"),    /* partitioned table */
-                     gettext_noop("index"),    /* partitioned index */
+                     gettext_noop("partitioned table"),    /* partitioned
table */
+                     gettext_noop("partitioned index"),    /* partitioned
index */
                      gettext_noop("Type"),
                      gettext_noop("Owner"));
diff --git a/doc/src/sgml/ref/psql-ref.sgml b/doc/src/sgml/ref/psql-ref.sgml
index b17039d60f..d2eb701a96 100644
--- a/doc/src/sgml/ref/psql-ref.sgml
+++ b/doc/src/sgml/ref/psql-ref.sgml
@@ -1635,6 +1635,21 @@ testdb=>
         </listitem>
       </varlistentry>
 
+
+      <varlistentry>
+        <term><literal>\dP[+] [ <link linkend="app-psql-patterns"><replaceable class="parameter">pattern</replaceable></link> ]</literal></term>
+        <listitem>
+        <para>
+        Lists partitioned tables. If <replaceable class="parameter">pattern</replaceable> is
+        specified, only entries whose table name or schema name matches
+        the pattern are listed.  If the form <literal>\dP+</literal>
+        is used, a sum of size of related partitions and a description
+        are also displayed.
+        </para>
+        </listitem>
+      </varlistentry>
+
+
       <varlistentry>
         <term><literal>\drds [ <link linkend="app-psql-patterns"><replaceable class="parameter">role-pattern</replaceable></link> [ <link linkend="app-psql-patterns"><replaceable class="parameter">database-pattern</replaceable></link> ] ]</literal></term>
         <listitem>
diff --git a/src/bin/psql/command.c b/src/bin/psql/command.c
index 4c85f43f09..09f49b4f39 100644
--- a/src/bin/psql/command.c
+++ b/src/bin/psql/command.c
@@ -785,6 +785,9 @@ exec_command_d(PsqlScanState scan_state, bool active_branch, const char *cmd)
 			case 'p':
 				success = permissionsList(pattern);
 				break;
+			case 'P':
+				success = listPartitions(pattern, show_verbose);
+				break;
 			case 'T':
 				success = describeTypes(pattern, show_verbose, show_system);
 				break;
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index c3bdf8555d..4542fd511c 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -3601,6 +3601,122 @@ listTables(const char *tabtypes, const char *pattern, bool verbose, bool showSys
 	return true;
 }
 
+/*
+ * listPartitions()
+ *
+ * handler for \dP
+ */
+bool
+listPartitions(const char *pattern, bool verbose)
+{
+	PQExpBufferData buf;
+	PGresult   *res;
+	printQueryOpt myopt = pset.popt;
+	static const bool translate_columns[] = {false, false, true, false, false, false, false};
+
+	initPQExpBuffer(&buf);
+
+	/*
+	 * Note: as of Pg 8.2, we no longer use relkind 's' (special), but we keep
+	 * it here for backwards compatibility.
+	 */
+	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 (verbose)
+	{
+		/* CTE is supported from 8.4 */
+		if (pset.sversion >= 80400)
+		{
+			appendPQExpBuffer(&buf,
+							  ",\n  (WITH RECURSIVE d\n"
+							  "        AS (SELECT inhrelid AS oid\n"
+							  "              FROM pg_inherits\n"
+							  "             WHERE inhparent = c.oid\n"
+							  "            UNION ALL\n"
+							  "            SELECT inhrelid\n"
+							  "              FROM pg_inherits i\n"
+							  "                   JOIN d ON i.inhparent = d.oid)\n");
+
+			if (pset.sversion >= 90000)
+				appendPQExpBuffer(&buf,
+							  "         SELECT pg_catalog.pg_size_pretty(sum(pg_table_size(");
+			else
+				appendPQExpBuffer(&buf,
+							  "         SELECT pg_catalog.pg_size_pretty(sum(pg_relation_size(");
+
+			appendPQExpBuffer(&buf,
+							  "oid))) FROM d) AS \"%s\"",
+							  gettext_noop("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");
+
+	appendPQExpBufferStr(&buf, "\nWHERE c.relkind IN ('p')\n");
+
+	if (!pattern)
+		appendPQExpBufferStr(&buf, "      AND n.nspname <> 'pg_catalog'\n"
+							 "      AND n.nspname <> 'information_schema'\n");
+
+	/*
+	 * TOAST objects are suppressed unconditionally.  Since we don't provide
+	 * any way to select RELKIND_TOASTVALUE above, we would never show toast
+	 * tables in any case; it seems a bit confusing to allow their indexes to
+	 * be shown.  Use plain \d if you really need to look at a TOAST
+	 * table/index.
+	 */
+	appendPQExpBufferStr(&buf, "      AND n.nspname !~ '^pg_toast'\n");
+
+	processSQLNamePattern(pset.db, &buf, pattern, true, false,
+						  "n.nspname", "c.relname", NULL,
+						  "pg_catalog.pg_table_is_visible(c.oid)");
+
+	appendPQExpBufferStr(&buf, "ORDER BY 1,2;");
+
+	res = PSQLexec(buf.data);
+	termPQExpBuffer(&buf);
+	if (!res)
+		return false;
+
+	/*
+	 * Most functions in this file are content to print an empty table when
+	 * there are no matching objects.  We intentionally deviate from that
+	 * here, but only in !quiet mode, for historical reasons.
+	 */
+	if (PQntuples(res) == 0 && !pset.quiet)
+	{
+		if (pattern)
+			psql_error("Did not find any relation named \"%s\".\n",
+					   pattern);
+		else
+			psql_error("Did not find any relations.\n");
+	}
+	else
+	{
+		myopt.nullPrint = NULL;
+		myopt.title = _("List of partitioned tables");
+		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;
+}
 
 /*
  * \dL
diff --git a/src/bin/psql/describe.h b/src/bin/psql/describe.h
index a4cc5efae0..0fb7c4b91e 100644
--- a/src/bin/psql/describe.h
+++ b/src/bin/psql/describe.h
@@ -63,6 +63,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);
 
+/* \dP */
+extern bool listPartitions(const char *pattern, bool verbose);
+
 /* \dD */
 extern bool listDomains(const char *pattern, bool verbose, bool showSystem);
 
diff --git a/src/bin/psql/help.c b/src/bin/psql/help.c
index 702e742af4..ccb85e8cb1 100644
--- a/src/bin/psql/help.c
+++ b/src/bin/psql/help.c
@@ -167,7 +167,7 @@ slashUsage(unsigned short int pager)
 	 * Use "psql --help=commands | wc" to count correctly.  It's okay to count
 	 * the USE_READLINE line even in builds without that.
 	 */
-	output = PageOutput(125, pager ? &(pset.popt.topt) : NULL);
+	output = PageOutput(126, pager ? &(pset.popt.topt) : NULL);
 
 	fprintf(output, _("General\n"));
 	fprintf(output, _("  \\copyright             show PostgreSQL usage and distribution terms\n"));
@@ -254,6 +254,7 @@ slashUsage(unsigned short int pager)
 	fprintf(output, _("  \\dRs[+] [PATTERN]      list replication subscriptions\n"));
 	fprintf(output, _("  \\ds[S+] [PATTERN]      list sequences\n"));
 	fprintf(output, _("  \\dt[S+] [PATTERN]      list tables\n"));
+	fprintf(output, _("  \\dP[+] [PATTERN]       list partitioned tables\n"));
 	fprintf(output, _("  \\dT[S+] [PATTERN]      list data types\n"));
 	fprintf(output, _("  \\du[S+] [PATTERN]      list roles\n"));
 	fprintf(output, _("  \\dv[S+] [PATTERN]      list views\n"));
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index bb696f8ee9..ce911983dc 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -1621,7 +1621,7 @@ psql_completion(const char *text, int start, int end)
 		"\\d", "\\da", "\\dA", "\\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",
+		"\\dm", "\\dn", "\\do", "\\dO", "\\dp", "\\dP",
 		"\\drds", "\\dRs", "\\dRp", "\\ds", "\\dS",
 		"\\dt", "\\dT", "\\dv", "\\du", "\\dx", "\\dy",
 		"\\e", "\\echo", "\\ef", "\\elif", "\\else", "\\encoding",

Reply via email to