diff options
Diffstat (limited to 'src/backend/optimizer/util/clauses.c')
-rw-r--r-- | src/backend/optimizer/util/clauses.c | 106 |
1 files changed, 46 insertions, 60 deletions
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index a7fdd52c294..eaf85dc9bd4 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -37,6 +37,7 @@ #include "optimizer/prep.h" #include "optimizer/var.h" #include "parser/analyze.h" +#include "parser/parse_agg.h" #include "parser/parse_coerce.h" #include "parser/parse_func.h" #include "rewrite/rewriteManip.h" @@ -463,9 +464,8 @@ count_agg_clauses_walker(Node *node, count_agg_clauses_context *context) Oid aggtranstype; int32 aggtransspace; QualCost argcosts; - Oid *inputTypes; + Oid inputTypes[FUNC_MAX_ARGS]; int numArguments; - ListCell *l; Assert(aggref->agglevelsup == 0); @@ -482,7 +482,7 @@ count_agg_clauses_walker(Node *node, count_agg_clauses_context *context) aggtransspace = aggform->aggtransspace; ReleaseSysCache(aggTuple); - /* count it */ + /* count it; note ordered-set aggs always have nonempty aggorder */ costs->numAggs++; if (aggref->aggorder != NIL || aggref->aggdistinct != NIL) costs->numOrderedAggs++; @@ -498,43 +498,40 @@ count_agg_clauses_walker(Node *node, count_agg_clauses_context *context) costs->transCost.per_tuple += argcosts.per_tuple; /* - * Add the filter's cost to per-input-row costs. XXX We should reduce - * input expression costs according to filter selectivity. + * Add any filter's cost to per-input-row costs. + * + * XXX Ideally we should reduce input expression costs according to + * filter selectivity, but it's not clear it's worth the trouble. */ - cost_qual_eval_node(&argcosts, (Node *) aggref->aggfilter, - context->root); - costs->transCost.startup += argcosts.startup; - costs->transCost.per_tuple += argcosts.per_tuple; - - /* extract argument types (ignoring any ORDER BY expressions) */ - inputTypes = (Oid *) palloc(sizeof(Oid) * list_length(aggref->args)); - numArguments = 0; - foreach(l, aggref->args) + if (aggref->aggfilter) { - TargetEntry *tle = (TargetEntry *) lfirst(l); - - if (!tle->resjunk) - inputTypes[numArguments++] = exprType((Node *) tle->expr); + cost_qual_eval_node(&argcosts, (Node *) aggref->aggfilter, + context->root); + costs->transCost.startup += argcosts.startup; + costs->transCost.per_tuple += argcosts.per_tuple; } - /* resolve actual type of transition state, if polymorphic */ - if (IsPolymorphicType(aggtranstype)) + /* + * If there are direct arguments, treat their evaluation cost like the + * cost of the finalfn. + */ + if (aggref->aggdirectargs) { - /* have to fetch the agg's declared input types... */ - Oid *declaredArgTypes; - int agg_nargs; - - (void) get_func_signature(aggref->aggfnoid, - &declaredArgTypes, &agg_nargs); - Assert(agg_nargs == numArguments); - aggtranstype = enforce_generic_type_consistency(inputTypes, - declaredArgTypes, - agg_nargs, - aggtranstype, - false); - pfree(declaredArgTypes); + cost_qual_eval_node(&argcosts, (Node *) aggref->aggdirectargs, + context->root); + costs->transCost.startup += argcosts.startup; + costs->finalCost += argcosts.per_tuple; } + /* extract argument types (ignoring any ORDER BY expressions) */ + numArguments = get_aggregate_argtypes(aggref, inputTypes); + + /* resolve actual type of transition state, if polymorphic */ + aggtranstype = resolve_aggregate_transtype(aggref->aggfnoid, + aggtranstype, + inputTypes, + numArguments); + /* * If the transition type is pass-by-value then it doesn't add * anything to the required size of the hashtable. If it is @@ -551,14 +548,16 @@ count_agg_clauses_walker(Node *node, count_agg_clauses_context *context) else { /* - * If transition state is of same type as first input, assume - * it's the same typmod (same width) as well. This works for - * cases like MAX/MIN and is probably somewhat reasonable - * otherwise. + * If transition state is of same type as first aggregated + * input, assume it's the same typmod (same width) as well. + * This works for cases like MAX/MIN and is probably somewhat + * reasonable otherwise. */ + int numdirectargs = list_length(aggref->aggdirectargs); int32 aggtranstypmod; - if (numArguments > 0 && aggtranstype == inputTypes[0]) + if (numArguments > numdirectargs && + aggtranstype == inputTypes[numdirectargs]) aggtranstypmod = exprTypmod((Node *) linitial(aggref->args)); else aggtranstypmod = -1; @@ -587,17 +586,11 @@ count_agg_clauses_walker(Node *node, count_agg_clauses_context *context) } /* - * Complain if the aggregate's arguments contain any aggregates; - * nested agg functions are semantically nonsensical. Aggregates in - * the FILTER clause are detected in transformAggregateCall(). - */ - if (contain_agg_clause((Node *) aggref->args)) - ereport(ERROR, - (errcode(ERRCODE_GROUPING_ERROR), - errmsg("aggregate function calls cannot be nested"))); - - /* - * Having checked that, we need not recurse into the argument. + * We assume that the parser checked that there are no aggregates (of + * this level anyway) in the aggregated arguments, direct arguments, + * or filter clause. Hence, we need not recurse into any of them. (If + * either the parser or the planner screws up on this point, the + * executor will still catch it; see ExecInitExpr.) */ return false; } @@ -662,17 +655,10 @@ find_window_functions_walker(Node *node, WindowFuncLists *lists) lists->numWindowFuncs++; /* - * Complain if the window function's arguments contain window - * functions. Window functions in the FILTER clause are detected in - * transformAggregateCall(). - */ - if (contain_window_function((Node *) wfunc->args)) - ereport(ERROR, - (errcode(ERRCODE_WINDOWING_ERROR), - errmsg("window function calls cannot be nested"))); - - /* - * Having checked that, we need not recurse into the argument. + * We assume that the parser checked that there are no window + * functions in the arguments or filter clause. Hence, we need not + * recurse into them. (If either the parser or the planner screws up + * on this point, the executor will still catch it; see ExecInitExpr.) */ return false; } |