diff options
Diffstat (limited to 'src/backend/optimizer/plan/planner.c')
-rw-r--r-- | src/backend/optimizer/plan/planner.c | 70 |
1 files changed, 61 insertions, 9 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 62b2354f004..bd4b652f7a3 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -88,6 +88,7 @@ create_upper_paths_hook_type create_upper_paths_hook = NULL; #define EXPRKIND_ARBITER_ELEM 10 #define EXPRKIND_TABLEFUNC 11 #define EXPRKIND_TABLEFUNC_LATERAL 12 +#define EXPRKIND_GROUPEXPR 13 /* * Data specific to grouping sets @@ -748,6 +749,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root, */ root->hasJoinRTEs = false; root->hasLateralRTEs = false; + root->group_rtindex = 0; hasOuterJoins = false; hasResultRTEs = false; foreach(l, parse->rtable) @@ -781,6 +783,10 @@ subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root, case RTE_RESULT: hasResultRTEs = true; break; + case RTE_GROUP: + Assert(parse->hasGroupRTE); + root->group_rtindex = list_cell_number(parse->rtable, l) + 1; + break; default: /* No work here for other RTE types */ break; @@ -836,10 +842,6 @@ subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root, preprocess_expression(root, (Node *) parse->targetList, EXPRKIND_TARGET); - /* Constant-folding might have removed all set-returning functions */ - if (parse->hasTargetSRFs) - parse->hasTargetSRFs = expression_returns_set((Node *) parse->targetList); - newWithCheckOptions = NIL; foreach(l, parse->withCheckOptions) { @@ -969,6 +971,13 @@ subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root, rte->values_lists = (List *) preprocess_expression(root, (Node *) rte->values_lists, kind); } + else if (rte->rtekind == RTE_GROUP) + { + /* Preprocess the groupexprs list fully */ + rte->groupexprs = (List *) + preprocess_expression(root, (Node *) rte->groupexprs, + EXPRKIND_GROUPEXPR); + } /* * Process each element of the securityQuals list as if it were a @@ -1006,6 +1015,27 @@ subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root, } /* + * Replace any Vars in the subquery's targetlist and havingQual that + * reference GROUP outputs with the underlying grouping expressions. + * + * Note that we need to perform this replacement after we've preprocessed + * the grouping expressions. This is to ensure that there is only one + * instance of SubPlan for each SubLink contained within the grouping + * expressions. + */ + if (parse->hasGroupRTE) + { + parse->targetList = (List *) + flatten_group_exprs(root, root->parse, (Node *) parse->targetList); + parse->havingQual = + flatten_group_exprs(root, root->parse, parse->havingQual); + } + + /* Constant-folding might have removed all set-returning functions */ + if (parse->hasTargetSRFs) + parse->hasTargetSRFs = expression_returns_set((Node *) parse->targetList); + + /* * In some cases we may want to transfer a HAVING clause into WHERE. We * cannot do so if the HAVING clause contains aggregates (obviously) or * volatile functions (since a HAVING clause is supposed to be executed @@ -1032,6 +1062,16 @@ subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root, * don't emit a bogus aggregated row. (This could be done better, but it * seems not worth optimizing.) * + * Note that a HAVING clause may contain expressions that are not fully + * preprocessed. This can happen if these expressions are part of + * grouping items. In such cases, they are replaced with GROUP Vars in + * the parser and then replaced back after we've done with expression + * preprocessing on havingQual. This is not an issue if the clause + * remains in HAVING, because these expressions will be matched to lower + * target items in setrefs.c. However, if the clause is moved or copied + * into WHERE, we need to ensure that these expressions are fully + * preprocessed. + * * Note that both havingQual and parse->jointree->quals are in * implicitly-ANDed-list form at this point, even though they are declared * as Node *. @@ -1051,16 +1091,28 @@ subquery_planner(PlannerGlobal *glob, Query *parse, PlannerInfo *parent_root, } else if (parse->groupClause && !parse->groupingSets) { - /* move it to WHERE */ + Node *whereclause; + + /* Preprocess the HAVING clause fully */ + whereclause = preprocess_expression(root, havingclause, + EXPRKIND_QUAL); + /* ... and move it to WHERE */ parse->jointree->quals = (Node *) - lappend((List *) parse->jointree->quals, havingclause); + list_concat((List *) parse->jointree->quals, + (List *) whereclause); } else { - /* put a copy in WHERE, keep it in HAVING */ + Node *whereclause; + + /* Preprocess the HAVING clause fully */ + whereclause = preprocess_expression(root, copyObject(havingclause), + EXPRKIND_QUAL); + /* ... and put a copy in WHERE */ parse->jointree->quals = (Node *) - lappend((List *) parse->jointree->quals, - copyObject(havingclause)); + list_concat((List *) parse->jointree->quals, + (List *) whereclause); + /* ... and also keep it in HAVING */ newHaving = lappend(newHaving, havingclause); } } |