Skip to content

Commit 3677a0b

Browse files
committed
Add pg_partition_root to display top-most parent of a partition tree
This is useful when looking at partition trees with multiple layers, and combined with pg_partition_tree, it provides the possibility to show up an entire tree by just knowing one member at any level. Author: Michael Paquier Reviewed-by: Álvaro Herrera, Amit Langote Discussion: https://postgr.es/m/20181207014015.GP2407@paquier.xyz
1 parent 34ea1ab commit 3677a0b

File tree

6 files changed

+153
-11
lines changed

6 files changed

+153
-11
lines changed

doc/src/sgml/func.sgml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20274,6 +20274,17 @@ postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup());
2027420274
their partitions, and so on.
2027520275
</entry>
2027620276
</row>
20277+
<row>
20278+
<entry>
20279+
<indexterm><primary>pg_partition_root</primary></indexterm>
20280+
<literal><function>pg_partition_root(<type>regclass</type>)</function></literal>
20281+
</entry>
20282+
<entry><type>regclass</type></entry>
20283+
<entry>
20284+
Return the top-most parent of a partition tree to which the given
20285+
relation belongs.
20286+
</entry>
20287+
</row>
2027720288
</tbody>
2027820289
</tgroup>
2027920290
</table>

src/backend/utils/adt/partitionfuncs.c

Lines changed: 65 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,33 @@
2525
#include "utils/lsyscache.h"
2626
#include "utils/syscache.h"
2727

28+
/*
29+
* Checks if a given relation can be part of a partition tree. Returns
30+
* false if the relation cannot be processed, in which case it is up to
31+
* the caller to decide what to do, by either raising an error or doing
32+
* something else.
33+
*/
34+
static bool
35+
check_rel_can_be_partition(Oid relid)
36+
{
37+
char relkind;
38+
39+
/* Check if relation exists */
40+
if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(relid)))
41+
return false;
42+
43+
relkind = get_rel_relkind(relid);
44+
45+
/* Only allow relation types that can appear in partition trees. */
46+
if (relkind != RELKIND_RELATION &&
47+
relkind != RELKIND_FOREIGN_TABLE &&
48+
relkind != RELKIND_INDEX &&
49+
relkind != RELKIND_PARTITIONED_TABLE &&
50+
relkind != RELKIND_PARTITIONED_INDEX)
51+
return false;
52+
53+
return true;
54+
}
2855

2956
/*
3057
* pg_partition_tree
@@ -39,19 +66,10 @@ pg_partition_tree(PG_FUNCTION_ARGS)
3966
{
4067
#define PG_PARTITION_TREE_COLS 4
4168
Oid rootrelid = PG_GETARG_OID(0);
42-
char relkind = get_rel_relkind(rootrelid);
4369
FuncCallContext *funcctx;
4470
ListCell **next;
4571

46-
if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(rootrelid)))
47-
PG_RETURN_NULL();
48-
49-
/* Return NULL for relation types that cannot appear in partition trees */
50-
if (relkind != RELKIND_RELATION &&
51-
relkind != RELKIND_FOREIGN_TABLE &&
52-
relkind != RELKIND_INDEX &&
53-
relkind != RELKIND_PARTITIONED_TABLE &&
54-
relkind != RELKIND_PARTITIONED_INDEX)
72+
if (!check_rel_can_be_partition(rootrelid))
5573
PG_RETURN_NULL();
5674

