From fb0e89559b0b19e9c15bcdaef6bf118d0cf57b98 Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Wed, 27 Jul 2016 15:47:39 +0900
Subject: [PATCH 6/8] Introduce a PartitionDispatch data structure.

Each partitioned table in a partition tree gets one and contains info
such as a pointer to its partition descriptor, partition key execution
state, global sequence numbers of its leaf partitions and a way to link
to the PartitionDispatch objects of any of its partitions that are
partitioned themselves.

Starting with the PartitionDispatch object of the root partitioned table
and a tuple to route, one can get the global sequence number of the leaf
partition that the tuple gets routed to, if one exists.
---
 src/backend/catalog/partition.c |  145 +++++++++++++++++++++++++++++++++++++++
 src/include/catalog/partition.h |    5 ++
 2 files changed, 150 insertions(+), 0 deletions(-)

diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index e21e7ad..03c7fa1 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -114,6 +114,43 @@ typedef struct PartitionListValue
 	int		index;
 } PartitionListValue;
 
+/*---------------------
+ * PartitionKeyExecInfo
+ *
+ *		This struct holds the information needed to extract partition
+ *		column values from a heap tuple.
+ *
+ *		Key					copy of the rd_partkey of rel
+ *		ExpressionState		exec state for expressions, or NIL if none
+ *---------------------
+ */
+typedef struct PartitionKeyExecInfo
+{
+	NodeTag			type;
+	PartitionKey	pi_Key;
+	List		   *pi_ExpressionState;	/* list of ExprState */
+} PartitionKeyExecInfo;
+
+/*-----------------------
+ * PartitionDispatch - information about one partitioned table in a partition
+ * hiearchy required to route a tuple to one of its partitions
+ *
+ *	relid		OID of the table
+ *	pkinfo		Partition key execution state required for expressions
+ *	partdesc	Partition descriptor of the table
+ *	indexes		Array with partdesc->nparts members (for details on what
+ *				individual members represent, see how they are set in
+ *				RelationGetPartitionDispatchInfo())
+ *-----------------------
+ */
+typedef struct PartitionDispatchData
+{
+	Oid						relid;
+	PartitionKeyExecInfo   *pkinfo;
+	PartitionDesc			partdesc;
+	int					   *indexes;
+} PartitionDispatchData;
+
 static int32 qsort_partition_list_value_cmp(const void *a, const void *b, void *arg);
 static int32 qsort_partition_rbound_cmp(const void *a, const void *b, void *arg);
 
@@ -874,6 +911,114 @@ RelationGetPartitionQual(Relation rel, bool recurse)
 	return generate_partition_qual(rel, recurse);
 }
 
