aboutsummaryrefslogtreecommitdiff
path: root/src/backend/partitioning/partdesc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/partitioning/partdesc.c')
-rw-r--r--src/backend/partitioning/partdesc.c221
1 files changed, 221 insertions, 0 deletions
diff --git a/src/backend/partitioning/partdesc.c b/src/backend/partitioning/partdesc.c
new file mode 100644
index 00000000000..8a4b63aa268
--- /dev/null
+++ b/src/backend/partitioning/partdesc.c
@@ -0,0 +1,221 @@
+/*-------------------------------------------------------------------------
+ *
+ * partdesc.c
+ * Support routines for manipulating partition descriptors
+ *
+ * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ * src/backend/partitioning/partdesc.c
+ *
+ *-------------------------------------------------------------------------
+ */
+
+#include "postgres.h"
+
+#include "catalog/partition.h"
+#include "catalog/pg_inherits.h"
+#include "partitioning/partbounds.h"
+#include "partitioning/partdesc.h"
+#include "utils/builtins.h"
+#include "utils/lsyscache.h"
+#include "utils/memutils.h"
+#include "utils/rel.h"
+#include "utils/partcache.h"
+#include "utils/syscache.h"
+
+/*
+ * RelationBuildPartitionDesc
+ * Form rel's partition descriptor
+ *
+ * Not flushed from the cache by RelationClearRelation() unless changed because
+ * of addition or removal of partition.
+ */
+void
+RelationBuildPartitionDesc(Relation rel)
+{
+ PartitionDesc partdesc;
+ PartitionBoundInfo boundinfo = NULL;
+ List *inhoids;
+ PartitionBoundSpec **boundspecs = NULL;
+ Oid *oids = NULL;
+ ListCell *cell;
+ int i,
+ nparts;
+ PartitionKey key = RelationGetPartitionKey(rel);
+ MemoryContext oldcxt;
+ int *mapping;
+
+ /* Get partition oids from pg_inherits */
+ inhoids = find_inheritance_children(RelationGetRelid(rel), NoLock);
+ nparts = list_length(inhoids);
+
+ if (nparts > 0)
+ {
+ oids = palloc(nparts * sizeof(Oid));
+ boundspecs = palloc(nparts * sizeof(PartitionBoundSpec *));
+ }
+
+ /* Collect bound spec nodes for each partition */
+ i = 0;
+ foreach(cell, inhoids)
+ {
+ Oid inhrelid = lfirst_oid(cell);
+ HeapTuple tuple;
+ Datum datum;
+ bool isnull;
+ PartitionBoundSpec *boundspec;
+
+ tuple = SearchSysCache1(RELOID, inhrelid);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for relation %u", inhrelid);
+
+ datum = SysCacheGetAttr(RELOID, tuple,
+ Anum_pg_class_relpartbound,
+ &isnull);
+ if (isnull)
+ elog(ERROR, "null relpartbound for relation %u", inhrelid);
+ boundspec = stringToNode(TextDatumGetCString(datum));
+ if (!IsA(boundspec, PartitionBoundSpec))
+ elog(ERROR, "invalid relpartbound for relation %u", inhrelid);
+
+ /*
+ * Sanity check: If the PartitionBoundSpec says this is the default
+ * partition, its OID should correspond to whatever's stored in
+ * pg_partitioned_table.partdefid; if not, the catalog is corrupt.
+ */
+ if (boundspec->is_default)
+ {
+ Oid partdefid;
+
+ partdefid = get_default_partition_oid(RelationGetRelid(rel));
+ if (partdefid != inhrelid)
+ elog(ERROR, "expected partdefid %u, but got %u",
+ inhrelid, partdefid);
+ }
+
+ oids[i] = inhrelid;
+ boundspecs[i] = boundspec;
+ ++i;
+ ReleaseSysCache(tuple);
+ }
+
+ /* Now build the actual relcache partition descriptor */
+ rel->rd_pdcxt = AllocSetContextCreate(CacheMemoryContext,
+ "partition descriptor",
+ ALLOCSET_DEFAULT_SIZES);
+ MemoryContextCopyAndSetIdentifier(rel->rd_pdcxt,
+ RelationGetRelationName(rel));
+
+ oldcxt = MemoryContextSwitchTo(rel->rd_pdcxt);
+ partdesc = (PartitionDescData *) palloc0(sizeof(PartitionDescData));
+ partdesc->nparts = nparts;
+ /* oids and boundinfo are allocated below. */
+
+ MemoryContextSwitchTo(oldcxt);
+
+ if (nparts == 0)
+ {
+ rel->rd_partdesc = partdesc;
+ return;
+ }
+
+ /* First create PartitionBoundInfo */
+ boundinfo = partition_bounds_create(boundspecs, nparts, key, &mapping);
+
+ /* Now copy boundinfo and oids into partdesc. */
+ oldcxt = MemoryContextSwitchTo(rel->rd_pdcxt);
+ partdesc->boundinfo = partition_bounds_copy(boundinfo, key);
+ partdesc->oids = (Oid *) palloc(partdesc->nparts * sizeof(Oid));
+ partdesc->is_leaf = (bool *) palloc(partdesc->nparts * sizeof(bool));
+
+ /*
+ * Now assign OIDs from the original array into mapped indexes of the
+ * result array. The order of OIDs in the former is defined by the
+ * catalog scan that retrieved them, whereas that in the latter is defined
+ * by canonicalized representation of the partition bounds.
+ */
+ for (i = 0; i < partdesc->nparts; i++)
+ {
+ int index = mapping[i];
+
+ partdesc->oids[index] = oids[i];
+ /* Record if the partition is a leaf partition */
+ partdesc->is_leaf[index] =
+ (get_rel_relkind(oids[i]) != RELKIND_PARTITIONED_TABLE);
+ }
+ MemoryContextSwitchTo(oldcxt);
+
+ rel->rd_partdesc = partdesc;
+}
+
+/*
+ * equalPartitionDescs
+ * Compare two partition descriptors for logical equality
+ */
+bool
+equalPartitionDescs(PartitionKey key, PartitionDesc partdesc1,
+ PartitionDesc partdesc2)
+{
+ int i;
+
+ if (partdesc1 != NULL)
+ {
+ if (partdesc2 == NULL)
+ return false;
+ if (partdesc1->nparts != partdesc2->nparts)
+ return false;
+
+ Assert(key != NULL || partdesc1->nparts == 0);
+
+ /*
+ * Same oids? If the partitioning structure did not change, that is,
+ * no partitions were added or removed to the relation, the oids array
+ * should still match element-by-element.
+ */
+ for (i = 0; i < partdesc1->nparts; i++)
+ {
+ if (partdesc1->oids[i] != partdesc2->oids[i])
+ return false;
+ }
+
+ /*
+ * Now compare partition bound collections. The logic to iterate over
+ * the collections is private to partition.c.
+ */
+ if (partdesc1->boundinfo != NULL)
+ {
+ if (partdesc2->boundinfo == NULL)
+ return false;
+
+ if (!partition_bounds_equal(key->partnatts, key->parttyplen,
+ key->parttypbyval,
+ partdesc1->boundinfo,
+ partdesc2->boundinfo))
+ return false;
+ }
+ else if (partdesc2->boundinfo != NULL)
+ return false;
+ }
+ else if (partdesc2 != NULL)
+ return false;
+
+ return true;
+}
+
+/*
+ * get_default_oid_from_partdesc
+ *
+ * Given a partition descriptor, return the OID of the default partition, if
+ * one exists; else, return InvalidOid.
+ */
+Oid
+get_default_oid_from_partdesc(PartitionDesc partdesc)
+{
+ if (partdesc && partdesc->boundinfo &&
+ partition_bound_has_default(partdesc->boundinfo))
+ return partdesc->oids[partdesc->boundinfo->default_index];
+
+ return InvalidOid;
+}