5775
/* stuff done only on the first call of the function */
@@ -153,3 +171,40 @@ pg_partition_tree(PG_FUNCTION_ARGS)
153171
/* done when there are no more elements left */
154172
SRF_RETURN_DONE(funcctx);
155173
}
174+
175+
/*
176+
* pg_partition_root
177+
*
178+
* Returns the top-most parent of the partition tree to which a given
179+
* relation belongs, or NULL if it's not (or cannot be) part of any
180+
* partition tree.
181+
*/
182+
Datum
183+
pg_partition_root(PG_FUNCTION_ARGS)
184+
{
185+
Oid relid = PG_GETARG_OID(0);
186+
Oid rootrelid;
187+
List *ancestors;
188+
189+
if (!check_rel_can_be_partition(relid))
190+
PG_RETURN_NULL();
191+
192+
/*
193+
* If the relation is not a partition (it may be the partition parent),
194+
* return itself as a result.
195+
*/
196+
if (!get_rel_relispartition(relid))
197+
PG_RETURN_OID(relid);
198+
199+
/* Fetch the top-most parent */
200+
ancestors = get_partition_ancestors(relid);
201+
rootrelid = llast_oid(ancestors);
202+
list_free(ancestors);
203+
204+
/*
205+
* "rootrelid" must contain a valid OID, given that the input relation is
206+
* a valid partition tree member as checked above.
207+
*/
208+
Assert(OidIsValid(rootrelid));
209+
PG_RETURN_OID(rootrelid);
210+
}

src/include/catalog/catversion.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/* yyyymmddN */
56-
#define CATALOG_VERSION_NO 201902071
56+
#define CATALOG_VERSION_NO 201902081
5757

5858
#endif

src/include/catalog/pg_proc.dat

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10509,4 +10509,9 @@
1050910509
proargnames => '{rootrelid,relid,parentrelid,isleaf,level}',
1051010510
prosrc => 'pg_partition_tree' },
1051110511

10512+
# function to get the top-most partition root parent
10513+
{ oid => '3424', descr => 'get top-most partition root parent',
10514+
proname => 'pg_partition_root', prorettype => 'regclass',
10515+
proargtypes => 'regclass', prosrc => 'pg_partition_root' },
10516+
1051210517
]

src/test/regress/expected/partition_info.out

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,18 @@ SELECT * FROM pg_partition_tree(0);
1212
| | |
1313
(1 row)
1414

15+
SELECT pg_partition_root(NULL);
16+
pg_partition_root
17+
-------------------
18+
19+
(1 row)
20+
21+
SELECT pg_partition_root(0);
22+
pg_partition_root
23+
-------------------
24+
25+
(1 row)
26+
1527
-- Test table partition trees
1628
CREATE TABLE ptif_test (a int, b int) PARTITION BY range (a);
1729
CREATE TABLE ptif_test0 PARTITION OF ptif_test
@@ -66,6 +78,20 @@ SELECT relid, parentrelid, level, isleaf
6678
ptif_test01 | ptif_test0 | 0 | t
6779
(1 row)
6880

81+
-- List all members using pg_partition_root with leaf table reference
82+
SELECT relid, parentrelid, level, isleaf
83+
FROM pg_partition_tree(pg_partition_root('ptif_test01')) p
84+
JOIN pg_class c ON (p.relid = c.oid);
85+
relid | parentrelid | level | isleaf
86+
-------------+-------------+-------+--------
87+
ptif_test | | 0 | f
88+
ptif_test0 | ptif_test | 1 | f
89+
ptif_test1 | ptif_test | 1 | f
90+
ptif_test2 | ptif_test | 1 | t
91+
ptif_test01 | ptif_test0 | 2 | t
92+
ptif_test11 | ptif_test1 | 2 | t
93+
(6 rows)
94+
6995
-- List all indexes members of the tree
7096
SELECT relid, parentrelid, level, isleaf
7197
FROM pg_partition_tree('ptif_test_index');
@@ -98,6 +124,20 @@ SELECT relid, parentrelid, level, isleaf
98124
ptif_test01_index | ptif_test0_index | 0 | t
99125
(1 row)
100126

127+
-- List all members using pg_partition_root with leaf index reference
128+
SELECT relid, parentrelid, level, isleaf
129+
FROM pg_partition_tree(pg_partition_root('ptif_test01_index')) p
130+
JOIN pg_class c ON (p.relid = c.oid);
131+
relid | parentrelid | level | isleaf
132+
-------------------+------------------+-------+--------
133+
ptif_test_index | | 0 | f
134+
ptif_test0_index | ptif_test_index | 1 | f
135+
ptif_test1_index | ptif_test_index | 1 | f
136+
ptif_test2_index | ptif_test_index | 1 | t
137+
ptif_test01_index | ptif_test0_index | 2 | t
138+
ptif_test11_index | ptif_test1_index | 2 | t
139+
(6 rows)
140+
101141
DROP TABLE ptif_test;
102142
-- Table that is not part of any partition tree is the only member listed.
103143
CREATE TABLE ptif_normal_table(a int);
@@ -108,6 +148,12 @@ SELECT relid, parentrelid, level, isleaf
108148
ptif_normal_table | | 0 | t
109149
(1 row)
110150

