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 PartitionDesc RelationBuildPartitionDesc (Relation rel, bool omit_detached)
 
PartitionDesc RelationGetPartitionDesc (Relation rel, bool omit_detached)
 
PartitionDirectory CreatePartitionDirectory (MemoryContext mcxt, bool omit_detached)
 
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,
bool  omit_detached 
)

Definition at line 377 of file partdesc.c.

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

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

378 {
379  MemoryContext oldcontext = MemoryContextSwitchTo(mcxt);
380  PartitionDirectory pdir;
381  HASHCTL ctl;
382 
383  pdir = palloc(sizeof(PartitionDirectoryData));
384  pdir->pdir_mcxt = mcxt;
385 
386  ctl.keysize = sizeof(Oid);
387  ctl.entrysize = sizeof(PartitionDirectoryEntry);
388  ctl.hcxt = mcxt;
389 
390  pdir->pdir_hash = hash_create("partition directory", 256, &ctl,
392  pdir->omit_detached = omit_detached;
393 
394  MemoryContextSwitchTo(oldcontext);
395  return pdir;
396 }
#define HASH_CONTEXT
Definition: hsearch.h:102
#define HASH_ELEM
Definition: hsearch.h:95
MemoryContext hcxt
Definition: hsearch.h:86
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Size entrysize
Definition: hsearch.h:76
unsigned int Oid
Definition: postgres_ext.h:31
MemoryContext pdir_mcxt
Definition: partdesc.c:38
HTAB * hash_create(const char *tabname, long nelem, const HASHCTL *info, int flags)
Definition: dynahash.c:349
struct PartitionDirectoryEntry PartitionDirectoryEntry
#define HASH_BLOBS
Definition: hsearch.h:97
Size keysize
Definition: hsearch.h:75
void * palloc(Size size)
Definition: mcxt.c:1062

◆ DestroyPartitionDirectory()

void DestroyPartitionDirectory ( PartitionDirectory  pdir)

Definition at line 438 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().

439 {
442 
443  hash_seq_init(&status, pdir->pdir_hash);
444  while ((pde = hash_seq_search(&status)) != NULL)
446 }
void RelationDecrementReferenceCount(Relation rel)
Definition: relcache.c:2081
void * hash_seq_search(HASH_SEQ_STATUS *status)
Definition: dynahash.c:1436
void hash_seq_init(HASH_SEQ_STATUS *status, HTAB *hashp)
Definition: dynahash.c:1426
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 455 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().

456 {
457  if (partdesc && partdesc->boundinfo &&
459  return partdesc->oids[partdesc->boundinfo->default_index];
460 
461  return InvalidOid;
462 }
PartitionBoundInfo boundinfo
Definition: partdesc.h:38
#define partition_bound_has_default(bi)
Definition: partbounds.h:97
#define InvalidOid
Definition: postgres_ext.h:36

◆ PartitionDirectoryLookup()

PartitionDesc PartitionDirectoryLookup ( PartitionDirectory  pdir,
Relation  rel 
)

Definition at line 410 of file partdesc.c.

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

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

411 {
413  Oid relid = RelationGetRelid(rel);
414  bool found;
415 
416  pde = hash_search(pdir->pdir_hash, &relid, HASH_ENTER, &found);
417  if (!found)
418  {
419  /*
420  * We must keep a reference count on the relation so that the
421  * PartitionDesc to which we are pointing can't get destroyed.
422  */
424  pde->rel = rel;
425  pde->pd = RelationGetPartitionDesc(rel, pdir->omit_detached);
426  Assert(pde->pd != NULL);
427  }
428  return pde->pd;
429 }
void * hash_search(HTAB *hashp, const void *keyPtr, HASHACTION action, bool *foundPtr)
Definition: dynahash.c:954
unsigned int Oid
Definition: postgres_ext.h:31
PartitionDesc pd
Definition: partdesc.c:47
PartitionDesc RelationGetPartitionDesc(Relation rel, bool omit_detached)
Definition: partdesc.c:72
void RelationIncrementReferenceCount(Relation rel)
Definition: relcache.c:2068
#define Assert(condition)
Definition: c.h:804
#define RelationGetRelid(relation)
Definition: rel.h:477

◆ RelationBuildPartitionDesc()

static PartitionDesc RelationBuildPartitionDesc ( Relation  rel,
bool  omit_detached 
)
static

Definition at line 135 of file partdesc.c.

References AccessShareLock, ActiveSnapshotSet(), ALLOCSET_SMALL_SIZES, AllocSetContextCreate, Assert, PartitionDescData::boundinfo, BTEqualStrategyNumber, CacheMemoryContext, CurTransactionContext, PartitionDescData::detached_exist, elog, ERROR, find_inheritance_children_extended(), get_default_partition_oid(), get_rel_relkind(), heap_getattr, HeapTupleIsValid, i, InvalidTransactionId, 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_partdesc_nodetached, RelationData::rd_partdesc_nodetached_xmin, RelationData::rd_pdcxt, RelationData::rd_pddcxt, RelationGetDescr, RelationGetPartitionKey(), RelationGetRelationName, RelationGetRelid, ReleaseSysCache(), RELOID, ScanKeyInit(), SearchSysCache1(), stringToNode(), SysCacheGetAttr(), systable_beginscan(), systable_endscan(), systable_getnext(), table_close(), table_open(), TextDatumGetCString, and TransactionIdIsValid.

Referenced by RelationGetPartitionDesc().

136 {
137  PartitionDesc partdesc;
138  PartitionBoundInfo boundinfo = NULL;
139  List *inhoids;
140  PartitionBoundSpec **boundspecs = NULL;
141  Oid *oids = NULL;
142  bool *is_leaf = NULL;
143  bool detached_exist;
144  bool is_omit;
145  TransactionId detached_xmin;
146  ListCell *cell;
147  int i,
148  nparts;
150  MemoryContext new_pdcxt;
151  MemoryContext oldcxt;
152  int *mapping;
153 
154  /*
155  * Get partition oids from pg_inherits. This uses a single snapshot to
156  * fetch the list of children, so while more children may be getting added
157  * concurrently, whatever this function returns will be accurate as of
158  * some well-defined point in time.
159  */
160  detached_exist = false;
161  detached_xmin = InvalidTransactionId;
163  omit_detached, NoLock,
164  &detached_exist,
165  &detached_xmin);
166 
167  nparts = list_length(inhoids);
168 
169  /* Allocate working arrays for OIDs, leaf flags, and boundspecs. */
170  if (nparts > 0)
171  {
172  oids = (Oid *) palloc(nparts * sizeof(Oid));
173  is_leaf = (bool *) palloc(nparts * sizeof(bool));
174  boundspecs = palloc(nparts * sizeof(PartitionBoundSpec *));
175  }
176 
177  /* Collect bound spec nodes for each partition. */
178  i = 0;
179  foreach(cell, inhoids)
180  {
181  Oid inhrelid = lfirst_oid(cell);
182  HeapTuple tuple;
183  PartitionBoundSpec *boundspec = NULL;
184 
185  /* Try fetching the tuple from the catcache, for speed. */
186  tuple = SearchSysCache1(RELOID, inhrelid);
187  if (HeapTupleIsValid(tuple))
188  {
189  Datum datum;
190  bool isnull;
191 
192  datum = SysCacheGetAttr(RELOID, tuple,
193  Anum_pg_class_relpartbound,
194  &isnull);
195  if (!isnull)
196  boundspec = stringToNode(TextDatumGetCString(datum));
197  ReleaseSysCache(tuple);
198  }
199 
200  /*
201  * The system cache may be out of date; if so, we may find no pg_class
202  * tuple or an old one where relpartbound is NULL. In that case, try
203  * the table directly. We can't just AcceptInvalidationMessages() and
204  * retry the system cache lookup because it's possible that a
205  * concurrent ATTACH PARTITION operation has removed itself from the
206  * ProcArray but not yet added invalidation messages to the shared
207  * queue; InvalidateSystemCaches() would work, but seems excessive.
208  *
209  * Note that this algorithm assumes that PartitionBoundSpec we manage
210  * to fetch is the right one -- so this is only good enough for
211  * concurrent ATTACH PARTITION, not concurrent DETACH PARTITION or
212  * some hypothetical operation that changes the partition bounds.
213  */
214  if (boundspec == NULL)
215  {
216  Relation pg_class;
217  SysScanDesc scan;
218  ScanKeyData key[1];
219  Datum datum;
220  bool isnull;
221 
222  pg_class = table_open(RelationRelationId, AccessShareLock);
223  ScanKeyInit(&key[0],
224  Anum_pg_class_oid,
225  BTEqualStrategyNumber, F_OIDEQ,
226  ObjectIdGetDatum(inhrelid));
227  scan = systable_beginscan(pg_class, ClassOidIndexId, true,
228  NULL, 1, key);
229  tuple = systable_getnext(scan);
230  datum = heap_getattr(tuple, Anum_pg_class_relpartbound,
231  RelationGetDescr(pg_class), &isnull);
232  if (!isnull)
233  boundspec = stringToNode(TextDatumGetCString(datum));
234  systable_endscan(scan);
235  table_close(pg_class, AccessShareLock);
236  }
237 
238  /* Sanity checks. */
239  if (!boundspec)
240  elog(ERROR, "missing relpartbound for relation %u", inhrelid);
241  if (!IsA(boundspec, PartitionBoundSpec))
242  elog(ERROR, "invalid relpartbound for relation %u", inhrelid);
243 
244  /*
245  * If the PartitionBoundSpec says this is the default partition, its
246  * OID should match pg_partitioned_table.partdefid; if not, the
247  * catalog is corrupt.
248  */
249  if (boundspec->is_default)
250  {
251  Oid partdefid;
252 
254  if (partdefid != inhrelid)
255  elog(ERROR, "expected partdefid %u, but got %u",
256  inhrelid, partdefid);
257  }
258 
259  /* Save results. */
260  oids[i] = inhrelid;
261  is_leaf[i] = (get_rel_relkind(inhrelid) != RELKIND_PARTITIONED_TABLE);
262  boundspecs[i] = boundspec;
263  ++i;
264  }
265 
266  /*
267  * Create PartitionBoundInfo and mapping, working in the caller's context.
268  * This could fail, but we haven't done any damage if so.
269  */
270  if (nparts > 0)
271  boundinfo = partition_bounds_create(boundspecs, nparts, key, &mapping);
272 
273  /*
274  * Now build the actual relcache partition descriptor, copying all the
275  * data into a new, small context. As per above comment, we don't make
276  * this a long-lived context until it's finished.
277  */
279  "partition descriptor",
283 
284  partdesc = (PartitionDescData *)
285  MemoryContextAllocZero(new_pdcxt, sizeof(PartitionDescData));
286  partdesc->nparts = nparts;
287  partdesc->detached_exist = detached_exist;
288  /* If there are no partitions, the rest of the partdesc can stay zero */
289  if (nparts > 0)
290  {
291  oldcxt = MemoryContextSwitchTo(new_pdcxt);
292  partdesc->boundinfo = partition_bounds_copy(boundinfo, key);
293  partdesc->oids = (Oid *) palloc(nparts * sizeof(Oid));
294  partdesc->is_leaf = (bool *) palloc(nparts * sizeof(bool));
295 
296  /*
297  * Assign OIDs from the original array into mapped indexes of the
298  * result array. The order of OIDs in the former is defined by the
299  * catalog scan that retrieved them, whereas that in the latter is
300  * defined by canonicalized representation of the partition bounds.
301  * Also save leaf-ness of each partition.
302  */
303  for (i = 0; i < nparts; i++)
304  {
305  int index = mapping[i];
306 
307  partdesc->oids[index] = oids[i];
308  partdesc->is_leaf[index] = is_leaf[i];
309  }
310  MemoryContextSwitchTo(oldcxt);
311  }
312 
313  /*
314  * Are we working with the partdesc that omits the detached partition, or
315  * the one that includes it?
316  *
317  * Note that if a partition was found by the catalog's scan to have been
318  * detached, but the pg_inherit tuple saying so was not visible to the
319  * active snapshot (find_inheritance_children_extended will not have set
320  * detached_xmin in that case), we consider there to be no "omittable"
321  * detached partitions.
322  */
323  is_omit = omit_detached && detached_exist && ActiveSnapshotSet() &&
324  TransactionIdIsValid(detached_xmin);
325 
326  /*
327  * We have a fully valid partdesc. Reparent it so that it has the right
328  * lifespan.
329  */
331 
332  /*
333  * Store it into relcache.
334  *
335  * But first, a kluge: if there's an old context for this type of
336  * descriptor, it contains an old partition descriptor that may still be
337  * referenced somewhere. Preserve it, while not leaking it, by
338  * reattaching it as a child context of the new one. Eventually it will
339  * get dropped by either RelationClose or RelationClearRelation. (We keep
340  * the regular partdesc in rd_pdcxt, and the partdesc-excluding-
341  * detached-partitions in rd_pddcxt.)
342  */
343  if (is_omit)
344  {
345  if (rel->rd_pddcxt != NULL)
346  MemoryContextSetParent(rel->rd_pddcxt, new_pdcxt);
347  rel->rd_pddcxt = new_pdcxt;
348  rel->rd_partdesc_nodetached = partdesc;
349 
350  /*
351  * For partdescs built excluding detached partitions, which we save
352  * separately, we also record the pg_inherits.xmin of the detached
353  * partition that was omitted; this informs a future potential user of
354  * such a cached partdesc to only use it after cross-checking that the
355  * xmin is indeed visible to the snapshot it is going to be working
356  * with.
357  */
358  Assert(TransactionIdIsValid(detached_xmin));
359  rel->rd_partdesc_nodetached_xmin = detached_xmin;
360  }
361  else
362  {
363  if (rel->rd_pdcxt != NULL)
364  MemoryContextSetParent(rel->rd_pdcxt, new_pdcxt);
365  rel->rd_pdcxt = new_pdcxt;
366  rel->rd_partdesc = partdesc;
367  }
368 
369  return partdesc;
370 }
#define IsA(nodeptr, _type_)
Definition: nodes.h:587
#define AllocSetContextCreate
Definition: memutils.h:173
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:167
void systable_endscan(SysScanDesc sysscan)
Definition: genam.c:595
uint32 TransactionId
Definition: c.h:587
#define RelationGetDescr(relation)
Definition: rel.h:503
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:361
char get_rel_relkind(Oid relid)
Definition: lsyscache.c:1974
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:205
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define AccessShareLock
Definition: lockdefs.h:36
MemoryContext CurTransactionContext
Definition: mcxt.c:54
void * stringToNode(const char *str)
Definition: read.c:89
bool * is_leaf
Definition: partdesc.h:35
PartitionKey RelationGetPartitionKey(Relation rel)
Definition: partcache.c:54
unsigned int Oid
Definition: postgres_ext.h:31
SysScanDesc systable_beginscan(Relation heapRelation, Oid indexId, bool indexOK, Snapshot snapshot, int nkeys, ScanKey key)
Definition: genam.c:383
PartitionBoundInfo boundinfo
Definition: partdesc.h:38
Definition: type.h:89
bool detached_exist
Definition: partdesc.h:32
HeapTuple systable_getnext(SysScanDesc sysscan)
Definition: genam.c:502
#define ObjectIdGetDatum(X)
Definition: postgres.h:551
#define ERROR
Definition: elog.h:46
#define MemoryContextCopyAndSetIdentifier(cxt, id)
Definition: memutils.h:98
#define NoLock
Definition: lockdefs.h:34
#define InvalidTransactionId
Definition: transam.h:31
#define RelationGetRelationName(relation)
Definition: rel.h:511
MemoryContext rd_pddcxt
Definition: rel.h:133
bool ActiveSnapshotSet(void)
Definition: snapmgr.c:798
PartitionDesc rd_partdesc
Definition: rel.h:128
TransactionId rd_partdesc_nodetached_xmin
Definition: rel.h:142
Oid get_default_partition_oid(Oid parentId)
Definition: partition.c:313
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:761
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:1127
#define TextDatumGetCString(d)
Definition: builtins.h:87
PartitionBoundInfo partition_bounds_copy(PartitionBoundInfo src, PartitionKey key)
Definition: partbounds.c:1010
uintptr_t Datum
Definition: postgres.h:411
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1175
Datum SysCacheGetAttr(int cacheId, HeapTuple tup, AttrNumber attributeNumber, bool *isNull)
Definition: syscache.c:1388
PartitionDesc rd_partdesc_nodetached
Definition: rel.h:132
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:906
List * find_inheritance_children_extended(Oid parentrelId, bool omit_detached, LOCKMODE lockmode, bool *detached_exist, TransactionId *detached_xmin)
Definition: pg_inherits.c:83
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
MemoryContext rd_pdcxt
Definition: rel.h:129
#define Assert(condition)
Definition: c.h:804
static int list_length(const List *l)
Definition: pg_list.h:149
void * palloc(Size size)
Definition: mcxt.c:1062
#define elog(elevel,...)
Definition: elog.h:232
int i
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Definition: scankey.c:76
#define TransactionIdIsValid(xid)
Definition: transam.h:41
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:39
Definition: pg_list.h:50
#define RelationGetRelid(relation)
Definition: rel.h:477
PartitionBoundInfo partition_bounds_create(PartitionBoundSpec **boundspecs, int nparts, PartitionKey key, int **mapping)
Definition: partbounds.c:303
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define lfirst_oid(lc)
Definition: pg_list.h:171
MemoryContext CacheMemoryContext
Definition: mcxt.c:51

◆ RelationGetPartitionDesc()

PartitionDesc RelationGetPartitionDesc ( Relation  rel,
bool  omit_detached 
)

Definition at line 72 of file partdesc.c.

References ActiveSnapshotSet(), Assert, PartitionDescData::detached_exist, GetActiveSnapshot(), likely, RelationData::rd_partdesc, RelationData::rd_partdesc_nodetached, RelationData::rd_partdesc_nodetached_xmin, RelationData::rd_rel, RelationBuildPartitionDesc(), TransactionIdIsValid, and XidInMVCCSnapshot().

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

73 {
74  Assert(rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE);
75 
76  /*
77  * If relcache has a partition descriptor, use that. However, we can only
78  * do so when we are asked to include all partitions including detached;
79  * and also when we know that there are no detached partitions.
80  *
81  * If there is no active snapshot, detached partitions aren't omitted
82  * either, so we can use the cached descriptor too in that case.
83  */
84  if (likely(rel->rd_partdesc &&
85  (!rel->rd_partdesc->detached_exist || !omit_detached ||
86  !ActiveSnapshotSet())))
87  return rel->rd_partdesc;
88 
89  /*
90  * If we're asked to omit detached partitions, we may be able to use a
91  * cached descriptor too. We determine that based on the pg_inherits.xmin
92  * that was saved alongside that descriptor: if the xmin that was not in
93  * progress for that active snapshot is also not in progress for the
94  * current active snapshot, then we can use use it. Otherwise build one
95  * from scratch.
96  */
97  if (omit_detached &&
100  {
101  Snapshot activesnap;
102 
104  activesnap = GetActiveSnapshot();
105 
106  if (!XidInMVCCSnapshot(rel->rd_partdesc_nodetached_xmin, activesnap))
107  return rel->rd_partdesc_nodetached;
108  }
109 
110  return RelationBuildPartitionDesc(rel, omit_detached);
111 }
bool XidInMVCCSnapshot(TransactionId xid, Snapshot snapshot)
Definition: snapmgr.c:2242
#define likely(x)
Definition: c.h:272
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:786
Form_pg_class rd_rel
Definition: rel.h:109
bool detached_exist
Definition: partdesc.h:32
bool ActiveSnapshotSet(void)
Definition: snapmgr.c:798
PartitionDesc rd_partdesc
Definition: rel.h:128
TransactionId rd_partdesc_nodetached_xmin
Definition: rel.h:142
PartitionDesc rd_partdesc_nodetached
Definition: rel.h:132
#define Assert(condition)
Definition: c.h:804
static PartitionDesc RelationBuildPartitionDesc(Relation rel, bool omit_detached)
Definition: partdesc.c:135
#define TransactionIdIsValid(xid)
Definition: transam.h:41