PostgreSQL Source Code git master
partitionfuncs.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * partitionfuncs.c
4 * Functions for accessing partition-related metadata
5 *
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
8 *
9 *
10 * IDENTIFICATION
11 * src/backend/utils/adt/partitionfuncs.c
12 *
13 *-------------------------------------------------------------------------
14 */
15
16#include "postgres.h"
17
18#include "access/htup_details.h"
19#include "catalog/partition.h"
20#include "catalog/pg_class.h"
21#include "catalog/pg_inherits.h"
22#include "funcapi.h"
23#include "utils/fmgrprotos.h"
24#include "utils/lsyscache.h"
25#include "utils/syscache.h"
26
27/*
28 * Checks if a given relation can be part of a partition tree. Returns
29 * false if the relation cannot be processed, in which case it is up to
30 * the caller to decide what to do, by either raising an error or doing
31 * something else.
32 */
33static bool
35{
36 char relkind;
37 bool relispartition;
38
39 /* Check if relation exists */
40 if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(relid)))
41 return false;
42
43 relkind = get_rel_relkind(relid);
44 relispartition = get_rel_relispartition(relid);
45
46 /* Only allow relation types that can appear in partition trees. */
47 if (!relispartition && !RELKIND_HAS_PARTITIONS(relkind))
48 return false;
49
50 return true;
51}
52
53/*
54 * pg_partition_tree
55 *
56 * Produce a view with one row per member of a partition tree, beginning
57 * from the top-most parent given by the caller. This gives information
58 * about each partition, its immediate partitioned parent, if it is
59 * a leaf partition and its level in the hierarchy.
60 */
63{
64#define PG_PARTITION_TREE_COLS 4
65 Oid rootrelid = PG_GETARG_OID(0);
66 FuncCallContext *funcctx;
68
69 /* stuff done only on the first call of the function */
70 if (SRF_IS_FIRSTCALL())
71 {
72 MemoryContext oldcxt;
73 TupleDesc tupdesc;
74
75 /* create a function context for cross-call persistence */
76 funcctx = SRF_FIRSTCALL_INIT();
77
78 if (!check_rel_can_be_partition(rootrelid))
79 SRF_RETURN_DONE(funcctx);
80
81 /* switch to memory context appropriate for multiple function calls */
83
84 /*
85 * Find all members of inheritance set. We only need AccessShareLock
86 * on the children for the partition information lookup.
87 */
89
90 if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
91 elog(ERROR, "return type must be a row type");
92 funcctx->tuple_desc = tupdesc;
93
94 /* The only state we need is the partition list */
95 funcctx->user_fctx = partitions;
96
98 }
99
100 /* stuff done on every call of the function */
101 funcctx = SRF_PERCALL_SETUP();
102 partitions = (List *) funcctx->user_fctx;
103
104 if (funcctx->call_cntr < list_length(partitions))
105 {
106 Datum result;
108 bool nulls[PG_PARTITION_TREE_COLS] = {0};
109 HeapTuple tuple;
110 Oid parentid = InvalidOid;
111 Oid relid = list_nth_oid(partitions, funcctx->call_cntr);
112 char relkind = get_rel_relkind(relid);
113 int level = 0;
114 List *ancestors = get_partition_ancestors(relid);
115 ListCell *lc;
116
117 /*
118 * Form tuple with appropriate data.
119 */
120
121 /* relid */
122 values[0] = ObjectIdGetDatum(relid);
123
124 /* parentid */
125 if (ancestors != NIL)
126 parentid = linitial_oid(ancestors);
127 if (OidIsValid(parentid))
128 values[1] = ObjectIdGetDatum(parentid);
129 else
130 nulls[1] = true;
131
132 /* isleaf */
133 values[2] = BoolGetDatum(!RELKIND_HAS_PARTITIONS(relkind));
134
135 /* level */
136 if (relid != rootrelid)
137 {
138 foreach(lc, ancestors)
139 {
140 level++;
141 if (lfirst_oid(lc) == rootrelid)
142 break;
143 }
144 }
145 values[3] = Int32GetDatum(level);
146
147 tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
148 result = HeapTupleGetDatum(tuple);
149 SRF_RETURN_NEXT(funcctx, result);
150 }
151
152 /* done when there are no more elements left */
153 SRF_RETURN_DONE(funcctx);
154}
155
156/*
157 * pg_partition_root
158 *
159 * Returns the top-most parent of the partition tree to which a given
160 * relation belongs, or NULL if it's not (or cannot be) part of any
161 * partition tree.
162 */
163Datum
165{
166 Oid relid = PG_GETARG_OID(0);
167 Oid rootrelid;
168 List *ancestors;
169
170 if (!check_rel_can_be_partition(relid))
172
173 /* fetch the list of ancestors */
174 ancestors = get_partition_ancestors(relid);
175
176 /*
177 * If the input relation is already the top-most parent, just return
178 * itself.
179 */
180 if (ancestors == NIL)
181 PG_RETURN_OID(relid);
182
183 rootrelid = llast_oid(ancestors);
184 list_free(ancestors);
185
186 /*
187 * "rootrelid" must contain a valid OID, given that the input relation is
188 * a valid partition tree member as checked above.
189 */
190 Assert(OidIsValid(rootrelid));
191 PG_RETURN_OID(rootrelid);
192}
193
194/*
195 * pg_partition_ancestors
196 *
197 * Produces a view with one row per ancestor of the given partition,
198 * including the input relation itself.
199 */
200Datum
202{
203 Oid relid = PG_GETARG_OID(0);
204 FuncCallContext *funcctx;
205 List *ancestors;
206
207 if (SRF_IS_FIRSTCALL())
208 {
209 MemoryContext oldcxt;
210
211 funcctx = SRF_FIRSTCALL_INIT();
212
213 if (!check_rel_can_be_partition(relid))
214 SRF_RETURN_DONE(funcctx);
215
217
218 ancestors = get_partition_ancestors(relid);
219 ancestors = lcons_oid(relid, ancestors);
220
221 /* The only state we need is the ancestors list */
222 funcctx->user_fctx = ancestors;
223
224 MemoryContextSwitchTo(oldcxt);
225 }
226
227 funcctx = SRF_PERCALL_SETUP();
228 ancestors = (List *) funcctx->user_fctx;
229
230 if (funcctx->call_cntr < list_length(ancestors))
231 {
232 Oid resultrel = list_nth_oid(ancestors, funcctx->call_cntr);
233
234 SRF_RETURN_NEXT(funcctx, ObjectIdGetDatum(resultrel));
235 }
236
237 SRF_RETURN_DONE(funcctx);
238}
static Datum values[MAXATTR]
Definition: bootstrap.c:151
#define Assert(condition)
Definition: c.h:815
#define OidIsValid(objectId)
Definition: c.h:732
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:225
#define PG_GETARG_OID(n)
Definition: fmgr.h:275
#define PG_RETURN_NULL()
Definition: fmgr.h:345
#define PG_RETURN_OID(x)
Definition: fmgr.h:360
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:276
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:304
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:308
@ TYPEFUNC_COMPOSITE
Definition: funcapi.h:149
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:310
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:306
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
Definition: funcapi.h:230
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:328
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:76
List * lcons_oid(Oid datum, List *list)
Definition: list.c:531
void list_free(List *list)
Definition: list.c:1546
#define AccessShareLock
Definition: lockdefs.h:36
bool get_rel_relispartition(Oid relid)
Definition: lsyscache.c:2054
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:2030
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
List * get_partition_ancestors(Oid relid)
Definition: partition.c:134
Datum pg_partition_tree(PG_FUNCTION_ARGS)
#define PG_PARTITION_TREE_COLS
Datum pg_partition_root(PG_FUNCTION_ARGS)
static bool check_rel_can_be_partition(Oid relid)
Datum pg_partition_ancestors(PG_FUNCTION_ARGS)
List * find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
Definition: pg_inherits.c:255
static int list_length(const List *l)
Definition: pg_list.h:152
#define NIL
Definition: pg_list.h:68
static Oid list_nth_oid(const List *list, int n)
Definition: pg_list.h:321
#define llast_oid(l)
Definition: pg_list.h:200
#define linitial_oid(l)
Definition: pg_list.h:180
#define lfirst_oid(lc)
Definition: pg_list.h:174
static int partitions
Definition: pgbench.c:224
uintptr_t Datum
Definition: postgres.h:69
static Datum BoolGetDatum(bool X)
Definition: postgres.h:107
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:217
#define InvalidOid
Definition: postgres_ext.h:37
unsigned int Oid
Definition: postgres_ext.h:32
void * user_fctx
Definition: funcapi.h:82
uint64 call_cntr
Definition: funcapi.h:65
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101
TupleDesc tuple_desc
Definition: funcapi.h:112
Definition: pg_list.h:54
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:100