151+
SELECT pg_partition_root('ptif_normal_table');
152+
pg_partition_root
153+
-------------------
154+
ptif_normal_table
155+
(1 row)
156+
111157
DROP TABLE ptif_normal_table;
112158
-- Various partitioning-related functions return NULL if passed relations
113159
-- of types that cannot be part of a partition tree; for example, views,
@@ -126,5 +172,17 @@ SELECT * FROM pg_partition_tree('ptif_test_matview');
126172
| | |
127173
(1 row)
128174

175+
SELECT pg_partition_root('ptif_test_view');
176+
pg_partition_root
177+
-------------------
178+
179+
(1 row)
180+
181+
SELECT pg_partition_root('ptif_test_matview');
182+
pg_partition_root
183+
-------------------
184+
185+
(1 row)
186+
129187
DROP VIEW ptif_test_view;
130188
DROP MATERIALIZED VIEW ptif_test_matview;

src/test/regress/sql/partition_info.sql

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
--
44
SELECT * FROM pg_partition_tree(NULL);
55
SELECT * FROM pg_partition_tree(0);
6+
SELECT pg_partition_root(NULL);
7+
SELECT pg_partition_root(0);
68

79
-- Test table partition trees
810
CREATE TABLE ptif_test (a int, b int) PARTITION BY range (a);
@@ -39,6 +41,10 @@ SELECT relid, parentrelid, level, isleaf
3941
SELECT relid, parentrelid, level, isleaf
4042
FROM pg_partition_tree('ptif_test01') p
4143
JOIN pg_class c ON (p.relid = c.oid);
44+
-- List all members using pg_partition_root with leaf table reference
45+
SELECT relid, parentrelid, level, isleaf
46+
FROM pg_partition_tree(pg_partition_root('ptif_test01')) p
47+
JOIN pg_class c ON (p.relid = c.oid);
4248

4349
-- List all indexes members of the tree
4450
SELECT relid, parentrelid, level, isleaf
@@ -51,13 +57,18 @@ SELECT relid, parentrelid, level, isleaf
5157
SELECT relid, parentrelid, level, isleaf
5258
FROM pg_partition_tree('ptif_test01_index') p
5359
JOIN pg_class c ON (p.relid = c.oid);
60+
-- List all members using pg_partition_root with leaf index reference
61+
SELECT relid, parentrelid, level, isleaf
62+
FROM pg_partition_tree(pg_partition_root('ptif_test01_index')) p
63+
JOIN pg_class c ON (p.relid = c.oid);
5464

5565
DROP TABLE ptif_test;
5666

5767
-- Table that is not part of any partition tree is the only member listed.
5868
CREATE TABLE ptif_normal_table(a int);
5969
SELECT relid, parentrelid, level, isleaf
6070
FROM pg_partition_tree('ptif_normal_table');
71+
SELECT pg_partition_root('ptif_normal_table');
6172
DROP TABLE ptif_normal_table;
6273

6374
-- Various partitioning-related functions return NULL if passed relations
@@ -67,5 +78,7 @@ CREATE VIEW ptif_test_view AS SELECT 1;
6778
CREATE MATERIALIZED VIEW ptif_test_matview AS SELECT 1;
6879
SELECT * FROM pg_partition_tree('ptif_test_view');
6980
SELECT * FROM pg_partition_tree('ptif_test_matview');
81+
SELECT pg_partition_root('ptif_test_view');
82+
SELECT pg_partition_root('ptif_test_matview');
7083
DROP VIEW ptif_test_view;
7184
DROP MATERIALIZED VIEW ptif_test_matview;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy