pg_dp_dummy_crash.patch
text/x-patch
Filename: pg_dp_dummy_crash.patch
Type: text/x-patch
Part: 0
Patch
Format: unified
| File | + | − |
|---|---|---|
| src/backend/optimizer/path/allpaths.c | 4 | 14 |
| src/backend/optimizer/path/joinrels.c | 0 | 16 |
| src/backend/optimizer/util/relnode.c | 4 | 1 |
| src/include/nodes/relation.h | 16 | 3 |
| src/test/regress/expected/partition_join.out | 25 | 18 |
| src/test/regress/sql/partition_join.sql | 1 | 1 |
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 5bff90e..6e842f9 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -3425,20 +3425,8 @@ generate_partition_wise_join_paths(PlannerInfo *root, RelOptInfo *rel)
if (!IS_JOIN_REL(rel))
return;
- /*
- * If we've already proven this join is empty, we needn't consider any
- * more paths for it.
- */
- if (IS_DUMMY_REL(rel))
- return;
-
- /*
- * We've nothing to do if the relation is not partitioned. An outer join
- * relation which had an empty inner relation in every pair will have the
- * rest of the partitioning properties set except the child-join
- * RelOptInfos. See try_partition_wise_join() for more details.
- */
- if (rel->nparts <= 0 || rel->part_rels == NULL)
+ /* We've nothing to do if the relation is not partitioned. */
+ if (!IS_PARTITIONED_REL(rel))
return;
/* Guard against stack overflow due to overly deep partition hierarchy. */
@@ -3452,6 +3440,8 @@ generate_partition_wise_join_paths(PlannerInfo *root, RelOptInfo *rel)
{
RelOptInfo *child_rel = part_rels[cnt_parts];
+ Assert(child_rel != NULL);
+
/* Add partition-wise join paths for partitioned child-joins. */
generate_partition_wise_join_paths(root, child_rel);
diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c
index a35d068..f74afdb 100644
--- a/src/backend/optimizer/path/joinrels.c
+++ b/src/backend/optimizer/path/joinrels.c
@@ -1319,17 +1319,6 @@ try_partition_wise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
return;
/*
- * set_rel_pathlist() may not create paths in children of an empty
- * partitioned table and so we can not add paths to child-joins. So, deem
- * such a join as unpartitioned. When a partitioned relation is deemed
- * empty because all its children are empty, dummy path will be set in
- * each of the children. In such a case we could still consider the join
- * as partitioned, but it might not help much.
- */
- if (IS_DUMMY_REL(rel1) || IS_DUMMY_REL(rel2))
- return;
-
- /*
* Since this join relation is partitioned, all the base relations
* participating in this join must be partitioned and so are all the
* intermediate join relations.
@@ -1360,11 +1349,6 @@ try_partition_wise_join(PlannerInfo *root, RelOptInfo *rel1, RelOptInfo *rel2,
nparts = joinrel->nparts;
- /* Allocate space to hold child-joins RelOptInfos, if not already done. */
- if (!joinrel->part_rels)
- joinrel->part_rels =
- (RelOptInfo **) palloc0(sizeof(RelOptInfo *) * nparts);
-
/*
* Create child-join relations for this partitioned join, if those don't
* exist. Add paths to child-joins for a pair of child relations
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index ac5a7c9..5c36832 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -1662,11 +1662,14 @@ build_joinrel_partition_info(RelOptInfo *joinrel, RelOptInfo *outer_rel,
*/
joinrel->part_scheme = part_scheme;
joinrel->boundinfo = outer_rel->boundinfo;
- joinrel->nparts = outer_rel->nparts;
partnatts = joinrel->part_scheme->partnatts;
joinrel->partexprs = (List **) palloc0(sizeof(List *) * partnatts);
joinrel->nullable_partexprs =
(List **) palloc0(sizeof(List *) * partnatts);
+ joinrel->nparts = outer_rel->nparts;
+ joinrel->part_rels =
+ (RelOptInfo **) palloc0(sizeof(RelOptInfo *) * joinrel->nparts);
+
/*
* Construct partition keys for the join.
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index 6bf68f3..e082d05 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -668,11 +668,24 @@ typedef struct RelOptInfo
*
* A join between two partitioned relations with same partitioning scheme
* without any matching partitions will not have any partition in it but will
- * have partition scheme set. So a relation is deemed to be partitioned if it
- * has a partitioning scheme, bounds and positive number of partitions.
+ * have partition scheme set.
+ *
+ * set_rel_pathlist() may not create paths in children of an empty partitioned
+ * table. Hence we can not add paths to child-joins produced as a result of
+ * joining an empty partitioned table with another similarly partitioned table.
+ * So, deem such a join as unpartitioned. As a result any N-way join involving
+ * an empty partitioned table will be deemed as unpartitioned and will not have
+ * child-RelOptInfos created. NOTE: When a partitioned relation is deemed empty
+ * because all its children are empty, dummy path will be set in each of the
+ * children. In such a case we could still consider the join as partitioned,
+ * but it might not help much.
+ *
+ * So a relation is deemed to be partitioned if it has a partitioning scheme,
+ * bounds, positive number of partitions and child RelOptInfos.
*/
#define IS_PARTITIONED_REL(rel) \
- ((rel)->part_scheme && (rel)->boundinfo && (rel)->nparts > 0)
+ ((rel)->part_scheme && (rel)->boundinfo && (rel)->nparts > 0 && \
+ (rel)->part_rels && !(IS_DUMMY_REL(rel)))
/*
* Convenience macro to make sure that a partitioned relation has all the
diff --git a/src/test/regress/expected/partition_join.out b/src/test/regress/expected/partition_join.out
index 27ab852..333f938 100644
--- a/src/test/regress/expected/partition_join.out
+++ b/src/test/regress/expected/partition_join.out
@@ -1217,24 +1217,31 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1
(2 rows)
EXPLAIN (COSTS OFF)
-SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b WHERE t2.a = 0 ORDER BY t1.a, t2.b;
- QUERY PLAN
---------------------------------------------
- Sort
- Sort Key: a, t2.b
- -> Hash Left Join
- Hash Cond: (t2.b = a)
- -> Append
- -> Seq Scan on prt2_p1 t2
- Filter: (a = 0)
- -> Seq Scan on prt2_p2 t2_1
- Filter: (a = 0)
- -> Seq Scan on prt2_p3 t2_2
- Filter: (a = 0)
- -> Hash
- -> Result
- One-Time Filter: false
-(14 rows)
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b, prt1 t3 WHERE t2.b = t3.a;
+ QUERY PLAN
+--------------------------------------------------
+ Hash Left Join
+ Hash Cond: (t2.b = a)
+ -> Append
+ -> Hash Join
+ Hash Cond: (t3.a = t2.b)
+ -> Seq Scan on prt1_p1 t3
+ -> Hash
+ -> Seq Scan on prt2_p1 t2
+ -> Hash Join
+ Hash Cond: (t3_1.a = t2_1.b)
+ -> Seq Scan on prt1_p2 t3_1
+ -> Hash
+ -> Seq Scan on prt2_p2 t2_1
+ -> Hash Join
+ Hash Cond: (t3_2.a = t2_2.b)
+ -> Seq Scan on prt1_p3 t3_2
+ -> Hash
+ -> Seq Scan on prt2_p3 t2_2
+ -> Hash
+ -> Result
+ One-Time Filter: false
+(21 rows)
EXPLAIN (COSTS OFF)
SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1 FULL JOIN prt2 t2 ON t1.a = t2.b WHERE t2.a = 0 ORDER BY t1.a, t2.b;
diff --git a/src/test/regress/sql/partition_join.sql b/src/test/regress/sql/partition_join.sql
index 6efdf3c..55c5615 100644
--- a/src/test/regress/sql/partition_join.sql
+++ b/src/test/regress/sql/partition_join.sql
@@ -224,7 +224,7 @@ EXPLAIN (COSTS OFF)
SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1 LEFT JOIN prt2 t2 ON t1.a = t2.b;
EXPLAIN (COSTS OFF)
-SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b WHERE t2.a = 0 ORDER BY t1.a, t2.b;
+SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1 RIGHT JOIN prt2 t2 ON t1.a = t2.b, prt1 t3 WHERE t2.b = t3.a;
EXPLAIN (COSTS OFF)
SELECT t1.a, t1.c, t2.b, t2.c FROM (SELECT * FROM prt1 WHERE a = 1 AND a = 2) t1 FULL JOIN prt2 t2 ON t1.a = t2.b WHERE t2.a = 0 ORDER BY t1.a, t2.b;