Hi

Recently I have been working a lot with partitioned tables which contain a mix
of local and foreign partitions, and find it would be very useful to be able to
easily obtain an overview of which partitions are foreign and where they are
located.

Currently, executing "\d+" on a partitioned table lists the partitions
like this:

    postgres=# \d+ parttest
                                       Partitioned table "public.parttest"
     Column |  Type   | Collation | Nullable | Default | Storage  |
Compression | Stats target | Description
    
--------+---------+-----------+----------+---------+----------+-------------+--------------+-------------
     id     | integer |           | not null |         | plain    |
         |              |
     val1   | text    |           |          |         | extended |
         |              |
     val2   | text    |           |          |         | extended |
         |              |
    Partition key: HASH (id)
    Partitions: parttest_10_0 FOR VALUES WITH (modulus 10, remainder 0),
                parttest_10_1 FOR VALUES WITH (modulus 10, remainder 1),
                parttest_10_2 FOR VALUES WITH (modulus 10, remainder 2),
                parttest_10_3 FOR VALUES WITH (modulus 10, remainder 3),
                parttest_10_4 FOR VALUES WITH (modulus 10, remainder 4),
                parttest_10_5 FOR VALUES WITH (modulus 10, remainder 5),
                parttest_10_6 FOR VALUES WITH (modulus 10, remainder 6),
                parttest_10_7 FOR VALUES WITH (modulus 10, remainder 7),
                parttest_10_8 FOR VALUES WITH (modulus 10, remainder 8),
                parttest_10_9 FOR VALUES WITH (modulus 10, remainder 9)

which doesn't help much in that respect.

Attached patch changes this output to:

    postgres=# \d+ parttest
                                       Partitioned table "public.parttest"
     Column |  Type   | Collation | Nullable | Default | Storage  |
Compression | Stats target | Description
    
--------+---------+-----------+----------+---------+----------+-------------+--------------+-------------
     id     | integer |           | not null |         | plain    |
         |              |
     val1   | text    |           |          |         | extended |
         |              |
     val2   | text    |           |          |         | extended |
         |              |
    Partition key: HASH (id)
    Partitions: parttest_10_0 FOR VALUES WITH (modulus 10, remainder 0),
                parttest_10_1 FOR VALUES WITH (modulus 10, remainder
1), server: "fdw_node2",
                parttest_10_2 FOR VALUES WITH (modulus 10, remainder 2),
                parttest_10_3 FOR VALUES WITH (modulus 10, remainder
3), server: "fdw_node2",
                parttest_10_4 FOR VALUES WITH (modulus 10, remainder 4),
                parttest_10_5 FOR VALUES WITH (modulus 10, remainder
5), server: "fdw_node2",
                parttest_10_6 FOR VALUES WITH (modulus 10, remainder 6),
                parttest_10_7 FOR VALUES WITH (modulus 10, remainder
7), server: "fdw_node2",
                parttest_10_8 FOR VALUES WITH (modulus 10, remainder 8),
                parttest_10_9 FOR VALUES WITH (modulus 10, remainder
9), server: "fdw_node2"

which is much more informative, albeit a little more cluttered, but
short of using
emojis I can't see any better way (suggestions welcome).

For completeness, output with child tables could look like this:

    postgres=# \d+ inhtest
                                             Table "public.inhtest"
     Column |  Type   | Collation | Nullable | Default | Storage  |
Compression | Stats target | Description
    
--------+---------+-----------+----------+---------+----------+-------------+--------------+-------------
     id     | integer |           | not null |         | plain    |
         |              |
     val1   | text    |           |          |         | extended |
         |              |
     val2   | text    |           |          |         | extended |
         |              |
    Child tables: inhtest_10_0,
                  inhtest_10_1 (server: "fdw_node2"),
                  inhtest_10_2,
                  inhtest_10_3 (server: "fdw_node2"),
                  inhtest_10_4,
                  inhtest_10_5 (server: "fdw_node2"),
                  inhtest_10_6,
                  inhtest_10_7 (server: "fdw_node2"),
                  inhtest_10_8,
                  inhtest_10_9 (server: "fdw_node2")
    Access method: heap

Will add to next CF.


Regards

