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-2022, 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 "catalog/pg_type.h"
23 #include "funcapi.h"
24 #include "utils/fmgrprotos.h"
25 #include "utils/lsyscache.h"
26 #include "utils/syscache.h"
27 
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
36 {
37  char relkind;
38  bool relispartition;
39 
40  /* Check if relation exists */
42  return false;
43 
44  relkind = get_rel_relkind(relid);
45  relispartition = get_rel_relispartition(relid);
46 
47  /* Only allow relation types that can appear in partition trees. */
48  if (!relispartition && !RELKIND_HAS_PARTITIONS(relkind))
49  return false;
50 
51  return true;
52 }
53 
54 /*
55  * pg_partition_tree
56  *
57  * Produce a view with one row per member of a partition tree, beginning
58  * from the top-most parent given by the caller. This gives information
59  * about each partition, its immediate partitioned parent, if it is
60  * a leaf partition and its level in the hierarchy.
61  */
62 Datum
64 {
65 #define PG_PARTITION_TREE_COLS 4
66  Oid rootrelid = PG_GETARG_OID(0);
67  FuncCallContext *funcctx;
69 
70  /* stuff done only on the first call of the function */
71  if (SRF_IS_FIRSTCALL())
72  {
73  MemoryContext oldcxt;
74  TupleDesc tupdesc;
75 
76  /* create a function context for cross-call persistence */
77  funcctx = SRF_FIRSTCALL_INIT();
78 
79  if (!check_rel_can_be_partition(rootrelid))
80  SRF_RETURN_DONE(funcctx);
81 
82  /* switch to memory context appropriate for multiple function calls */
84 
85  /*
86  * Find all members of inheritance set. We only need AccessShareLock
87  * on the children for the partition information lookup.
88  */
90 
92  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "relid",
93  REGCLASSOID, -1, 0);
94  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "parentid",
95  REGCLASSOID, -1, 0);
96  TupleDescInitEntry(tupdesc, (AttrNumber) 3, "isleaf",
97  BOOLOID, -1, 0);
98  TupleDescInitEntry(tupdesc, (AttrNumber) 4, "level",
99  INT4OID, -1, 0);
100 
101  funcctx->tuple_desc = BlessTupleDesc(tupdesc);
102 
103  /* The only state we need is the partition list */
104  funcctx->user_fctx = (void *) partitions;
105 
106  MemoryContextSwitchTo(oldcxt);
107  }
108 
109  /* stuff done on every call of the function */
110  funcctx = SRF_PERCALL_SETUP();
111  partitions = (List *) funcctx->user_fctx;
112 
113  if (funcctx->call_cntr < list_length(partitions))
114  {
115  Datum result;
117  bool nulls[PG_PARTITION_TREE_COLS];
118  HeapTuple tuple;
119  Oid parentid = InvalidOid;
120  Oid relid = list_nth_oid(partitions, funcctx->call_cntr);
121  char relkind = get_rel_relkind(relid);
122  int level = 0;
123  List *ancestors = get_partition_ancestors(relid);
124  ListCell *lc;
125 
126  /*
127  * Form tuple with appropriate data.
128  */
129  MemSet(nulls, 0, sizeof(nulls));
130  MemSet(values, 0, sizeof(values));
131 
132  /* relid */
133  values[0] = ObjectIdGetDatum(relid);
134 
135  /* parentid */
136  if (ancestors != NIL)
137  parentid = linitial_oid(ancestors);
138  if (OidIsValid(parentid))
139  values[1] = ObjectIdGetDatum(parentid);
140  else
141  nulls[1] = true;
142 
143  /* isleaf */
144  values[2] = BoolGetDatum(!RELKIND_HAS_PARTITIONS(relkind));
145 
146  /* level */
147  if (relid != rootrelid)
148  {
149  foreach(lc, ancestors)
150  {
151  level++;
152  if (lfirst_oid(lc) == rootrelid)
153  break;
154  }
155  }
156  values[3] = Int32GetDatum(level);
157 
158  tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
159  result = HeapTupleGetDatum(tuple);
160  SRF_RETURN_NEXT(funcctx, result);
161  }
162 
163  /* done when there are no more elements left */
164  SRF_RETURN_DONE(funcctx);
165 }
166 
167 /*
168  * pg_partition_root
169  *
170  * Returns the top-most parent of the partition tree to which a given
171  * relation belongs, or NULL if it's not (or cannot be) part of any
172  * partition tree.
173  */
174 Datum
176 {
177  Oid relid = PG_GETARG_OID(0);
178  Oid rootrelid;
179  List *ancestors;
180 
181  if (!check_rel_can_be_partition(relid))
182  PG_RETURN_NULL();
183 
184  /* fetch the list of ancestors */
185  ancestors = get_partition_ancestors(relid);
186 
187  /*
188  * If the input relation is already the top-most parent, just return
189  * itself.
190  */
191  if (ancestors == NIL)
192  PG_RETURN_OID(relid);
193 
194  rootrelid = llast_oid(ancestors);
195  list_free(ancestors);
196 
197  /*
198  * "rootrelid" must contain a valid OID, given that the input relation is
199  * a valid partition tree member as checked above.
200  */
201  Assert(OidIsValid(rootrelid));
202  PG_RETURN_OID(rootrelid);
203 }
204 
205 /*
206  * pg_partition_ancestors
207  *
208  * Produces a view with one row per ancestor of the given partition,
209  * including the input relation itself.
210  */
211 Datum
213 {
214  Oid relid = PG_GETARG_OID(0);
215  FuncCallContext *funcctx;
216  List *ancestors;
217 
218  if (SRF_IS_FIRSTCALL())
219  {
220  MemoryContext oldcxt;
221 
222  funcctx = SRF_FIRSTCALL_INIT();
223 
224  if (!check_rel_can_be_partition(relid))
225  SRF_RETURN_DONE(funcctx);
226 
227  oldcxt = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
228 
229  ancestors = get_partition_ancestors(relid);
230  ancestors = lcons_oid(relid, ancestors);
231 
232  /* The only state we need is the ancestors list */
233  funcctx->user_fctx = (void *) ancestors;
234 
235  MemoryContextSwitchTo(oldcxt);
236  }
237 
238  funcctx = SRF_PERCALL_SETUP();
239  ancestors = (List *) funcctx->user_fctx;
240 
241  if (funcctx->call_cntr < list_length(ancestors))
242  {
243  Oid relid = list_nth_oid(ancestors, funcctx->call_cntr);
244 
245  SRF_RETURN_NEXT(funcctx, ObjectIdGetDatum(relid));
246  }
247 
248  SRF_RETURN_DONE(funcctx);
249 }
int16 AttrNumber
Definition: attnum.h:21
static Datum values[MAXATTR]
Definition: bootstrap.c:156
#define MemSet(start, val, len)
Definition: c.h:1008
#define OidIsValid(objectId)
Definition: c.h:710
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2071
#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
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:299
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:303
#define HeapTupleGetDatum(tuple)
Definition: funcapi.h:220
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:305
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:301
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:323
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
Assert(fmt[strlen(fmt) - 1] !='\n')
void list_free(List *list)
Definition: list.c:1505
List * lcons_oid(Oid datum, List *list)
Definition: list.c:510
#define AccessShareLock
Definition: lockdefs.h:36
bool get_rel_relispartition(Oid relid)
Definition: lsyscache.c:2008
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1984
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
List * get_partition_ancestors(Oid relid)
Definition: partition.c:133
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:256
static int list_length(const List *l)
Definition: pg_list.h:149
#define NIL
Definition: pg_list.h:65
static Oid list_nth_oid(const List *list, int n)
Definition: pg_list.h:300
#define llast_oid(l)
Definition: pg_list.h:196
#define linitial_oid(l)
Definition: pg_list.h:176
#define lfirst_oid(lc)
Definition: pg_list.h:171
static int partitions
Definition: pgbench.c:236
uintptr_t Datum
Definition: postgres.h:411
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define BoolGetDatum(X)
Definition: postgres.h:446
#define Int32GetDatum(X)
Definition: postgres.h:523
#define InvalidOid
Definition: postgres_ext.h:36
unsigned int Oid
Definition: postgres_ext.h:31
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:51
@ RELOID
Definition: syscache.h:89
#define SearchSysCacheExists1(cacheId, key1)
Definition: syscache.h:188
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:45
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:583