PostgreSQL Source Code  git master
partdesc.c File Reference
#include "postgres.h"
#include "access/genam.h"
#include "access/htup_details.h"
#include "access/table.h"
#include "catalog/partition.h"
#include "catalog/pg_inherits.h"
#include "partitioning/partbounds.h"
#include "partitioning/partdesc.h"
#include "storage/bufmgr.h"
#include "storage/sinval.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/hsearch.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/partcache.h"
#include "utils/rel.h"
#include "utils/syscache.h"
Include dependency graph for partdesc.c:

Go to the source code of this file.

Data Structures

struct  PartitionDirectoryData
 
struct  PartitionDirectoryEntry
 

Typedefs

typedef struct PartitionDirectoryData PartitionDirectoryData
 
typedef struct PartitionDirectoryEntry PartitionDirectoryEntry
 

Functions

static void RelationBuildPartitionDesc (Relation rel)
 
PartitionDesc RelationGetPartitionDesc (Relation rel)
 
PartitionDirectory CreatePartitionDirectory (MemoryContext mcxt)
 
PartitionDesc PartitionDirectoryLookup (PartitionDirectory pdir, Relation rel)
 
void DestroyPartitionDirectory (PartitionDirectory pdir)
 
Oid get_default_oid_from_partdesc (PartitionDesc partdesc)
 

Typedef Documentation

◆ PartitionDirectoryData

◆ PartitionDirectoryEntry

Function Documentation

◆ CreatePartitionDirectory()

PartitionDirectory CreatePartitionDirectory ( MemoryContext  mcxt)

Definition at line 283 of file partdesc.c.

References HASHCTL::entrysize, HASH_BLOBS, HASH_CONTEXT, hash_create(), HASH_ELEM, HASHCTL::hcxt, HASHCTL::keysize, MemoryContextSwitchTo(), MemSet, palloc(), PartitionDirectoryData::pdir_hash, and PartitionDirectoryData::pdir_mcxt.

Referenced by ExecCreatePartitionPruneState(), ExecInitPartitionDispatchInfo(), and set_relation_partition_info().