Ian Barwick
commit d5f5de96381b93a6ea1066d4abb4c6617e0af758
Author: Ian Barwick <barw...@gmail.com>
Date:   Thu Oct 20 12:45:28 2022 +0900

    psql: in \d+, indicate foreign partitions
    
    Currently with a partitioned table, \d+ lists the partitions and their
    partition key, but it would be useful to see which ones, if any, are
    foreign partitions.
    
    A simple way of doing this is, for foreign partitions, to display the
    name of the partition's foreign server.

diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index c645d66418..3bb491cc6c 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -3371,9 +3371,12 @@ describeOneTableDetails(const char *schemaname,
 			printfPQExpBuffer(&buf,
 							  "SELECT c.oid::pg_catalog.regclass, c.relkind,"
 							  " inhdetachpending,"
-							  " pg_catalog.pg_get_expr(c.relpartbound, c.oid)\n"
-							  "FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i\n"
-							  "WHERE c.oid = i.inhrelid AND i.inhparent = '%s'\n"
+							  " pg_catalog.pg_get_expr(c.relpartbound, c.oid),\n"
+							  " s.srvname\n"
+							  "FROM pg_catalog.pg_class c\n"
+							  "JOIN pg_catalog.pg_inherits i ON c.oid = i.inhrelid AND i.inhparent = '%s'\n"
+							  "LEFT JOIN pg_catalog.pg_foreign_table ft ON (ft.ftrelid = c.oid)\n"
+							  "LEFT JOIN pg_catalog.pg_foreign_server s ON (s.oid = ft.ftserver)\n"
 							  "ORDER BY pg_catalog.pg_get_expr(c.relpartbound, c.oid) = 'DEFAULT',"
 							  " c.oid::pg_catalog.regclass::pg_catalog.text;",
 							  oid);
@@ -3381,16 +3384,19 @@ describeOneTableDetails(const char *schemaname,
 			printfPQExpBuffer(&buf,
 							  "SELECT c.oid::pg_catalog.regclass, c.relkind,"
 							  " false AS inhdetachpending,"
-							  " pg_catalog.pg_get_expr(c.relpartbound, c.oid)\n"
-							  "FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i\n"
-							  "WHERE c.oid = i.inhrelid AND i.inhparent = '%s'\n"
+							  " pg_catalog.pg_get_expr(c.relpartbound, c.oid),\n"
+							  " s.srvname\n"
+							  "FROM pg_catalog.pg_class c\n"
+							  "JOIN pg_catalog.pg_inherits i ON c.oid = i.inhrelid AND i.inhparent = '%s'\n"
+							  "LEFT JOIN pg_catalog.pg_foreign_table ft ON (ft.ftrelid = c.oid)\n"
+							  "LEFT JOIN pg_catalog.pg_foreign_server s ON (s.oid = ft.ftserver)\n"
 							  "ORDER BY pg_catalog.pg_get_expr(c.relpartbound, c.oid) = 'DEFAULT',"
 							  " c.oid::pg_catalog.regclass::pg_catalog.text;",
 							  oid);
 		else
 			printfPQExpBuffer(&buf,
 							  "SELECT c.oid::pg_catalog.regclass, c.relkind,"
-							  " false AS inhdetachpending, NULL\n"
+							  " false AS inhdetachpending, NULL, NULL\n"
 							  "FROM pg_catalog.pg_class c, pg_catalog.pg_inherits i\n"
 							  "WHERE c.oid = i.inhrelid AND i.inhparent = '%s'\n"
 							  "ORDER BY c.oid::pg_catalog.regclass::pg_catalog.text;",
@@ -3445,6 +3451,10 @@ describeOneTableDetails(const char *schemaname,
 				if (child_relkind == RELKIND_PARTITIONED_TABLE ||
 					child_relkind == RELKIND_PARTITIONED_INDEX)
 					appendPQExpBufferStr(&buf, ", PARTITIONED");
+				else if (child_relkind == RELKIND_FOREIGN_TABLE && is_partitioned)
+					appendPQExpBuffer(&buf, ", server: \"%s\"", PQgetvalue(result, i, 4));
+				else if (child_relkind == RELKIND_FOREIGN_TABLE && !is_partitioned)
+					appendPQExpBuffer(&buf, " (server: \"%s\")", PQgetvalue(result, i, 4));
 				if (strcmp(PQgetvalue(result, i, 2), "t") == 0)
 					appendPQExpBufferStr(&buf, " (DETACH PENDING)");
 				if (i < tuples - 1)
diff --git a/src/test/regress/expected/foreign_data.out b/src/test/regress/expected/foreign_data.out
index 9d7610b948..1d208fa3a4 100644
--- a/src/test/regress/expected/foreign_data.out
+++ b/src/test/regress/expected/foreign_data.out
@@ -1404,7 +1404,7 @@ CREATE FOREIGN TABLE ft2 () INHERITS (fd_pt1)
  c1     | integer |           | not null |         | plain    |              | 
  c2     | text    |           |          |         | extended |              | 
  c3     | date    |           |          |         | plain    |              | 
-Child tables: ft2
+Child tables: ft2 (server: "s0")
 
 \d+ ft2
                                        Foreign table "public.ft2"
@@ -1449,7 +1449,7 @@ ALTER FOREIGN TABLE ft2 INHERIT fd_pt1;
  c1     | integer |           | not null |         | plain    |              | 
  c2     | text    |           |          |         | extended |              | 
  c3     | date    |           |          |         | plain    |              | 
-Child tables: ft2
+Child tables: ft2 (server: "s0")
 
 \d+ ft2
                                        Foreign table "public.ft2"
@@ -1483,7 +1483,7 @@ Server: s0
 FDW options: (delimiter ',', quote '"', "be quoted" 'value')
 Inherits: fd_pt1
 Child tables: ct3,
-              ft3
+              ft3 (server: "s0")
 
 \d+ ct3
                                     Table "public.ct3"
@@ -1522,7 +1522,7 @@ ALTER TABLE fd_pt1 ADD COLUMN c8 integer;
  c6     | integer |           |          |         | plain    |              | 
  c7     | integer |           | not null |         | plain    |              | 
  c8     | integer |           |          |         | plain    |              | 
-Child tables: ft2
+Child tables: ft2 (server: "s0")
 
 \d+ ft2
                                        Foreign table "public.ft2"
@@ -1540,7 +1540,7 @@ Server: s0
 FDW options: (delimiter ',', quote '"', "be quoted" 'value')
 Inherits: fd_pt1
 Child tables: ct3,
-              ft3
+              ft3 (server: "s0")
 
 \d+ ct3
                                     Table "public.ct3"
@@ -1596,7 +1596,7 @@ ALTER TABLE fd_pt1 ALTER COLUMN c8 SET STORAGE EXTERNAL;
  c6     | integer |           | not null |         | plain    |              | 
  c7     | integer |           |          |         | plain    |              | 
  c8     | text    |           |          |         | external |              | 
-Child tables: ft2
+Child tables: ft2 (server: "s0")
 
 \d+ ft2
                                        Foreign table "public.ft2"
@@ -1614,7 +1614,7 @@ Server: s0
 FDW options: (delimiter ',', quote '"', "be quoted" 'value')
 Inherits: fd_pt1
 Child tables: ct3,
-              ft3
+              ft3 (server: "s0")
 
 -- drop attributes recursively
 ALTER TABLE fd_pt1 DROP COLUMN c4;
@@ -1629,7 +1629,7 @@ ALTER TABLE fd_pt1 DROP COLUMN c8;
  c1     | integer |           | not null |         | plain    | 10000        | 
  c2     | text    |           |          |         | extended |              | 
  c3     | date    |           |          |         | plain    |              | 
-Child tables: ft2
+Child tables: ft2 (server: "s0")
 
 \d+ ft2
                                        Foreign table "public.ft2"
@@ -1642,7 +1642,7 @@ Server: s0
 FDW options: (delimiter ',', quote '"', "be quoted" 'value')
 Inherits: fd_pt1
 Child tables: ct3,
-              ft3
+              ft3 (server: "s0")
 
 -- add constraints recursively
 ALTER TABLE fd_pt1 ADD CONSTRAINT fd_pt1chk1 CHECK (c1 > 0) NO INHERIT;
@@ -1669,7 +1669,7 @@ SELECT relname, conname, contype, conislocal, coninhcount, connoinherit
 Check constraints:
     "fd_pt1chk1" CHECK (c1 > 0) NO INHERIT
     "fd_pt1chk2" CHECK (c2 <> ''::text)
-Child tables: ft2
+Child tables: ft2 (server: "s0")
 
 \d+ ft2
                                        Foreign table "public.ft2"
@@ -1684,7 +1684,7 @@ Server: s0
 FDW options: (delimiter ',', quote '"', "be quoted" 'value')
 Inherits: fd_pt1
 Child tables: ct3,
-              ft3
+              ft3 (server: "s0")
 
 DROP FOREIGN TABLE ft2; -- ERROR
 ERROR:  cannot drop foreign table ft2 because other objects depend on it
@@ -1716,7 +1716,7 @@ ALTER FOREIGN TABLE ft2 INHERIT fd_pt1;
 Check constraints:
     "fd_pt1chk1" CHECK (c1 > 0) NO INHERIT
     "fd_pt1chk2" CHECK (c2 <> ''::text)
-Child tables: ft2
+Child tables: ft2 (server: "s0")
 
 \d+ ft2
                                        Foreign table "public.ft2"
@@ -1746,7 +1746,7 @@ ALTER TABLE fd_pt1 ADD CONSTRAINT fd_pt1chk3 CHECK (c2 <> '') NOT VALID;
  c3     | date    |           |          |         | plain    |              | 
 Check constraints:
     "fd_pt1chk3" CHECK (c2 <> ''::text) NOT VALID
-Child tables: ft2
+Child tables: ft2 (server: "s0")
 
 \d+ ft2
                                        Foreign table "public.ft2"
@@ -1773,7 +1773,7 @@ ALTER TABLE fd_pt1 VALIDATE CONSTRAINT fd_pt1chk3;
  c3     | date    |           |          |         | plain    |              | 
 Check constraints:
     "fd_pt1chk3" CHECK (c2 <> ''::text)
-Child tables: ft2
+Child tables: ft2 (server: "s0")
 
 \d+ ft2
                                        Foreign table "public.ft2"
@@ -1804,7 +1804,7 @@ ALTER TABLE fd_pt1 RENAME CONSTRAINT fd_pt1chk3 TO f2_check;
  f3     | date    |           |          |         | plain    |              | 
 Check constraints:
     "f2_check" CHECK (f2 <> ''::text)
-Child tables: ft2
+Child tables: ft2 (server: "s0")
 
 \d+ ft2
                                        Foreign table "public.ft2"
@@ -1862,7 +1862,7 @@ CREATE FOREIGN TABLE fd_pt2_1 PARTITION OF fd_pt2 FOR VALUES IN (1)
  c2     | text    |           |          |         | extended |              | 
  c3     | date    |           |          |         | plain    |              | 
 Partition key: LIST (c1)
-Partitions: fd_pt2_1 FOR VALUES IN (1)
+Partitions: fd_pt2_1 FOR VALUES IN (1), server: "s0"
 
 \d+ fd_pt2_1
                                      Foreign table "public.fd_pt2_1"
@@ -1934,7 +1934,7 @@ ALTER TABLE fd_pt2 ATTACH PARTITION fd_pt2_1 FOR VALUES IN (1);
  c2     | text    |           |          |         | extended |              | 
  c3     | date    |           |          |         | plain    |              | 
 Partition key: LIST (c1)
-Partitions: fd_pt2_1 FOR VALUES IN (1)
+Partitions: fd_pt2_1 FOR VALUES IN (1), server: "s0"
 
 \d+ fd_pt2_1
                                      Foreign table "public.fd_pt2_1"
@@ -1962,7 +1962,7 @@ ALTER TABLE fd_pt2_1 ADD CONSTRAINT p21chk CHECK (c2 <> '');
  c2     | text    |           |          |         | extended |              | 
  c3     | date    |           |          |         | plain    |              | 
 Partition key: LIST (c1)
-Partitions: fd_pt2_1 FOR VALUES IN (1)
+Partitions: fd_pt2_1 FOR VALUES IN (1), server: "s0"
 
 \d+ fd_pt2_1
                                      Foreign table "public.fd_pt2_1"

Reply via email to