diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index bac94a3..9ee45c7 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -3417,36 +3417,104 @@ describeOneTableDetails(const char *schemaname, PQclear(result); } - /* print child tables (with additional info if partitions) */ - if (pset.sversion >= 140000) - 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" - "ORDER BY pg_catalog.pg_get_expr(c.relpartbound, c.oid) = 'DEFAULT'," - " c.oid::pg_catalog.regclass::pg_catalog.text;", - oid); - else if (pset.sversion >= 100000) - 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" - "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" - "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;", - oid); - + /* print child tables (with additional info if partitions) */ + if (pset.sversion >= 140000) + printfPQExpBuffer(&buf, + "WITH RECURSIVE partition_tree AS ( " + " SELECT c.oid::pg_catalog.regclass AS object_name, " + " c.oid," + " 0 AS level," + " c.relkind," + " i.inhdetachpending," + " pg_get_expr(c.relpartbound, c.oid) AS relpartbound," + " array[c.relname::text] AS path \n" + " FROM pg_catalog.pg_class c \n" + " JOIN pg_catalog.pg_inherits i ON c.oid = i.inhrelid \n" + " WHERE i.inhparent ='%s' \n" + " UNION ALL \n" + " SELECT c.oid::pg_catalog.regclass AS object_name," + " c.oid," + " pt.level + 1 AS level," + " c.relkind," + " i.inhdetachpending," + " pg_get_expr(c.relpartbound, c.oid) AS relpartbound," + " pt.path || c.relname::text \n" + " FROM pg_catalog.pg_class c \n" + " JOIN pg_catalog.pg_inherits i ON c.oid = i.inhrelid \n" + " JOIN partition_tree pt ON i.inhparent = pt.oid \n" + " WHERE pt.level < 1 \n" + ") \n" + " SELECT REPEAT(E'\t', level) || object_name AS oid," + " relkind," + " inhdetachpending," + " relpartbound as pg_get_expr \n" + "FROM partition_tree t \n" + "ORDER BY path, array_to_string(t.path || array[t.object_name::text], '.'), t.object_name, relpartbound = 'DEFAULT';", + oid); + else if (pset.sversion >= 100000) + printfPQExpBuffer(&buf, + "WITH RECURSIVE partition_tree AS (\n" + " SELECT c.oid::pg_catalog.regclass AS partition_name," + " c.oid," + " 0 AS level," + " c.relkind," + " false AS i.inhdetachpending," + " pg_catalog.pg_get_expr(c.relpartbound, c.oid) AS relpartbound" + " array[c.relname::text] AS path \n" + " FROM pg_catalog.pg_class c " + " JOIN pg_catalog.pg_inherits i ON c.oid = i.inhrelid\n" + " WHERE i.inhparent = '%s'\n" + " UNION ALL" + " SELECT c.oid::pg_catalog.regclass AS partition_name," + " c.oid," + " pt.level + 1 AS level," + " c.relkind," + " false AS i.inhdetachpending," + " pg_catalog.pg_get_expr(c.relpartbound, c.oid) AS relpartbound" + " pt.path || c.relname::text\n" + " FROM pg_catalog.pg_class c" + " JOIN pg_catalog.pg_inherits i ON c.oid = i.inhrelid" + " JOIN partition_tree pt ON i.inhparent = pt.oid" + " WHERE pt.level < 1 \n" + ")\n" + "SELECT REPEAT(' ', level * 4) || partition_name AS oid," + " relkind," + " inhdetachpending," + " relpartbound as pg_get_expr\n" + "FROM partition_tree\n" + "ORDER BY partition_name::pg_catalog.text, level, relpartbound = 'DEFAULT';", + oid); + else + printfPQExpBuffer(&buf, + "WITH RECURSIVE partition_tree AS (\n" + " SELECT c.oid::pg_catalog.regclass AS partition_name," + " c.oid," + " 0 AS level," + " c.relkind," + " false AS i.inhdetachpending," + " array[c.relname::text] AS path \n" + " FROM pg_catalog.pg_class c " + " JOIN pg_catalog.pg_inherits i ON c.oid = i.inhrelid\n" + " WHERE i.inhparent = '%s'\n" + " UNION ALL" + " SELECT c.oid::pg_catalog.regclass AS partition_name," + " c.oid," + " pt.level + 1 AS level," + " c.relkind," + " false AS i.inhdetachpending," + " pt.path || c.relname::text\n" + " FROM pg_catalog.pg_class c" + " JOIN pg_catalog.pg_inherits i ON c.oid = i.inhrelid" + " JOIN partition_tree pt ON i.inhparent = pt.oid" + " WHERE pt.level < 1 \n" + ")\n" + "SELECT REPEAT(' ', level * 4) || partition_name AS oid," + " relkind," + " inhdetachpending," + " NULL\n" + "FROM partition_tree\n" + "ORDER BY partition_name::pg_catalog.text, level, relpartbound = 'DEFAULT';", + oid); result = PSQLexec(buf.data); if (!result) goto error_return; @@ -3495,7 +3563,7 @@ describeOneTableDetails(const char *schemaname, appendPQExpBuffer(&buf, " %s", PQgetvalue(result, i, 3)); if (child_relkind == RELKIND_PARTITIONED_TABLE || child_relkind == RELKIND_PARTITIONED_INDEX) - appendPQExpBufferStr(&buf, ", PARTITIONED"); + appendPQExpBufferStr(&buf, ", CONTAINS SUBPARTITIONS"); else if (child_relkind == RELKIND_FOREIGN_TABLE) appendPQExpBufferStr(&buf, ", FOREIGN"); if (strcmp(PQgetvalue(result, i, 2), "t") == 0) diff --git a/src/test/regress/expected/subpartition_indentation.out b/src/test/regress/expected/subpartition_indentation.out new file mode 100644 index 0000000..7239685 --- /dev/null +++ b/src/test/regress/expected/subpartition_indentation.out @@ -0,0 +1,100 @@ +-- +-- Tests for psql subpartition indentation in \d+ [table] +-- + +CREATE TABLE +CREATE TABLE +CREATE TABLE +CREATE TABLE +CREATE TABLE +CREATE TABLE +CREATE TABLE +CREATE TABLE +CREATE TABLE +CREATE TABLE +CREATE TABLE +CREATE TABLE +CREATE TABLE +CREATE TABLE +CREATE TABLE +CREATE TABLE +CREATE TABLE +CREATE TABLE +CREATE TABLE +CREATE TABLE +CREATE TABLE +CREATE TABLE + Partitioned table "public.p_quarter_check" + Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description +--------+-----------------------+-----------+----------+---------+----------+-------------+--------------+------------- + id | integer | | not null | | plain | | | + dept | character varying(10) | | | | extended | | | + name | character varying(20) | | | | extended | | | + in_d | date | | not null | | plain | | | + etc | text | | | | extended | | | +Partition key: RANGE (in_d) +Partitions: in_p_q1 FOR VALUES FROM ('2023-01-01') TO ('2023-04-01'), CONTAINS SUBPARTITIONES, + in_p_m202301 FOR VALUES FROM ('2023-01-01') TO ('2023-02-01'), CONTAINS SUBPARTITIONES, + in_p_m202302 FOR VALUES FROM ('2023-02-01') TO ('2023-03-01'), CONTAINS SUBPARTITIONES, + in_p_m202303 FOR VALUES FROM ('2023-03-01') TO ('2023-04-01'), CONTAINS SUBPARTITIONES, + in_p_q2 FOR VALUES FROM ('2023-04-01') TO ('2023-07-01'), CONTAINS SUBPARTITIONES, + in_p_m202304 FOR VALUES FROM ('2023-04-01') TO ('2023-05-01'), CONTAINS SUBPARTITIONES, + in_p_m202305 FOR VALUES FROM ('2023-05-01') TO ('2023-06-01'), CONTAINS SUBPARTITIONES, + in_p_m202306 FOR VALUES FROM ('2023-06-01') TO ('2023-07-01'), CONTAINS SUBPARTITIONES, + in_p_q3 FOR VALUES FROM ('2023-07-01') TO ('2023-10-01'), CONTAINS SUBPARTITIONES, + in_p_m202307 FOR VALUES FROM ('2023-07-01') TO ('2023-08-01'), CONTAINS SUBPARTITIONES, + in_p_m202308 FOR VALUES FROM ('2023-08-01') TO ('2023-09-01'), CONTAINS SUBPARTITIONES, + in_p_m202309 FOR VALUES FROM ('2023-09-01') TO ('2023-10-01'), CONTAINS SUBPARTITIONES, + in_p_q4 FOR VALUES FROM ('2023-10-01') TO ('2024-01-01'), CONTAINS SUBPARTITIONES, + in_p_m202310 FOR VALUES FROM ('2023-10-01') TO ('2023-11-01'), CONTAINS SUBPARTITIONES, + in_p_m202311 FOR VALUES FROM ('2023-11-01') TO ('2023-12-01'), CONTAINS SUBPARTITIONES, + in_p_m202312 FOR VALUES FROM ('2023-12-01') TO ('2024-01-01'), CONTAINS SUBPARTITIONES + + Partitioned table "public.in_p_q1" + Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description +--------+-----------------------+-----------+----------+---------+----------+-------------+--------------+------------- + id | integer | | not null | | plain | | | + dept | character varying(10) | | | | extended | | | + name | character varying(20) | | | | extended | | | + in_d | date | | not null | | plain | | | + etc | text | | | | extended | | | +Partition of: p_quarter_check FOR VALUES FROM ('2023-01-01') TO ('2023-04-01') +Partition constraint: ((in_d IS NOT NULL) AND (in_d >= '2023-01-01'::date) AND (in_d < '2023-04-01'::date)) +Partition key: RANGE (in_d) +Partitions: in_p_m202301 FOR VALUES FROM ('2023-01-01') TO ('2023-02-01'), CONTAINS SUBPARTITIONES, + in_p_w202301 FOR VALUES FROM ('2023-01-01') TO ('2023-01-08'), + in_p_w202302 FOR VALUES FROM ('2023-01-08') TO ('2023-01-15'), + in_p_w202303 FOR VALUES FROM ('2023-01-15') TO ('2023-01-22'), + in_p_w202304 FOR VALUES FROM ('2023-01-22') TO ('2023-01-29'), + in_p_w202305 FOR VALUES FROM ('2023-01-29') TO ('2023-02-01'), + in_p_m202302 FOR VALUES FROM ('2023-02-01') TO ('2023-03-01'), CONTAINS SUBPARTITIONES, + in_p_m202303 FOR VALUES FROM ('2023-03-01') TO ('2023-04-01'), CONTAINS SUBPARTITIONES + + Partitioned table "public.in_p_m202301" + Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description +--------+-----------------------+-----------+----------+---------+----------+-------------+--------------+------------- + id | integer | | not null | | plain | | | + dept | character varying(10) | | | | extended | | | + name | character varying(20) | | | | extended | | | + in_d | date | | not null | | plain | | | + etc | text | | | | extended | | | +Partition of: in_p_q1 FOR VALUES FROM ('2023-01-01') TO ('2023-02-01') +Partition constraint: ((in_d IS NOT NULL) AND (in_d >= '2023-01-01'::date) AND (in_d < '2023-04-01'::date) AND (in_d IS NOT NULL) AND (in_d >= '2023-01-01'::date) AND (in_d < '2023-02-01'::date)) +Partition key: RANGE (in_d) +Partitions: in_p_w202301 FOR VALUES FROM ('2023-01-01') TO ('2023-01-08'), + in_p_w202302 FOR VALUES FROM ('2023-01-08') TO ('2023-01-15'), + in_p_w202303 FOR VALUES FROM ('2023-01-15') TO ('2023-01-22'), + in_p_w202304 FOR VALUES FROM ('2023-01-22') TO ('2023-01-29'), + in_p_w202305 FOR VALUES FROM ('2023-01-29') TO ('2023-02-01') + + Table "public.in_p_w202301" + Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description +--------+-----------------------+-----------+----------+---------+----------+-------------+--------------+------------- + id | integer | | not null | | plain | | | + dept | character varying(10) | | | | extended | | | + name | character varying(20) | | | | extended | | | + in_d | date | | not null | | plain | | | + etc | text | | | | extended | | | +Partition of: in_p_m202301 FOR VALUES FROM ('2023-01-01') TO ('2023-01-08') +Partition constraint: ((in_d IS NOT NULL) AND (in_d >= '2023-01-01'::date) AND (in_d < '2023-04-01'::date) AND (in_d IS NOT NULL) AND (in_d >= '2023-01-01'::date) AND (in_d < '2023-02-01'::date) AND (in_d IS NOT NULL) AND (in_d >= '2023-01-01'::date) AND (in_d < '2023-01-08'::date)) +Access method: heap diff --git a/src/test/regress/sql/subpartition_indentation.sql b/src/test/regress/sql/subpartition_indentation.sql new file mode 100644 index 0000000..1303ae7 --- /dev/null +++ b/src/test/regress/sql/subpartition_indentation.sql @@ -0,0 +1,46 @@ +-- +-- Tests for psql subpartition indentation in \d+ [table] +-- + +-- Test partition table & subpartition table create +create table p_quarter_check( + id int not null + , dept varchar(10) + , name varchar(20) + , in_d date not null + , etc text) + partition by range(in_d) ; + +create table in_p_q1 partition of p_quarter_check for values from ('20230101') to ('20230401') PARTITION BY range (in_d) ; +create table in_p_q2 partition of p_quarter_check for values from ('20230401') to ('20230701') PARTITION BY range (in_d) ; +create table in_p_q3 partition of p_quarter_check for values from ('20230701') to ('20231001') PARTITION BY range (in_d) ; +create table in_p_q4 partition of p_quarter_check for values from ('20231001') to ('20240101') PARTITION BY range (in_d) ; + +create table in_p_m202301 partition of in_p_q1 for values from ('20230101') to ('20230201') PARTITION BY range (in_d) ; +create table in_p_m202302 partition of in_p_q1 for values from ('20230201') to ('20230301') PARTITION BY range (in_d) ; +create table in_p_m202303 partition of in_p_q1 for values from ('20230301') to ('20230401') PARTITION BY range (in_d) ; + +create table in_p_m202304 partition of in_p_q2 for values from ('20230401') to ('20230501') PARTITION BY range (in_d); +create table in_p_m202305 partition of in_p_q2 for values from ('20230501') to ('20230601') PARTITION BY range (in_d); +create table in_p_m202306 partition of in_p_q2 for values from ('20230601') to ('20230701') PARTITION BY range (in_d); + +create table in_p_m202307 partition of in_p_q3 for values from ('20230701') to ('20230801') PARTITION BY range (in_d); +create table in_p_m202308 partition of in_p_q3 for values from ('20230801') to ('20230901') PARTITION BY range (in_d); +create table in_p_m202309 partition of in_p_q3 for values from ('20230901') to ('20231001') PARTITION BY range (in_d); + +create table in_p_m202310 partition of in_p_q4 for values from ('20231001') to ('20231101') PARTITION BY range (in_d); +create table in_p_m202311 partition of in_p_q4 for values from ('20231101') to ('20231201') PARTITION BY range (in_d); +create table in_p_m202312 partition of in_p_q4 for values from ('20231201') to ('20240101') PARTITION BY range (in_d); + +create table in_p_w202301 partition of in_p_m202301 for values from ('20230101') to ('20230108') ; +create table in_p_w202302 partition of in_p_m202301 for values from ('20230108') to ('20230115') ; +create table in_p_w202303 partition of in_p_m202301 for values from ('20230115') to ('20230122') ; +create table in_p_w202304 partition of in_p_m202301 for values from ('20230122') to ('20230129') ; +create table in_p_w202305 partition of in_p_m202301 for values from ('20230129') to ('20230201') ; + +-- Test partition indentation +\d+ p_quarter_check +\d+ in_p_q1 +\d+ in_p_m202301 +\d+ in_p_w202301 +