Modify-partition-matching-algorithm-1.patch
application/octet-stream
Filename: Modify-partition-matching-algorithm-1.patch
Type: application/octet-stream
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
| File | + | − |
|---|---|---|
| src/backend/nodes/outfuncs.c | 2 | 0 |
| src/backend/optimizer/path/joinrels.c | 202 | 67 |
| src/backend/optimizer/util/inherit.c | 2 | 0 |
| src/backend/optimizer/util/relnode.c | 9 | 3 |
| src/backend/partitioning/partbounds.c | 26 | 134 |
| src/include/nodes/pathnodes.h | 5 | 0 |
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index e6ce8e2110..b7849560b7 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -2281,6 +2281,8 @@ _outRelOptInfo(StringInfo str, const RelOptInfo *node)
WRITE_BOOL_FIELD(has_eclass_joins);
WRITE_BOOL_FIELD(consider_partitionwise_join);
WRITE_BITMAPSET_FIELD(top_parent_relids);
+ WRITE_BOOL_FIELD(merged);
+ WRITE_BITMAPSET_FIELD(all_partrels);
WRITE_NODE_FIELD(partitioned_child_rels);
}
diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c
index 52abd8a12f..8442e9d186 100644
--- a/src/backend/optimizer/path/joinrels.c
+++ b/src/backend/optimizer/path/joinrels.c
@@ -48,6 +48,9 @@ static SpecialJoinInfo *build_child_join_sjinfo(PlannerInfo *root,
Relids left_relids, Relids right_relids);
static int match_expr_to_partition_keys(Expr *expr, RelOptInfo *rel,
bool strict_op);
+static void get_matching_part_pairs(PlannerInfo *root, RelOptInfo *joinrel,
+ RelOptInfo *rel1, RelOptInfo *rel2,
+ List **parts1, List **parts2);
/*
@@ -1357,19 +1360,18 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
{
bool rel1_is_simple = IS_SIMPLE_REL(rel1);
bool rel2_is_simple = IS_SIMPLE_REL(rel2);
- PartitionScheme part_scheme;
- PartitionBoundInfo join_boundinfo;
- List *parts1;
- List *parts2;
- ListCell *lc1;
- ListCell *lc2;
+ bool merged = false;
+ 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)
+ if (joinrel->part_scheme == NULL || joinrel->nparts == 0)
return;
/* The join relation should have consider_partitionwise_join set. */
@@ -1394,51 +1396,100 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
*/
Assert(joinrel->part_scheme == rel1->part_scheme &&
joinrel->part_scheme == rel2->part_scheme);
- part_scheme = joinrel->part_scheme;
/*
- * Get the list of matching partitions to be joined along with the
- * partition bounds of the join relation. Because of the restrictions
- * imposed by partition matching algorithm, not every pair of joining
- * relations for this join will be able to use partition-wise join. But all
- * those pairs which can use partition-wise join will produce the same
- * partition bounds for the join relation.
+ * If we don't have the partition bounds for the join rel yet, try to
+ * create it along with pairs of partitions to be joined; else generate
+ * those using the partitioning info for the join rel we already have.
*/
- join_boundinfo = partition_bounds_merge(part_scheme->partnatts,
- part_scheme->parttyplen,
- part_scheme->parttypbyval,
- part_scheme->partsupfunc,
- part_scheme->partcollation,
- rel1, rel2,
- parent_sjinfo->jointype,
- &parts1, &parts2);
-
- if (join_boundinfo == NULL)
- return;
-
- if (joinrel->boundinfo == NULL)
+ if (joinrel->nparts == -1)
{
- Assert(joinrel->nparts == 0 && joinrel->part_rels == NULL);
- joinrel->boundinfo = join_boundinfo;
- joinrel->nparts = list_length(parts1);
- Assert(joinrel->nparts == list_length(parts2));
+ PartitionScheme part_scheme = joinrel->part_scheme;
+ PartitionBoundInfo boundinfo = NULL;
+ int nparts = 0;
+
+ Assert(joinrel->boundinfo == NULL);
+ Assert(joinrel->part_rels == NULL);
+
+ /*
+ * See if the partition bounds for inputs are exactly the same, in
+ * which case we don't need to work hard; partitions with the same
+ * partition indexes will form join pairs, and the join rel will have
+ * the same partition bounds as inputs.
+ *
+ * In theory, the partition bounds for inputs might be exactly the
+ * same even in the case where one or both inputs have merged
+ * partition bounds, but it seems unlikely to be worth the cycles to
+ * check.
+ */
+ if (!rel1->merged &&
+ !rel2->merged &&
+ rel1->nparts == rel2->nparts &&
+ partition_bounds_equal(part_scheme->partnatts,
+ part_scheme->parttyplen,
+ part_scheme->parttypbyval,
+ rel1->boundinfo, rel2->boundinfo))
+ {
+ boundinfo = rel1->boundinfo;
+ nparts = rel1->nparts;
+ }
+
+ /*
+ * Try to create the partition bounds along with join pairs.
+ */
+ if (boundinfo == NULL)
+ {
+ boundinfo = partition_bounds_merge(part_scheme->partnatts,
+ part_scheme->parttyplen,
+ part_scheme->parttypbyval,
+ part_scheme->partsupfunc,
+ part_scheme->partcollation,
+ rel1, rel2,
+ parent_sjinfo->jointype,
+ &parts1, &parts2);
+ Assert(list_length(parts1) == list_length(parts2));
+ if (boundinfo == NULL)
+ {
+ joinrel->nparts = 0;
+ return;
+ }
+ nparts = list_length(parts1);
+ merged = true;
+ }
+
+ Assert(nparts > 0);
+ joinrel->boundinfo = boundinfo;
+ joinrel->merged = merged;
+ joinrel->nparts = nparts;
joinrel->part_rels =
- (RelOptInfo **) palloc0(sizeof(RelOptInfo *) *
- joinrel->nparts);
+ (RelOptInfo **) palloc0(sizeof(RelOptInfo *) * nparts);
}
else
{
- Assert(partition_bounds_equal(part_scheme->partnatts,
- part_scheme->parttyplen,
- part_scheme->parttypbyval,
- join_boundinfo, joinrel->boundinfo));
+ Assert(joinrel->nparts > 0);
+ Assert(joinrel->boundinfo);
+ Assert(joinrel->part_rels);
+
/*
- * Every pair of joining relations should result in the same number
- * of child-joins.
+ * If the partition bounds for the join rel are not merged ones,
+ * inputs are guaranteed to have the same partition bounds, so
+ * partitions with the same partition indexes will form join pairs;
+ * else let get_matching_part_pairs() do the work.
*/
- Assert(joinrel->nparts == list_length(parts1));
- Assert(joinrel->nparts == list_length(parts2));
- Assert(joinrel->part_rels);
+ 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);
+ merged = true;
+ }
+ }
+
+ if (merged)
+ {
+ lcr1 = list_head(parts1);
+ lcr2 = list_head(parts2);
}
/*
@@ -1446,15 +1497,14 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
* exist. Add paths to child-joins for a pair of child relations
* corresponding to the given pair of parent relations.
*/
- cnt_parts = -1;
- forboth(lc1, parts1, lc2, parts2)
+ for (cnt_parts = 0; cnt_parts < joinrel->nparts; cnt_parts++)
{
- int part1 = lfirst_int(lc1);
- int part2 = lfirst_int(lc2);
- RelOptInfo *child_rel1;
- RelOptInfo *child_rel2;
- bool rel1_empty;
- bool rel2_empty;
+ RelOptInfo *child_rel1 = merged ? (RelOptInfo *) lfirst(lcr1) : rel1->part_rels[cnt_parts];
+ RelOptInfo *child_rel2 = merged ? (RelOptInfo *) lfirst(lcr2) : rel2->part_rels[cnt_parts];
+ bool rel1_empty = (child_rel1 == NULL ||
+ IS_DUMMY_REL(child_rel1));
+ bool rel2_empty = (child_rel2 == NULL ||
+ IS_DUMMY_REL(child_rel2));
SpecialJoinInfo *child_sjinfo;
List *child_restrictlist;
RelOptInfo *child_joinrel;
@@ -1462,12 +1512,11 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
AppendRelInfo **appinfos;
int nappinfos;
- Assert(part1 >= 0 && part2 >= 0);
- child_rel1 = rel1->part_rels[part1];
- child_rel2 = rel2->part_rels[part2];
- rel1_empty = (child_rel1 == NULL || IS_DUMMY_REL(child_rel1));
- rel2_empty = (child_rel2 == NULL || IS_DUMMY_REL(child_rel2));
- cnt_parts++;
+ if (merged)
+ {
+ lcr1 = lnext(parts1, lcr1);
+ lcr2 = lnext(parts2, lcr2);
+ }
/*
* Check for cases where we can prove that this segment of the join
@@ -1566,25 +1615,17 @@ try_partitionwise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
child_sjinfo,
child_sjinfo->jointype);
joinrel->part_rels[cnt_parts] = child_joinrel;
+ joinrel->all_partrels = bms_add_members(joinrel->all_partrels,
+ child_joinrel->relids);
}
- /*
- * For every pair of joining relations, the set of matching partitions
- * would change. However, the base relation partitions constituting
- * the given child should remain same for all the joining pairs. Since
- * the order in which children are stored in the array of child-joins,
- * depends upon partition bounds of the join, which are same for all
- * the joining pairs, every joining pair yields the child-joins in the
- * same order.
- */
Assert(bms_equal(child_joinrel->relids, child_joinrelids));
populate_joinrel_with_paths(root, child_rel1, child_rel2,
child_joinrel, child_sjinfo,
child_restrictlist);
- }
- Assert(cnt_parts == (joinrel->nparts - 1));
+ }
}
/*
@@ -1793,3 +1834,97 @@ match_expr_to_partition_keys(Expr *expr, RelOptInfo *rel, bool strict_op)
return -1;
}
+
+/*
+ * get_matching_part_pairs
+ * Generate join pairs of partitions for the two inputs for the join rel
+ */
+static void
+get_matching_part_pairs(PlannerInfo *root, RelOptInfo *joinrel,
+ RelOptInfo *rel1, RelOptInfo *rel2,
+ List **parts1, List **parts2)
+{
+ bool rel1_is_simple = IS_SIMPLE_REL(rel1);
+ bool rel2_is_simple = IS_SIMPLE_REL(rel2);
+ int cnt_parts;
+
+ *parts1 = NIL;
+ *parts2 = NIL;
+
+ for (cnt_parts = 0; cnt_parts < joinrel->nparts; cnt_parts++)
+ {
+ RelOptInfo *child_joinrel = joinrel->part_rels[cnt_parts];
+ RelOptInfo *child_rel1;
+ RelOptInfo *child_rel2;
+ Relids child_relids1;
+ Relids child_relids2;
+
+ /*
+ * If this segment of the join is empty, it means that this segment
+ * was ignored when previously creating child-join paths for it in
+ * try_partitionwise_join() as it would not contribute to the join
+ * result, due to one or both inputs being empty; add NULL to each of
+ * the given lists so that this segment will be ignored again in that
+ * function.
+ */
+ if (!child_joinrel)
+ {
+ *parts1 = lappend(*parts1, NULL);
+ *parts2 = lappend(*parts2, NULL);
+ continue;
+ }
+
+ /*
+ * Get a relids set of partition(s) involved in this join segment that
+ * are from the rel1 side.
+ */
+ child_relids1 = bms_intersect(child_joinrel->relids,
+ rel1->all_partrels);
+ Assert(bms_num_members(child_relids1) == bms_num_members(rel1->relids));
+ /*
+ * Get a child rel for rel1 with the relids. Note that we should have
+ * the child rel even if rel1 is a join rel, because in that case the
+ * partitions specified in the relids would have matching/overlapping
+ * boundaries, so those partitions should be considered as ones to be
+ * joined even when planning partitionwise joins of rel1, meaning that
+ * the child rel would have been built by the time we get here.
+ */
+ if (rel1_is_simple)
+ {
+ int varno = bms_singleton_member(child_relids1);
+
+ child_rel1 = find_base_rel(root, varno);
+ }
+ else
+ child_rel1 = find_join_rel(root, child_relids1);
+ Assert(child_rel1);
+
+ /*
+ * Get a relids set of partition(s) involved in this join segment that
+ * are from the rel2 side.
+ */
+ child_relids2 = bms_intersect(child_joinrel->relids,
+ rel2->all_partrels);
+ Assert(bms_num_members(child_relids2) == bms_num_members(rel2->relids));
+ /*
+ * Get a child rel for rel2 with the relids. See above comments.
+ */
+ if (rel2_is_simple)
+ {
+ int varno = bms_singleton_member(child_relids2);
+
+ child_rel2 = find_base_rel(root, varno);
+ }
+ else
+ child_rel2 = find_join_rel(root, child_relids2);
+ Assert(child_rel2);
+
+ /*
+ * The join of rel1 and rel2 is legal, so is the join of the child
+ * rels obtained above; add them to the given lists as a join pair
+ * producing this join segment.
+ */
+ *parts1 = lappend(*parts1, child_rel1);
+ *parts2 = lappend(*parts2, child_rel2);
+ }
+}
diff --git a/src/backend/optimizer/util/inherit.c b/src/backend/optimizer/util/inherit.c
index 38bc61e687..caf6039c10 100644
--- a/src/backend/optimizer/util/inherit.c
+++ b/src/backend/optimizer/util/inherit.c
@@ -376,6 +376,8 @@ expand_partitioned_rtentry(PlannerInfo *root, RelOptInfo *relinfo,
/* Create the otherrel RelOptInfo too. */
childrelinfo = build_simple_rel(root, childRTindex, relinfo);
relinfo->part_rels[i] = childrelinfo;
+ relinfo->all_partrels = bms_add_members(relinfo->all_partrels,
+ childrelinfo->relids);
/* If this child is itself partitioned, recurse */
if (childrel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index ce85082bb3..248a9e9093 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -240,10 +240,12 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptInfo *parent)
rel->has_eclass_joins = false;
rel->consider_partitionwise_join = false; /* might get changed later */
rel->part_scheme = NULL;
- rel->nparts = 0;
+ rel->nparts = -1;
rel->boundinfo = NULL;
+ rel->merged = false;
rel->partition_qual = NIL;
rel->part_rels = NULL;
+ rel->all_partrels = NULL;
rel->partexprs = NULL;
rel->nullable_partexprs = NULL;
rel->partitioned_child_rels = NIL;
@@ -653,10 +655,12 @@ build_join_rel(PlannerInfo *root,
joinrel->consider_partitionwise_join = false; /* might get changed later */
joinrel->top_parent_relids = NULL;
joinrel->part_scheme = NULL;
- joinrel->nparts = 0;
+ joinrel->nparts = -1;
joinrel->boundinfo = NULL;
+ joinrel->merged = false;
joinrel->partition_qual = NIL;
joinrel->part_rels = NULL;
+ joinrel->all_partrels = NULL;
joinrel->partexprs = NULL;
joinrel->nullable_partexprs = NULL;
joinrel->partitioned_child_rels = NIL;
@@ -829,10 +833,12 @@ build_child_join_rel(PlannerInfo *root, RelOptInfo *outer_rel,
joinrel->consider_partitionwise_join = false; /* might get changed later */
joinrel->top_parent_relids = NULL;
joinrel->part_scheme = NULL;
- joinrel->nparts = 0;
+ joinrel->nparts = -1;
joinrel->boundinfo = NULL;
+ joinrel->merged = false;
joinrel->partition_qual = NIL;
joinrel->part_rels = NULL;
+ joinrel->all_partrels = NULL;
joinrel->partexprs = NULL;
joinrel->nullable_partexprs = NULL;
joinrel->partitioned_child_rels = NIL;
diff --git a/src/backend/partitioning/partbounds.c b/src/backend/partitioning/partbounds.c
index a8c85966af..f06fa0827c 100644
--- a/src/backend/partitioning/partbounds.c
+++ b/src/backend/partitioning/partbounds.c
@@ -124,15 +124,14 @@ static PartitionBoundInfo partition_list_bounds_merge(FmgrInfo *partsupfunc, Oid
RelOptInfo *outer_rel, RelOptInfo *inner_rel,
List **outer_parts, List **inner_parts,
JoinType jointype);
-static PartitionBoundInfo partition_hash_bounds_merge(int partnatts,
- int16 *parttyplen, bool *parttypbyval,
- RelOptInfo *outer_rel, RelOptInfo *inner_rel,
- List **outer_parts, List **inner_parts);
-static void generate_matching_part_pairs(PartitionMap *outer_maps,
- PartitionMap *inner_maps,
- int nparts1, int nparts2,
- JoinType jointype, int nparts,
- List **parts1, List **parts2);
+static void generate_matching_part_pairs(RelOptInfo *rel1,
+ RelOptInfo *rel2,
+ PartitionMap *partmaps1,
+ PartitionMap *partmaps2,
+ int nparts1, int nparts2,
+ int nparts,
+ List **matched_parts1,
+ List **matched_parts2);
static PartitionBoundInfo build_merged_partition_bounds(char strategy,
List *merged_datums, List *merged_indexes,
List *merged_contents, int null_index,
@@ -3104,6 +3103,11 @@ partition_bounds_merge(int partnatts,
*inner_parts = NIL;
switch (strategy)
{
+ case PARTITION_STRATEGY_HASH:
+ merged_bounds = NULL;
+
+ break;
+
case PARTITION_STRATEGY_LIST:
merged_bounds = partition_list_bounds_merge(partsupfunc,
partcollation,
@@ -3120,13 +3124,6 @@ partition_bounds_merge(int partnatts,
partcollation);
break;
- case PARTITION_STRATEGY_HASH:
- merged_bounds = partition_hash_bounds_merge(partnatts,
- parttyplen, parttypbyval,
- outer_rel, inner_rel,
- outer_parts, inner_parts);
- break;
-
default:
elog(ERROR, "unexpected partition strategy: %d", strategy);
}
@@ -3135,9 +3132,6 @@ partition_bounds_merge(int partnatts,
Assert(list_length(*outer_parts) == list_length(*inner_parts));
- Assert((*outer_parts == NIL || *inner_parts != NIL) &&
- (*inner_parts == NIL || *outer_parts != NIL));
-
return merged_bounds;
}
@@ -3839,9 +3833,10 @@ partition_range_bounds_merge(RelOptInfo *outer_rel, RelOptInfo *inner_rel,
return NULL;
/* Use maps to match partition from the joining relations. */
- generate_matching_part_pairs(outer_maps, inner_maps,
+ generate_matching_part_pairs(outer_rel, inner_rel,
+ outer_maps, inner_maps,
outer_nparts, inner_nparts,
- jointype, next_index,
+ next_index,
outer_parts, inner_parts);
/* Craft a PartitionBoundInfo to return. */
@@ -4099,9 +4094,10 @@ partition_list_bounds_merge(FmgrInfo *partsupfunc, Oid *partcollation,
return NULL;
/* Use maps to match partition from the joining relations. */
- generate_matching_part_pairs(outer_maps, inner_maps,
+ generate_matching_part_pairs(outer_rel, inner_rel,
+ outer_maps, inner_maps,
outer_nparts, inner_nparts,
- jointype, next_index,
+ next_index,
outer_parts, inner_parts);
/* Craft a PartitionBoundInfo to return. */
@@ -4122,61 +4118,6 @@ partition_list_bounds_merge(FmgrInfo *partsupfunc, Oid *partcollation,
return merged_bounds;
}
-/*
- * partition_bounds_merge()'s arm for hash partitioned tables.
- *
- * If the given two hash bounds are same, the function returns the first one
- * without any change, alongwith the lists of matching partitions. Otherwise it
- * returns NULL.
- *
- * We could try merging the bounds when both the bounds have same greatest
- * modulii. But there seems to be hardly any requirement for the same.
- */
-static PartitionBoundInfo
-partition_hash_bounds_merge(int partnatts,
- int16 *parttyplen, bool *parttypbyval,
- RelOptInfo *outer_rel, RelOptInfo *inner_rel,
- List **outer_parts, List **inner_parts)
-{
- PartitionBoundInfo outer_bi = outer_rel->boundinfo,
- inner_bi = inner_rel->boundinfo;
- int cnt;
-
- Assert(*outer_parts == NIL);
- Assert(*inner_parts == NIL);
-
- Assert(outer_bi->strategy == inner_bi->strategy &&
- outer_bi->strategy == PARTITION_STRATEGY_HASH);
-
- /*
- * Hash partitioned table does not have explicit NULL accepting partition
- * and also does not have a default partition.
- */
- Assert(!partition_bound_has_default(outer_bi) &&
- !partition_bound_has_default(inner_bi));
- Assert(!partition_bound_accepts_nulls(outer_bi) &&
- !partition_bound_accepts_nulls(inner_bi));
-
- if (outer_rel->nparts != inner_rel->nparts)
- return NULL;
-
- if (!partition_bounds_equal(partnatts, parttyplen, parttypbyval,
- outer_bi, inner_bi))
- return NULL;
-
- /*
- * Cook up list of matching partitions. Since bounds are exactly same the
- * partitions at the same position from both the relations match.
- */
- for (cnt = 0; cnt < outer_rel->nparts; cnt++)
- {
- *outer_parts = lappend_int(*outer_parts, cnt);
- *inner_parts = lappend_int(*inner_parts, cnt);
- }
-
- return outer_bi;
-}
-
/*
* map_and_merge_partitions
*
@@ -4312,12 +4253,11 @@ map_and_merge_partitions(PartitionMap *partmaps1, PartitionMap *partmaps2,
* set to NIL.
*/
static void
-generate_matching_part_pairs(PartitionMap *partmaps1, PartitionMap *partmaps2,
- int nparts1, int nparts2,
- JoinType jointype, int nparts,
+generate_matching_part_pairs(RelOptInfo *rel1, RelOptInfo *rel2,
+ PartitionMap *partmaps1, PartitionMap *partmaps2,
+ int nparts1, int nparts2, int nparts,
List **matched_parts1, List **matched_parts2)
{
- bool merged = true;
int *matching1,
*matching2;
int i;
@@ -4358,16 +4298,6 @@ generate_matching_part_pairs(PartitionMap *partmaps1, PartitionMap *partmaps2,
}
}
- /*
- * If we have a partition missing on an inner side, we need to add a dummy
- * relation which joins with the outer partition. If the inner relation
- * happens to be a base relation, it will require adding a dummy child
- * base relation during join processing. Right now, we freeze the base
- * relation arrays like PlannerInfo::simple_rte_array after planning for
- * base relations. Adding a new (dummy) base relation would require some
- * changes to that. So, right now, we do not implement partition-wise join
- * in such cases.
- */
for (i = 0; i < nparts; i++)
{
int part1 = matching1[i];
@@ -4376,52 +4306,14 @@ generate_matching_part_pairs(PartitionMap *partmaps1, PartitionMap *partmaps2,
/* At least one of the partitions should exist. */
Assert(part1 >= 0 || part2 >= 0);
- switch (jointype)
- {
- case JOIN_INNER:
- case JOIN_SEMI:
-
- /*
- * An inner or semi join can not return any row when the
- * matching partition on either side is missing. We should
- * have eliminated all such cases while merging the bounds.
- */
- Assert(part1 >= 0 && part2 >= 0);
- break;
-
- case JOIN_LEFT:
- case JOIN_ANTI:
- Assert(part1 >= 0);
- if (part2 < 0)
- merged = false;
- break;
-
- case JOIN_FULL:
- if (part1 < 0 || part2 < 0)
- merged = false;
- break;
-
- default:
- elog(ERROR, "unrecognized join type: %d", (int) jointype);
- }
-
- if (!merged)
- break;
-
- *matched_parts1 = lappend_int(*matched_parts1, part1);
- *matched_parts2 = lappend_int(*matched_parts2, part2);
+ *matched_parts1 = lappend(*matched_parts1,
+ part1 >= 0 ? rel1->part_rels[part1] : NULL);
+ *matched_parts2 = lappend(*matched_parts2,
+ part2 >= 0 ? rel2->part_rels[part2] : NULL);
}
pfree(matching1);
pfree(matching2);
-
- if (!merged)
- {
- list_free(*matched_parts1);
- list_free(*matched_parts2);
- *matched_parts1 = NIL;
- *matched_parts2 = NIL;
- }
}
static PartitionBoundInfo
diff --git a/src/include/nodes/pathnodes.h b/src/include/nodes/pathnodes.h
index 23a06d718e..e06eb9aaae 100644
--- a/src/include/nodes/pathnodes.h
+++ b/src/include/nodes/pathnodes.h
@@ -577,8 +577,10 @@ typedef struct PartitionSchemeData *PartitionScheme;
* part_scheme - Partitioning scheme of the relation
* nparts - Number of partitions
* boundinfo - Partition bounds
+ * merged - true if partition bounds are merged ones
* partition_qual - Partition constraint if not the root
* part_rels - RelOptInfos for each partition
+ * all_partrels - Relids set of all partition relids
* partexprs, nullable_partexprs - Partition key expressions
* partitioned_child_rels - RT indexes of unpruned partitions of
* this relation that are partitioned tables
@@ -718,9 +720,12 @@ typedef struct RelOptInfo
PartitionScheme part_scheme; /* Partitioning scheme. */
int nparts; /* number of partitions */
struct PartitionBoundInfoData *boundinfo; /* Partition bounds */
+ bool merged; /* true if partition bounds were created by
+ * partition_bounds_merge() */
List *partition_qual; /* partition constraint */
struct RelOptInfo **part_rels; /* Array of RelOptInfos of partitions,
* stored in the same order of bounds */
+ Relids all_partrels; /* Relids set of all partition relids */
List **partexprs; /* Non-nullable partition key expressions. */
List **nullable_partexprs; /* Nullable partition key expressions. */
List *partitioned_child_rels; /* List of RT indexes. */