diff --git a/src/backend/optimizer/plan/aqumv.c b/src/backend/optimizer/plan/aqumv.c index 5ab2e87f126..818bebc89e9 100644 --- a/src/backend/optimizer/plan/aqumv.c +++ b/src/backend/optimizer/plan/aqumv.c @@ -121,7 +121,6 @@ answer_query_using_materialized_views(PlannerInfo *root, (parse->rowMarks != NIL) || parse->hasWindowFuncs || parse->hasDistinctOn || - (parse->havingQual != NULL) || parse->hasModifyingCTE || parse->sortClause || (parse->parentStmtType == PARENTSTMTTYPE_REFRESH_MATVIEW) || @@ -344,13 +343,19 @@ answer_query_using_materialized_views(PlannerInfo *root, continue; /* - * We have successfully processed target list, all columns in Aggrefs could be - * computed from mvQuery. - * It's safe to set hasAggs here. + * We have successfully processed target list, and all columns in Aggrefs + * could be computed from mvQuery. */ mvQuery->hasAggs = parse->hasAggs; mvQuery->groupClause = parse->groupClause; mvQuery->groupingSets = parse->groupingSets; + /* + * For HAVING quals have aggregations, we have already processed them in + * Aggrefs during aqumv_process_targetlist(). + * For HAVING quals don't have aggregations, they may be pushed down to + * jointree's quals and would be processed in post_quals later. + */ + mvQuery->havingQual = parse->havingQual; /* * AQUMV @@ -359,7 +364,6 @@ answer_query_using_materialized_views(PlannerInfo *root, * We assume that the selection predicates of view and query expressions * have been converted into conjunctive normal form(CNF) before we process * them. - * AQUMV_MVP: no having quals now. */ preprocess_qual_conditions(subroot, (Node *) mvQuery->jointree); @@ -388,7 +392,11 @@ answer_query_using_materialized_views(PlannerInfo *root, * NB: Update processed_tlist again in case that tlist has been changed. */ preprocess_targetlist(subroot); - preprocess_aggrefs(subroot, (Node *) subroot->processed_tlist); + if(mvQuery->hasAggs) + { + preprocess_aggrefs(subroot, (Node *) subroot->processed_tlist); + preprocess_aggrefs(subroot, mvQuery->havingQual); + } /* * AQUMV diff --git a/src/test/regress/expected/aqumv.out b/src/test/regress/expected/aqumv.out index 0d7782963bd..0cf24f6fb1b 100644 --- a/src/test/regress/expected/aqumv.out +++ b/src/test/regress/expected/aqumv.out @@ -1433,6 +1433,151 @@ select c1, c3, count(c2) from aqumv_t3 where c1 > 90 group by cube(c1, c3); | 95 | 1 (32 rows) +abort; +-- +-- Test HAVING clause +-- +begin; +create table aqumv_t4(c1 int, c2 int, c3 int) distributed by (c1); +insert into aqumv_t4 select i, i+1, i+2 from generate_series(1, 100) i; +insert into aqumv_t4 values (91, NULL, 95); +analyze aqumv_t4; +create incremental materialized view aqumv_mvt4_0 as + select c1 as mc1, c2 as mc2, c3 as mc3 + from aqumv_t4 where c1 > 90; +analyze aqumv_mvt4_0; +-- HAVING clause pushed down to where quals. +set local enable_answer_query_using_materialized_views = off; +explain(costs off, verbose) +select c1, c3 from aqumv_t4 where c1 > 90 group by (c1, c3) having c3 > 97 ; + QUERY PLAN +----------------------------------------------------------------------------------- + Gather Motion 3:1 (slice1; segments: 3) + Output: c1, c3 + -> GroupAggregate + Output: c1, c3 + Group Key: aqumv_t4.c1, aqumv_t4.c3 + -> Sort + Output: c1, c3 + Sort Key: aqumv_t4.c1, aqumv_t4.c3 + -> Seq Scan on public.aqumv_t4 + Output: c1, c3 + Filter: ((aqumv_t4.c1 > 90) AND (aqumv_t4.c3 > 97)) + Settings: enable_answer_query_using_materialized_views = 'off', optimizer = 'off' + Optimizer: Postgres query optimizer +(13 rows) + +select c1, c3 from aqumv_t4 where c1 > 90 group by (c1, c3) having c3 > 97 ; + c1 | c3 +-----+----- + 96 | 98 + 100 | 102 + 97 | 99 + 99 | 101 + 98 | 100 +(5 rows) + +set local enable_answer_query_using_materialized_views = on; +explain(costs off, verbose) +select c1, c3 from aqumv_t4 where c1 > 90 group by (c1, c3) having c3 > 97 ; + QUERY PLAN +---------------------------------------------------------------------------------- + Gather Motion 3:1 (slice1; segments: 3) + Output: mc1, mc3 + -> HashAggregate + Output: mc1, mc3 + Group Key: aqumv_mvt4_0.mc1, aqumv_mvt4_0.mc3 + -> Seq Scan on public.aqumv_mvt4_0 + Output: mc1, mc2, mc3 + Filter: (aqumv_mvt4_0.mc3 > 97) + Settings: enable_answer_query_using_materialized_views = 'on', optimizer = 'off' + Optimizer: Postgres query optimizer +(10 rows) + +select c1, c3 from aqumv_t4 where c1 > 90 group by (c1, c3) having c3 > 97 ; + c1 | c3 +-----+----- + 100 | 102 + 96 | 98 + 98 | 100 + 99 | 101 + 97 | 99 +(5 rows) + +-- quals kept in HAVING clause. +set local enable_answer_query_using_materialized_views = off; +explain(costs off, verbose) +select c1, c3, avg(c2) from aqumv_t4 where c1 > 90 group by (c1, c3) having avg(c2) > 95; + QUERY PLAN +----------------------------------------------------------------------------------- + Gather Motion 3:1 (slice1; segments: 3) + Output: c1, c3, (avg(c2)) + -> HashAggregate + Output: c1, c3, avg(c2) + Group Key: aqumv_t4.c1, aqumv_t4.c3 + Filter: (avg(aqumv_t4.c2) > '95'::numeric) + -> Seq Scan on public.aqumv_t4 + Output: c1, c2, c3 + Filter: (aqumv_t4.c1 > 90) + Settings: enable_answer_query_using_materialized_views = 'off', optimizer = 'off' + Optimizer: Postgres query optimizer +(11 rows) + +select c1, c3, avg(c2) from aqumv_t4 where c1 > 90 group by (c1, c3) having avg(c2) > 95; + c1 | c3 | avg +-----+-----+---------------------- + 99 | 101 | 100.0000000000000000 + 97 | 99 | 98.0000000000000000 + 98 | 100 | 99.0000000000000000 + 95 | 97 | 96.0000000000000000 + 100 | 102 | 101.0000000000000000 + 96 | 98 | 97.0000000000000000 +(6 rows) + +set local enable_answer_query_using_materialized_views = on; +explain(costs off, verbose) +select c1, c3, avg(c2) from aqumv_t4 where c1 > 90 group by (c1, c3) having avg(c2) > 95; + QUERY PLAN +---------------------------------------------------------------------------------- + Gather Motion 3:1 (slice1; segments: 3) + Output: mc1, mc3, (avg(mc2)) + -> HashAggregate + Output: mc1, mc3, avg(mc2) + Group Key: aqumv_mvt4_0.mc1, aqumv_mvt4_0.mc3 + Filter: (avg(aqumv_mvt4_0.mc2) > '95'::numeric) + -> Seq Scan on public.aqumv_mvt4_0 + Output: mc1, mc2, mc3 + Settings: enable_answer_query_using_materialized_views = 'on', optimizer = 'off' + Optimizer: Postgres query optimizer +(10 rows) + +select c1, c3, avg(c2) from aqumv_t4 where c1 > 90 group by (c1, c3) having avg(c2) > 95; + c1 | c3 | avg +-----+-----+---------------------- + 98 | 100 | 99.0000000000000000 + 95 | 97 | 96.0000000000000000 + 99 | 101 | 100.0000000000000000 + 97 | 99 | 98.0000000000000000 + 100 | 102 | 101.0000000000000000 + 96 | 98 | 97.0000000000000000 +(6 rows) + +-- duplicated having quals with where quals. +explain(costs off, verbose) +select c1, c3, avg(c2) from aqumv_t4 where c1 > 90 group by (c1, c3) having c1 > 90; + QUERY PLAN +---------------------------------------------------------------------------------- + Gather Motion 3:1 (slice1; segments: 3) + Output: mc1, mc3, (avg(mc2)) + -> HashAggregate + Output: mc1, mc3, avg(mc2) + Group Key: aqumv_mvt4_0.mc1, aqumv_mvt4_0.mc3 + -> Seq Scan on public.aqumv_mvt4_0 + Output: mc1, mc2, mc3 + Settings: enable_answer_query_using_materialized_views = 'on', optimizer = 'off' + Optimizer: Postgres query optimizer +(9 rows) + abort; reset optimizer; reset enable_answer_query_using_materialized_views; diff --git a/src/test/regress/sql/aqumv.sql b/src/test/regress/sql/aqumv.sql index 36200ab7ce6..c812727096d 100644 --- a/src/test/regress/sql/aqumv.sql +++ b/src/test/regress/sql/aqumv.sql @@ -369,6 +369,46 @@ select c1, c3, count(c2) from aqumv_t3 where c1 > 90 group by cube(c1, c3); select c1, c3, count(c2) from aqumv_t3 where c1 > 90 group by cube(c1, c3); abort; +-- +-- Test HAVING clause +-- +begin; +create table aqumv_t4(c1 int, c2 int, c3 int) distributed by (c1); +insert into aqumv_t4 select i, i+1, i+2 from generate_series(1, 100) i; +insert into aqumv_t4 values (91, NULL, 95); +analyze aqumv_t4; + +create incremental materialized view aqumv_mvt4_0 as + select c1 as mc1, c2 as mc2, c3 as mc3 + from aqumv_t4 where c1 > 90; +analyze aqumv_mvt4_0; + +-- HAVING clause pushed down to where quals. +set local enable_answer_query_using_materialized_views = off; +explain(costs off, verbose) +select c1, c3 from aqumv_t4 where c1 > 90 group by (c1, c3) having c3 > 97 ; +select c1, c3 from aqumv_t4 where c1 > 90 group by (c1, c3) having c3 > 97 ; +set local enable_answer_query_using_materialized_views = on; +explain(costs off, verbose) +select c1, c3 from aqumv_t4 where c1 > 90 group by (c1, c3) having c3 > 97 ; +select c1, c3 from aqumv_t4 where c1 > 90 group by (c1, c3) having c3 > 97 ; + +-- quals kept in HAVING clause. +set local enable_answer_query_using_materialized_views = off; +explain(costs off, verbose) +select c1, c3, avg(c2) from aqumv_t4 where c1 > 90 group by (c1, c3) having avg(c2) > 95; +select c1, c3, avg(c2) from aqumv_t4 where c1 > 90 group by (c1, c3) having avg(c2) > 95; +set local enable_answer_query_using_materialized_views = on; +explain(costs off, verbose) +select c1, c3, avg(c2) from aqumv_t4 where c1 > 90 group by (c1, c3) having avg(c2) > 95; +select c1, c3, avg(c2) from aqumv_t4 where c1 > 90 group by (c1, c3) having avg(c2) > 95; + +-- duplicated having quals with where quals. +explain(costs off, verbose) +select c1, c3, avg(c2) from aqumv_t4 where c1 > 90 group by (c1, c3) having c1 > 90; + +abort; + reset optimizer; reset enable_answer_query_using_materialized_views; drop table aqumv_t1 cascade;