+/* Turn an array of OIDs with N elements into a list */
+#define OID_ARRAY_TO_LIST(arr, N, list) \
+	do\
+	{\
+		int		i;\
+		for (i = 0; i < (N); i++)\
+			(list) = lappend_oid((list), (arr)[i]);\
+	} while(0)
+
+/*
+ * RelationGetPartitionDispatchInfo
+ *		Returns information necessary to route tuples down a partition tree
+ *
+ * All the partitions will be locked with lockmode, unless it is NoLock.
+ * A list of the OIDs of all the leaf partition of rel is returned in
+ * *leaf_part_oids.
+ */
+PartitionDispatch *
+RelationGetPartitionDispatchInfo(Relation rel, int lockmode,
+								 List **leaf_part_oids)
+{
+	PartitionDesc	rootpartdesc = RelationGetPartitionDesc(rel);
+	PartitionDispatchData **pd;
+	List	   *all_parts = NIL,
+			   *parted_rels = NIL;
+	ListCell   *lc;
+	int			i,
+				k,
+				num_parted;
+
+	/*
+	 * Lock partitions and collect OIDs of the partitioned ones to prepare
+	 * their PartitionDispatch objects.
+	 *
+	 * Cannot use find_all_inheritors() here, because then the order of OIDs
+	 * in parted_rels list would be unknown, which does not help because down
+	 * below, we assign indexes within individual PartitionDispatch in an
+	 * order that's predetermined (determined by the order of OIDs in
+	 * individual partition descriptors).
+	 */
+	parted_rels = lappend_oid(parted_rels, RelationGetRelid(rel));
+	num_parted = 1;
+	OID_ARRAY_TO_LIST(rootpartdesc->oids, rootpartdesc->nparts, all_parts);
+	foreach(lc, all_parts)
+	{
+		Relation		partrel = heap_open(lfirst_oid(lc), lockmode);
+		PartitionDesc	partdesc = RelationGetPartitionDesc(partrel);
+
+		/*
+		 * If this partition is a partitined table, add its children to to the
+		 * end of the list, so that they are processed as well.
+		 */
+		if (partdesc)
+		{
+			num_parted++;
+			parted_rels = lappend_oid(parted_rels, lfirst_oid(lc));
+			OID_ARRAY_TO_LIST(partdesc->oids, partdesc->nparts, all_parts);
+		}
+
+		heap_close(partrel, NoLock);
+	}
+
+	/* Generate PartitionDispatch objects for all partitioned tables */
+	pd = (PartitionDispatchData **) palloc(num_parted *
+										sizeof(PartitionDispatchData *));
+	*leaf_part_oids = NIL;
+	i = k = 0;
+	foreach(lc, parted_rels)
+	{
+		/* We locked all partitions above */
+		Relation	partrel = heap_open(lfirst_oid(lc), NoLock);
+		PartitionDesc partdesc = RelationGetPartitionDesc(partrel);
+		int			j,
+					m;
+
+		pd[i] = (PartitionDispatch) palloc(sizeof(PartitionDispatchData));
+		pd[i]->relid = RelationGetRelid(partrel);
+		pd[i]->pkinfo = NULL;
+		pd[i]->partdesc = partdesc;
+		pd[i]->indexes = (int *) palloc(partdesc->nparts * sizeof(int));
+		heap_close(partrel, NoLock);
+
+		m = 0;
+		for (j = 0; j < partdesc->nparts; j++)
+		{
+			Oid		partrelid = partdesc->oids[j];
+
+			if (get_rel_relkind(partrelid) != RELKIND_PARTITIONED_TABLE)
+			{
+				*leaf_part_oids = lappend_oid(*leaf_part_oids, partrelid);
+				pd[i]->indexes[j] = k++;
+			}
+			else
+			{
+				/*
+				 * We can assign indexes this way because of the way
+				 * parted_rels has been generated.
+				 */
+				pd[i]->indexes[j] = -(i + 1 + m);
+				m++;
+			}
+		}
+		i++;
+	}
+
+	return pd;
+}
+
 /* Module-local functions */
 
 /*
diff --git a/src/include/catalog/partition.h b/src/include/catalog/partition.h
index 062de88..fb43cc1 100644
--- a/src/include/catalog/partition.h
+++ b/src/include/catalog/partition.h
@@ -36,6 +36,7 @@ typedef struct PartitionDescData
 } PartitionDescData;
 
 typedef struct PartitionDescData *PartitionDesc;
+typedef struct PartitionDispatchData *PartitionDispatch;
 
 extern void RelationBuildPartitionDesc(Relation relation);
 extern bool partition_bounds_equal(PartitionKey key,
@@ -45,4 +46,8 @@ extern void check_new_partition_bound(char *relname, Oid parentId, Node *bound);
 extern Oid get_partition_parent(Oid relid);
 extern List *get_qual_from_partbound(Relation rel, Relation parent, Node *bound);
 extern List *RelationGetPartitionQual(Relation rel, bool recurse);
+
+/* For tuple routing */
+extern PartitionDispatch *RelationGetPartitionDispatchInfo(Relation rel, int lockmode,
+								 List **leaf_part_oids);
 #endif   /* PARTITION_H */
-- 
1.7.1

