summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util/clauses.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/util/clauses.c')
-rw-r--r--src/backend/optimizer/util/clauses.c106
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;
}