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-2024, 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  */
33 static 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  */
61 Datum
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 = (void *) partitions;
96 
97  MemoryContextSwitchTo(oldcxt);
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  */
163 Datum
165 {
166  Oid relid = PG_GETARG_OID(0);
167  Oid rootrelid;
168  List *ancestors;
169 
170  if (!check_rel_can_be_partition(relid))
171  PG_RETURN_NULL();
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  */
200 Datum
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 
216  oldcxt = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
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 = (void *) 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:152
#define Assert(condition)
Definition: c.h:858
#define OidIsValid(objectId)
Definition: c.h:775
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:224
#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:1116
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
void list_free(List *list)
Definition: list.c:1546
List * lcons_oid(Oid datum, List *list)
Definition: list.c:531
#define AccessShareLock
Definition: lockdefs.h:36
bool get_rel_relispartition(Oid relid)
Definition: lsyscache.c:2027
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:2003
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:223
uintptr_t Datum
Definition: postgres.h:64
static Datum BoolGetDatum(bool X)
Definition: postgres.h:102
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:252
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
MemoryContextSwitchTo(old_ctx)
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:95