On Mon, Jun 18, 2018 at 9:27 PM, Andres Freund <and...@anarazel.de> wrote:

> On 2018-06-18 17:10:12 +0530, Jeevan Chalke wrote:
> > On Mon, Jun 18, 2018 at 5:02 PM, Rajkumar Raghuwanshi <
> > rajkumar.raghuwan...@enterprisedb.com> wrote:
> >
> > > Hi,
> > >
> > > Below test case crashed, when set enable_partitionwise_aggregate to
> true.
> > >
> >
> > I will have a look over this.
>

In the reported testcase, parallel_workers is set to 0 for all partition
(child) relations. Which means partial parallel paths are not possible for
child rels. However, the parent can have partial parallel paths. Thus, when
we have a full partitionwise aggregate possible (as the group by clause
matches with the partition key), we end-up in a situation where we do
create a partially_grouped_rel for the parent but there won't be any
partially_grouped_live_children.

The current code was calling add_paths_to_append_rel() without making sure
of any live children present or not (sorry, it was my fault). This causes
an Assertion failure in add_paths_to_append_rel() as this function assumes
that it will have non-NIL live_childrels list.

I have fixed partitionwise aggregate code which is calling
add_paths_to_append_rel() by checking the live children list correctly. And
for robustness, I have also added an Assert() in add_paths_to_append_rel().

I have verified the callers of add_paths_to_append_rel() and except one,
all are calling it by making sure that they have a non-NIL live children
list. The one which is calling add_paths_to_append_rel() directly is
set_append_rel_pathlist(). And I think, at that place, we will never have
an empty live children list, I may be wrong though. And if that's the case
then newly added Assert() in add_paths_to_append_rel() will fail anyway to
catch any programming error in that code path.

Attached patch fixing the crash and also added a simple test-coverage for
that.

Let me know if I missed any.

Thanks


> >
> > Thanks for reporting.
>
> I've added an v11 open-items entry.
>
> - Andres
>

-- 
Jeevan Chalke
Technical Architect, Product Development
EnterpriseDB Corporation
The Enterprise PostgreSQL Company
From e969ef65e7ccebaa4d068a09ac9db812ee0793ab Mon Sep 17 00:00:00 2001
From: Jeevan Chalke <jeevan.cha...@enterprisedb.com>
Date: Tue, 19 Jun 2018 10:44:33 +0530
Subject: [PATCH] Make sure that we have live children before we append them.

In create_partitionwise_grouping_paths(), we were calling
add_paths_to_append_rel() on empty live children which causing
an Assertion failure inside it. Thus, prevent calling
add_paths_to_append_rel() when there are no live children.

In passing, add an Assert() in add_paths_to_append_rel() to
check that it receives a valid live children list.

Jeevan Chalke
---
 src/backend/optimizer/path/allpaths.c             |  3 ++
 src/backend/optimizer/plan/planner.c              |  6 ++--
 src/test/regress/expected/partition_aggregate.out | 40 +++++++++++++++++++++++
 src/test/regress/sql/partition_aggregate.sql      | 14 ++++++++
 4 files changed, 61 insertions(+), 2 deletions(-)

diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 477b9f7..4d8e7a0 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -1391,6 +1391,9 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
 	bool		build_partitioned_rels = false;
 	double		partial_rows = -1;
 
+	/* We should end-up here only when we have few live child rels. */
+	Assert(live_childrels != NIL);
+
 	/*
 	 * AppendPath generated for partitioned tables must record the RT indexes
 	 * of partitioned tables that are direct or indirect children of this
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 67a2c7a..5e75f7f 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -7114,8 +7114,10 @@ create_partitionwise_grouping_paths(PlannerInfo *root,
 	 * partitionwise aggregation, we might have paths in the partial_pathlist
 	 * if parallel aggregation is possible.  For partial partitionwise
 	 * aggregation, we may have paths in both pathlist and partial_pathlist.
+	 * However, if there are no live children, then we cannot create any append
+	 * path.
 	 */
-	if (partially_grouped_rel)
+	if (partially_grouped_rel && partially_grouped_live_children != NIL)
 	{
 		add_paths_to_append_rel(root, partially_grouped_rel,
 								partially_grouped_live_children);
@@ -7129,7 +7131,7 @@ create_partitionwise_grouping_paths(PlannerInfo *root,
 	}
 
 	/* If possible, create append paths for fully grouped children. */
-	if (patype == PARTITIONWISE_AGGREGATE_FULL)
+	if (patype == PARTITIONWISE_AGGREGATE_FULL && grouped_live_children != NIL)
 		add_paths_to_append_rel(root, grouped_rel, grouped_live_children);
 }
 