284 {
285  MemoryContext oldcontext = MemoryContextSwitchTo(mcxt);
286  PartitionDirectory pdir;
287  HASHCTL ctl;
288 
289  MemSet(&ctl, 0, sizeof(HASHCTL));
290  ctl.keysize = sizeof(Oid);
291  ctl.entrysize = sizeof(PartitionDirectoryEntry);
292  ctl.hcxt = mcxt;
293 
294  pdir = palloc(sizeof(PartitionDirectoryData));
295  pdir->pdir_mcxt = mcxt;
296  pdir->pdir_hash = hash_create("partition directory", 256, &ctl,
298 
299  MemoryContextSwitchTo(oldcontext);
300  return pdir;
301 }
#define HASH_CONTEXT
Definition: hsearch.h:91
#define HASH_ELEM
Definition: hsearch.h:85
MemoryContext hcxt
Definition: hsearch.h:77
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Size entrysize
Definition: hsearch.h:72
#define MemSet(start, val, len)
Definition: c.h:1004
unsigned int Oid
Definition: postgres_ext.h:31
MemoryContext pdir_mcxt
Definition: partdesc.c:38
struct PartitionDirectoryEntry PartitionDirectoryEntry
#define HASH_BLOBS
Definition: hsearch.h:86
HTAB * hash_create(const char *tabname, long nelem, HASHCTL *info, int flags)
Definition: dynahash.c:326
Size keysize
Definition: hsearch.h:71
void * palloc(Size size)
Definition: mcxt.c:950

◆ DestroyPartitionDirectory()

void DestroyPartitionDirectory ( PartitionDirectory  pdir)

Definition at line 343 of file partdesc.c.

References hash_seq_init(), hash_seq_search(), PartitionDirectoryData::pdir_hash, PartitionDirectoryEntry::rel, RelationDecrementReferenceCount(), and status().

Referenced by FreeExecutorState(), and standard_planner().

344 {
347 
348  hash_seq_init(&status, pdir->pdir_hash);
349  while ((pde = hash_seq_search(&status)) != NULL)
351 }
void RelationDecrementReferenceCount(Relation rel)
Definition: relcache.c:2091
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1401
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1391
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:227

◆ get_default_oid_from_partdesc()

Oid get_default_oid_from_partdesc ( PartitionDesc  partdesc)

Definition at line 360 of file partdesc.c.

References PartitionDescData::boundinfo, PartitionBoundInfoData::default_index, InvalidOid, PartitionDescData::oids, and partition_bound_has_default.

Referenced by ATExecAttachPartition(), ATExecDetachPartition(), DefineRelation(), and StorePartitionBound().

361 {
362  if (partdesc && partdesc->boundinfo &&
364  return partdesc->oids[partdesc->boundinfo->default_index];
365 
366  return InvalidOid;
367 }
PartitionBoundInfo boundinfo
Definition: partdesc.h:29
#define partition_bound_has_default(bi)
Definition: partbounds.h:75
#define InvalidOid
Definition: postgres_ext.h:36

◆ PartitionDirectoryLookup()

PartitionDesc PartitionDirectoryLookup ( PartitionDirectory  pdir,
Relation  rel 
)

Definition at line 315 of file partdesc.c.

References Assert, HASH_ENTER, hash_search(), PartitionDirectoryEntry::pd, PartitionDirectoryData::pdir_hash, PartitionDirectoryEntry::rel, RelationGetPartitionDesc(), RelationGetRelid, and RelationIncrementReferenceCount().

Referenced by ExecCreatePartitionPruneState(), ExecInitPartitionDispatchInfo(), expand_partitioned_rtentry(), and set_relation_partition_info().

316 {
318  Oid relid = RelationGetRelid(rel);
319  bool found;
320 
321  pde = hash_search(pdir->pdir_hash, &relid, HASH_ENTER, &found);
322  if (!found)
323  {
324  /*
325  * We must keep a reference count on the relation so that the
326  * PartitionDesc to which we are pointing can't get destroyed.
327  */
329  pde->rel = rel;
330  pde->pd = RelationGetPartitionDesc(rel);
331  Assert(pde->pd != NULL);
332  }
333  return pde->pd;
334 }
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:919
unsigned int Oid
Definition: postgres_ext.h:31
PartitionDesc pd
Definition: partdesc.c:46
PartitionDesc RelationGetPartitionDesc(Relation rel)
Definition: partdesc.c:64
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:2078
#define Assert(condition)
Definition: c.h:800
#define RelationGetRelid(relation)
Definition: rel.h:457

◆ RelationBuildPartitionDesc()

static void RelationBuildPartitionDesc ( Relation  rel)
static

Definition at line 91 of file partdesc.c.

References AccessShareLock, ALLOCSET_SMALL_SIZES, AllocSetContextCreate, PartitionDescData::boundinfo, BTEqualStrategyNumber, CacheMemoryContext, ClassOidIndexId, CurTransactionContext, elog, ERROR, find_inheritance_children(), get_default_partition_oid(), get_rel_relkind(), heap_getattr, HeapTupleIsValid, i, PartitionBoundSpec::is_default, PartitionDescData::is_leaf, IsA, sort-test::key, lfirst_oid, list_length(), MemoryContextAllocZero(), MemoryContextCopyAndSetIdentifier, MemoryContextSetParent(), MemoryContextSwitchTo(), NoLock, PartitionDescData::nparts, ObjectIdGetDatum, PartitionDescData::oids, palloc(), partition_bounds_copy(), partition_bounds_create(), RelationData::rd_partdesc, RelationData::rd_pdcxt, RelationGetDescr, RelationGetPartitionKey(), RelationGetRelationName, RelationGetRelid, ReleaseSysCache(), RELOID, ScanKeyInit(), SearchSysCache1(), stringToNode(), SysCacheGetAttr(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), and TextDatumGetCString.

Referenced by RelationGetPartitionDesc().

92 {
93  PartitionDesc partdesc;
94  PartitionBoundInfo boundinfo = NULL;
95  List *inhoids;
96  PartitionBoundSpec **boundspecs = NULL;
97  Oid *oids = NULL;
98  bool *is_leaf = NULL;
99  ListCell *cell;
100  int i,
101  nparts;
103  MemoryContext new_pdcxt;
104  MemoryContext oldcxt;
105  int *mapping;
106 
107  /*
108  * Get partition oids from pg_inherits. This uses a single snapshot to
109  * fetch the list of children, so while more children may be getting added
110  * concurrently, whatever this function returns will be accurate as of
111  * some well-defined point in time.
112  */
114  nparts = list_length(inhoids);
115 
116  /* Allocate working arrays for OIDs, leaf flags, and boundspecs. */
117  if (nparts > 0)
118  {
119  oids = (Oid *) palloc(nparts * sizeof(Oid));
120  is_leaf = (bool *) palloc(nparts * sizeof(bool));
121  boundspecs = palloc(nparts * sizeof(PartitionBoundSpec *));
122  }
123 
124  /* Collect bound spec nodes for each partition. */
125  i = 0;
126  foreach(cell, inhoids)
127  {
128  Oid inhrelid = lfirst_oid(cell);
129  HeapTuple tuple;
130  PartitionBoundSpec *boundspec = NULL;
131 
132  /* Try fetching the tuple from the catcache, for speed. */
133  tuple = SearchSysCache1(RELOID, inhrelid);
134  if (HeapTupleIsValid(tuple))
135  {
136  Datum datum;
137  bool isnull;
138 
139  datum = SysCacheGetAttr(RELOID, tuple,
140  Anum_pg_class_relpartbound,
141  &isnull);
142  if (!isnull)
143  boundspec = stringToNode(TextDatumGetCString(datum));
144  ReleaseSysCache(tuple);
145  }
146 
147  /*
148  * The system cache may be out of date; if so, we may find no pg_class
149  * tuple or an old one where relpartbound is NULL. In that case, try
150  * the table directly. We can't just AcceptInvalidationMessages() and
151  * retry the system cache lookup because it's possible that a
152  * concurrent ATTACH PARTITION operation has removed itself from the
153  * ProcArray but not yet added invalidation messages to the shared
154  * queue; InvalidateSystemCaches() would work, but seems excessive.
155  *
156  * Note that this algorithm assumes that PartitionBoundSpec we manage
157  * to fetch is the right one -- so this is only good enough for
158  * concurrent ATTACH PARTITION, not concurrent DETACH PARTITION or
159  * some hypothetical operation that changes the partition bounds.
160  */
161  if (boundspec == NULL)
162  {
163  Relation pg_class;
164  SysScanDesc scan;
165  ScanKeyData key[1];
166  Datum datum;
167  bool isnull;
168 
169  pg_class = table_open(RelationRelationId, AccessShareLock);
170  ScanKeyInit(&key[0],
171  Anum_pg_class_oid,
172  BTEqualStrategyNumber, F_OIDEQ,
173  ObjectIdGetDatum(inhrelid));
174  scan = systable_beginscan(pg_class, ClassOidIndexId, true,
175  NULL, 1, key);
176  tuple = systable_getnext(scan);
177  datum = heap_getattr(tuple, Anum_pg_class_relpartbound,
178  RelationGetDescr(pg_class), &isnull);
179  if (!isnull)
180  boundspec = stringToNode(TextDatumGetCString(datum));
181  systable_endscan(scan);
182  table_close(pg_class, AccessShareLock);
183  }
184 
185  /* Sanity checks. */
186  if (!boundspec)
187  elog(ERROR, "missing relpartbound for relation %u", inhrelid);
188  if (!IsA(boundspec, PartitionBoundSpec))
189  elog(ERROR, "invalid relpartbound for relation %u", inhrelid);
190 
191  /*
192  * If the PartitionBoundSpec says this is the default partition, its
193  * OID should match pg_partitioned_table.partdefid; if not, the
194  * catalog is corrupt.
195  */
196  if (boundspec->is_default)
197  {
198  Oid partdefid;
199 
201  if (partdefid != inhrelid)
202  elog(ERROR, "expected partdefid %u, but got %u",
203  inhrelid, partdefid);
204  }
205 
206  /* Save results. */
207  oids[i] = inhrelid;
208  is_leaf[i] = (get_rel_relkind(inhrelid) != RELKIND_PARTITIONED_TABLE);
209  boundspecs[i] = boundspec;
210  ++i;
211  }
212 
213  /*
214  * Create PartitionBoundInfo and mapping, working in the caller's context.
215  * This could fail, but we haven't done any damage if so.
216  */
217  if (nparts > 0)
218  boundinfo = partition_bounds_create(boundspecs, nparts, key, &mapping);
219 
220  /*
221  * Now build the actual relcache partition descriptor, copying all the
222  * data into a new, small context. As per above comment, we don't make
223  * this a long-lived context until it's finished.
224  */
226  "partition descriptor",
230 
231  partdesc = (PartitionDescData *)
232  MemoryContextAllocZero(new_pdcxt, sizeof(PartitionDescData));
233  partdesc->nparts = nparts;
234  /* If there are no partitions, the rest of the partdesc can stay zero */
235  if (nparts > 0)
236  {
237  oldcxt = MemoryContextSwitchTo(new_pdcxt);
238  partdesc->boundinfo = partition_bounds_copy(boundinfo, key);
239  partdesc->oids = (Oid *) palloc(nparts * sizeof(Oid));
240  partdesc->is_leaf = (bool *) palloc(nparts * sizeof(bool));
241 
242  /*
243  * Assign OIDs from the original array into mapped indexes of the
244  * result array. The order of OIDs in the former is defined by the
245  * catalog scan that retrieved them, whereas that in the latter is
246  * defined by canonicalized representation of the partition bounds.
247  * Also save leaf-ness of each partition.
248  */
249  for (i = 0; i < nparts; i++)
250  {
251  int index = mapping[i];
252 
253  partdesc->oids[index] = oids[i];
254  partdesc->is_leaf[index] = is_leaf[i];
255  }
256  MemoryContextSwitchTo(oldcxt);
257  }
258 
259  /*
260  * We have a fully valid partdesc ready to store into the relcache.
261  * Reparent it so it has the right lifespan.
262  */
264 
265  /*
266  * But first, a kluge: if there's an old rd_pdcxt, it contains an old
267  * partition descriptor that may still be referenced somewhere. Preserve
268  * it, while not leaking it, by reattaching it as a child context of the
269  * new rd_pdcxt. Eventually it will get dropped by either RelationClose
270  * or RelationClearRelation.
271  */
272  if (rel->rd_pdcxt != NULL)
273  MemoryContextSetParent(rel->rd_pdcxt, new_pdcxt);
274  rel->rd_pdcxt = new_pdcxt;
275  rel->rd_partdesc = partdesc;
276 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:578
#define AllocSetContextCreate
Definition: memutils.h:170
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:569
#define RelationGetDescr(relation)
Definition: rel.h:483
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:355
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1920
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:202
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define AccessShareLock
Definition: lockdefs.h:36
MemoryContext CurTransactionContext
Definition: mcxt.c:50
void * stringToNode(const char *str)
Definition: read.c:89
bool * is_leaf
Definition: partdesc.h:26
PartitionKey RelationGetPartitionKey(Relation rel)
Definition: partcache.c:54
unsigned int Oid
Definition: postgres_ext.h:31
#define ClassOidIndexId
Definition: pg_class.h:156
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:357
PartitionBoundInfo boundinfo
Definition: partdesc.h:29
Definition: type.h:89
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:476
#define ObjectIdGetDatum(X)
Definition: postgres.h:507
#define ERROR
Definition: elog.h:43
#define MemoryContextCopyAndSetIdentifier(cxt, id)
Definition: memutils.h:97
#define NoLock
Definition: lockdefs.h:34
#define RelationGetRelationName(relation)
Definition: rel.h:491
PartitionDesc rd_partdesc
Definition: rel.h:129
Oid get_default_partition_oid(Oid parentId)
Definition: partition.c:291
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:762
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1115
#define TextDatumGetCString(d)
Definition: builtins.h:87
PartitionBoundInfo partition_bounds_copy(PartitionBoundInfo src, PartitionKey key)
Definition: partbounds.c:917
uintptr_t Datum
Definition: postgres.h:367
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1163
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1376
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:840
List * find_inheritance_children(Oid parentrelId, LOCKMODE lockmode)
Definition: pg_inherits.c:55
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
MemoryContext rd_pdcxt
Definition: rel.h:130
static int list_length(const List *l)
Definition: pg_list.h:149
void * palloc(Size size)
Definition: mcxt.c:950
#define elog(elevel,...)
Definition: elog.h:228
int i
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:457
PartitionBoundInfo partition_bounds_create(PartitionBoundSpec **boundspecs, int nparts, PartitionKey key, int **mapping)
Definition: partbounds.c:305
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define lfirst_oid(lc)
Definition: pg_list.h:171
MemoryContext CacheMemoryContext
Definition: mcxt.c:47

◆ RelationGetPartitionDesc()

PartitionDesc RelationGetPartitionDesc ( Relation  rel)

Definition at line 64 of file partdesc.c.

References RelationData::rd_partdesc, RelationData::rd_rel, RelationBuildPartitionDesc(), and unlikely.

Referenced by addFkRecurseReferenced(), addFkRecurseReferencing(), ATExecAttachPartition(), ATExecAttachPartitionIdx(), ATExecDetachPartition(), ATPrepDropNotNull(), check_new_partition_bound(), CreateTrigger(), DefineIndex(), DefineRelation(), get_qual_for_list(), get_qual_for_range(), PartitionDirectoryLookup(), QueuePartitionConstraintValidation(), StorePartitionBound(), and validatePartitionedIndex().

65 {
66  if (rel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
67  return NULL;
68 
69  if (unlikely(rel->rd_partdesc == NULL))
71 
72  return rel->rd_partdesc;
73 }
Form_pg_class rd_rel
Definition: rel.h:110
PartitionDesc rd_partdesc
Definition: rel.h:129
static void RelationBuildPartitionDesc(Relation rel)
Definition: partdesc.c:91
#define unlikely(x)
Definition: c.h:261