From dc5f82f8c74a04c55b03bc8c6d09ffd7f93f70ca Mon Sep 17 00:00:00 2001
From: Tomas Vondra <tv@fuzzy.cz>
Date: Thu, 26 Mar 2020 01:15:04 +0100
Subject: [PATCH 3/3] split try_partitionwise_join

---
 src/backend/optimizer/path/joinrels.c | 146 ++++++++++++++------------
 1 file changed, 78 insertions(+), 68 deletions(-)

diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c
index 0b082fc915..314b0267c3 100644
--- a/src/backend/optimizer/path/joinrels.c
+++ b/src/backend/optimizer/path/joinrels.c
@@ -1333,71 +1333,12 @@ restriction_is_constant_false(List *restrictlist,
 	return false;
 }
 
-/*
- * Assess whether join between given two partitioned relations can be broken
- * down into joins between matching partitions; a technique called
- * "partitionwise join"
- *
- * Partitionwise join is possible when a. Joining relations have same
- * partitioning scheme b. There exists an equi-join between the partition keys
- * of the two relations.
- *
- * Partitionwise join is planned as follows (details: optimizer/README.)
- *
- * 1. Create the RelOptInfos for joins between matching partitions i.e
- * child-joins and add paths to them.
- *
- * 2. Construct Append or MergeAppend paths across the set of child joins.
- * This second phase is implemented by generate_partitionwise_join_paths().
- *
- * The RelOptInfo, SpecialJoinInfo and restrictlist for each child join are
- * obtained by translating the respective parent join structures.
- */
 static void
-try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
-					   RelOptInfo *joinrel, SpecialJoinInfo *parent_sjinfo,
-					   List *parent_restrictlist)
+compute_partition_bounds(PlannerInfo *root, RelOptInfo *rel1,
+						 RelOptInfo *rel2, RelOptInfo *joinrel,
+						 SpecialJoinInfo *parent_sjinfo,
+						 List **parts1, List **parts2)
 {
-	bool		rel1_is_simple = IS_SIMPLE_REL(rel1);
-	bool		rel2_is_simple = IS_SIMPLE_REL(rel2);
-	List	   *parts1 = NIL;
-	List	   *parts2 = NIL;
-	ListCell   *lcr1 = NULL;
-	ListCell   *lcr2 = NULL;
-	int			cnt_parts;
-
-	/* Guard against stack overflow due to overly deep partition hierarchy. */
-	check_stack_depth();
-
-	/* Nothing to do, if the join relation is not partitioned. */
-	if (joinrel->part_scheme == NULL || joinrel->nparts == 0)
-		return;
-
-	/* The join relation should have consider_partitionwise_join set. */
-	Assert(joinrel->consider_partitionwise_join);
-
-	/*
-	 * We can not perform partitionwise join if either of the joining relations
-	 * is not partitioned.
-	 */
-	if (!IS_PARTITIONED_REL(rel1) || !IS_PARTITIONED_REL(rel2))
-		return;
-
-	Assert(REL_HAS_ALL_PART_PROPS(rel1) && REL_HAS_ALL_PART_PROPS(rel2));
-
-	/* The joining relations should have consider_partitionwise_join set. */
-	Assert(rel1->consider_partitionwise_join &&
-		   rel2->consider_partitionwise_join);
-
-	/*
-	 * The partition scheme of the join relation should match that of the
-	 * joining relations.
-	 */
-	Assert(joinrel->part_scheme == rel1->part_scheme &&
-		   joinrel->part_scheme == rel2->part_scheme);
-
-	Assert(!(joinrel->merged && (joinrel->nparts <= 0)));
-
 	/*
 	 * If we don't have the partition bounds for the join rel yet, try to
 	 * compute those along with pairs of partitions to be joined.
@@ -1440,13 +1381,13 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
 											   part_scheme->partcollation,
 											   rel1, rel2,
 											   parent_sjinfo->jointype,
-											   &parts1, &parts2);
+											   parts1, parts2);
 			if (boundinfo == NULL)
 			{
 				joinrel->nparts = 0;
 				return;
 			}
-			nparts = list_length(parts1);
+			nparts = list_length(*parts1);
 			joinrel->merged = true;
 		}
 
@@ -1472,11 +1413,80 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
 		if (joinrel->merged)
 		{
 			get_matching_part_pairs(root, joinrel, rel1, rel2,
-									&parts1, &parts2);
-			Assert(list_length(parts1) == joinrel->nparts);
-			Assert(list_length(parts2) == joinrel->nparts);
+									parts1, parts2);
+			Assert(list_length(*parts1) == joinrel->nparts);
+			Assert(list_length(*parts2) == joinrel->nparts);
 		}
 	}
+}
+
+/*
+ * Assess whether join between given two partitioned relations can be broken
+ * down into joins between matching partitions; a technique called
+ * "partitionwise join"
+ *
+ * Partitionwise join is possible when a. Joining relations have same
+ * partitioning scheme b. There exists an equi-join between the partition keys
+ * of the two relations.
+ *
+ * Partitionwise join is planned as follows (details: optimizer/README.)
+ *
+ * 1. Create the RelOptInfos for joins between matching partitions i.e
+ * child-joins and add paths to them.
+ *
+ * 2. Construct Append or MergeAppend paths across the set of child joins.
+ * This second phase is implemented by generate_partitionwise_join_paths().
+ *
+ * The RelOptInfo, SpecialJoinInfo and restrictlist for each child join are
+ * obtained by translating the respective parent join structures.
+ */
+static void
+try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
+					   RelOptInfo *joinrel, SpecialJoinInfo *parent_sjinfo,
+					   List *parent_restrictlist)
+{
+	bool		rel1_is_simple = IS_SIMPLE_REL(rel1);
+	bool		rel2_is_simple = IS_SIMPLE_REL(rel2);
+	List	   *parts1 = NIL;
+	List	   *parts2 = NIL;
+	ListCell   *lcr1 = NULL;
+	ListCell   *lcr2 = NULL;
+	int			cnt_parts;
+
+	/* Guard against stack overflow due to overly deep partition hierarchy. */
+	check_stack_depth();
+
+	/* Nothing to do, if the join relation is not partitioned. */
+	if (joinrel->part_scheme == NULL || joinrel->nparts == 0)
+		return;
+
+	/* The join relation should have consider_partitionwise_join set. */
+	Assert(joinrel->consider_partitionwise_join);
+
+	/*
+	 * We can not perform partitionwise join if either of the joining relations
+	 * is not partitioned.
+	 */
+	if (!IS_PARTITIONED_REL(rel1) || !IS_PARTITIONED_REL(rel2))
+		return;
+
+	Assert(REL_HAS_ALL_PART_PROPS(rel1) && REL_HAS_ALL_PART_PROPS(rel2));
+
+	/* The joining relations should have consider_partitionwise_join set. */
+	Assert(rel1->consider_partitionwise_join &&
+		   rel2->consider_partitionwise_join);
+
+	/*
+	 * The partition scheme of the join relation should match that of the
+	 * joining relations.
+	 */
+	Assert(joinrel->part_scheme == rel1->part_scheme &&
+		   joinrel->part_scheme == rel2->part_scheme);
+
+	Assert(!(joinrel->merged && (joinrel->nparts <= 0)));
+
+	compute_partition_bounds(root, rel1, rel2, joinrel, parent_sjinfo,
+							 &parts1, &parts2);
 
 	if (joinrel->merged)
 	{
-- 
2.21.1