diff --git a/src/test/regress/expected/partition_aggregate.out b/src/test/regress/expected/partition_aggregate.out
index 76a8209..bfde035 100644
--- a/src/test/regress/expected/partition_aggregate.out
+++ b/src/test/regress/expected/partition_aggregate.out
@@ -1394,3 +1394,43 @@ SELECT y, sum(x), avg(x), count(*) FROM pagg_tab_para GROUP BY y HAVING avg(x) <
  11 | 16500 | 11.0000000000000000 |  1500
 (4 rows)
 
+-- Test when partition tables has parallel_workers = 0 but not the parent
+ALTER TABLE pagg_tab_para_p1 SET (parallel_workers = 0);
+ALTER TABLE pagg_tab_para_p2 SET (parallel_workers = 0);
+ALTER TABLE pagg_tab_para_p3 SET (parallel_workers = 0);
+ANALYZE pagg_tab_para;
+-- Reset parallelism parameters to get partitionwise aggregation plan.
+RESET min_parallel_table_scan_size;
+RESET parallel_setup_cost;
+EXPLAIN (COSTS OFF)
+SELECT x, sum(y), avg(y), count(*) FROM pagg_tab_para GROUP BY x HAVING avg(y) < 7 ORDER BY 1, 2, 3;
+                                      QUERY PLAN                                      
+--------------------------------------------------------------------------------------
+ Sort
+   Sort Key: pagg_tab_para_p1.x, (sum(pagg_tab_para_p1.y)), (avg(pagg_tab_para_p1.y))
+   ->  Append
+         ->  HashAggregate
+               Group Key: pagg_tab_para_p1.x
+               Filter: (avg(pagg_tab_para_p1.y) < '7'::numeric)
+               ->  Seq Scan on pagg_tab_para_p1
+         ->  HashAggregate
+               Group Key: pagg_tab_para_p2.x
+               Filter: (avg(pagg_tab_para_p2.y) < '7'::numeric)
+               ->  Seq Scan on pagg_tab_para_p2
+         ->  HashAggregate
+               Group Key: pagg_tab_para_p3.x
+               Filter: (avg(pagg_tab_para_p3.y) < '7'::numeric)
+               ->  Seq Scan on pagg_tab_para_p3
+(15 rows)
+
+SELECT x, sum(y), avg(y), count(*) FROM pagg_tab_para GROUP BY x HAVING avg(y) < 7 ORDER BY 1, 2, 3;
+ x  | sum  |        avg         | count 
+----+------+--------------------+-------
+  0 | 5000 | 5.0000000000000000 |  1000
+  1 | 6000 | 6.0000000000000000 |  1000
+ 10 | 5000 | 5.0000000000000000 |  1000
+ 11 | 6000 | 6.0000000000000000 |  1000
+ 20 | 5000 | 5.0000000000000000 |  1000
+ 21 | 6000 | 6.0000000000000000 |  1000
+(6 rows)
+
diff --git a/src/test/regress/sql/partition_aggregate.sql b/src/test/regress/sql/partition_aggregate.sql
index c60d7d2..a1aacf5 100644
--- a/src/test/regress/sql/partition_aggregate.sql
+++ b/src/test/regress/sql/partition_aggregate.sql
@@ -294,3 +294,17 @@ SELECT x, sum(y), avg(y), count(*) FROM pagg_tab_para GROUP BY x HAVING avg(y) <
 EXPLAIN (COSTS OFF)
 SELECT y, sum(x), avg(x), count(*) FROM pagg_tab_para GROUP BY y HAVING avg(x) < 12 ORDER BY 1, 2, 3;
 SELECT y, sum(x), avg(x), count(*) FROM pagg_tab_para GROUP BY y HAVING avg(x) < 12 ORDER BY 1, 2, 3;
+
+-- Test when partition tables has parallel_workers = 0 but not the parent
+ALTER TABLE pagg_tab_para_p1 SET (parallel_workers = 0);
+ALTER TABLE pagg_tab_para_p2 SET (parallel_workers = 0);
+ALTER TABLE pagg_tab_para_p3 SET (parallel_workers = 0);
+ANALYZE pagg_tab_para;
+
+-- Reset parallelism parameters to get partitionwise aggregation plan.
+RESET min_parallel_table_scan_size;
+RESET parallel_setup_cost;
+
+EXPLAIN (COSTS OFF)
+SELECT x, sum(y), avg(y), count(*) FROM pagg_tab_para GROUP BY x HAVING avg(y) < 7 ORDER BY 1, 2, 3;
+SELECT x, sum(y), avg(y), count(*) FROM pagg_tab_para GROUP BY x HAVING avg(y) < 7 ORDER BY 1, 2, 3;
-- 
1.8.3.1

Reply via email to