diff options
Diffstat (limited to 'src/backend/optimizer/util/clauses.c')
-rw-r--r-- | src/backend/optimizer/util/clauses.c | 124 |
1 files changed, 122 insertions, 2 deletions
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 3c74831f4da..ee45f32abbb 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.271 2008/12/18 18:20:34 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.272 2008/12/28 18:53:57 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -72,7 +72,9 @@ typedef struct } substitute_actual_srf_parameters_context; static bool contain_agg_clause_walker(Node *node, void *context); +static bool pull_agg_clause_walker(Node *node, List **context); static bool count_agg_clauses_walker(Node *node, AggClauseCounts *counts); +static bool find_window_functions_walker(Node *node, WindowFuncLists *lists); static bool expression_returns_set_rows_walker(Node *node, double *count); static bool contain_subplans_walker(Node *node, void *context); static bool contain_mutable_functions_walker(Node *node, void *context); @@ -389,6 +391,41 @@ contain_agg_clause_walker(Node *node, void *context) } /* + * pull_agg_clause + * Recursively search for Aggref nodes within a clause. + * + * Returns a List of all Aggrefs found. + * + * This does not descend into subqueries, and so should be used only after + * reduction of sublinks to subplans, or in contexts where it's known there + * are no subqueries. There mustn't be outer-aggregate references either. + */ +List * +pull_agg_clause(Node *clause) +{ + List *result = NIL; + + (void) pull_agg_clause_walker(clause, &result); + return result; +} + +static bool +pull_agg_clause_walker(Node *node, List **context) +{ + if (node == NULL) + return false; + if (IsA(node, Aggref)) + { + Assert(((Aggref *) node)->agglevelsup == 0); + *context = lappend(*context, node); + return false; /* no need to descend into arguments */ + } + Assert(!IsA(node, SubLink)); + return expression_tree_walker(node, pull_agg_clause_walker, + (void *) context); +} + +/* * count_agg_clauses * Recursively count the Aggref nodes in an expression tree. * @@ -520,6 +557,79 @@ count_agg_clauses_walker(Node *node, AggClauseCounts *counts) /***************************************************************************** + * Window-function clause manipulation + *****************************************************************************/ + +/* + * contain_window_function + * Recursively search for WindowFunc nodes within a clause. + * + * Since window functions don't have level fields, but are hard-wired to + * be associated with the current query level, this is just the same as + * rewriteManip.c's function. + */ +bool +contain_window_function(Node *clause) +{ + return checkExprHasWindowFuncs(clause); +} + +/* + * find_window_functions + * Locate all the WindowFunc nodes in an expression tree, and organize + * them by winref ID number. + * + * Caller must provide an upper bound on the winref IDs expected in the tree. + */ +WindowFuncLists * +find_window_functions(Node *clause, Index maxWinRef) +{ + WindowFuncLists *lists = palloc(sizeof(WindowFuncLists)); + + lists->numWindowFuncs = 0; + lists->maxWinRef = maxWinRef; + lists->windowFuncs = (List **) palloc0((maxWinRef + 1) * sizeof(List *)); + (void) find_window_functions_walker(clause, lists); + return lists; +} + +static bool +find_window_functions_walker(Node *node, WindowFuncLists *lists) +{ + if (node == NULL) + return false; + if (IsA(node, WindowFunc)) + { + WindowFunc *wfunc = (WindowFunc *) node; + + /* winref is unsigned, so one-sided test is OK */ + if (wfunc->winref > lists->maxWinRef) + elog(ERROR, "WindowFunc contains out-of-range winref %u", + wfunc->winref); + lists->windowFuncs[wfunc->winref] = + lappend(lists->windowFuncs[wfunc->winref], wfunc); + lists->numWindowFuncs++; + + /* + * Complain if the window function's arguments contain window functions + */ + 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. + */ + return false; + } + Assert(!IsA(node, SubLink)); + return expression_tree_walker(node, find_window_functions_walker, + (void *) lists); +} + + +/***************************************************************************** * Support for expressions returning sets *****************************************************************************/ @@ -567,6 +677,8 @@ expression_returns_set_rows_walker(Node *node, double *count) /* Avoid recursion for some cases that can't return a set */ if (IsA(node, Aggref)) return false; + if (IsA(node, WindowFunc)) + return false; if (IsA(node, DistinctExpr)) return false; if (IsA(node, ScalarArrayOpExpr)) @@ -897,6 +1009,11 @@ contain_nonstrict_functions_walker(Node *node, void *context) /* an aggregate could return non-null with null input */ return true; } + if (IsA(node, WindowFunc)) + { + /* a window function could return non-null with null input */ + return true; + } if (IsA(node, ArrayRef)) { /* array assignment is nonstrict, but subscripting is strict */ @@ -1589,7 +1706,8 @@ is_strict_saop(ScalarArrayOpExpr *expr, bool falseOK) * not-constant expressions, namely aggregates (Aggrefs). In current usage * this is only applied to WHERE clauses and so a check for Aggrefs would be * a waste of cycles; but be sure to also check contain_agg_clause() if you - * want to know about pseudo-constness in other contexts. + * want to know about pseudo-constness in other contexts. The same goes + * for window functions (WindowFuncs). */ bool is_pseudo_constant_clause(Node *clause) @@ -3472,6 +3590,7 @@ inline_function(Oid funcid, Oid result_type, List *args, querytree->utilityStmt || querytree->intoClause || querytree->hasAggs || + querytree->hasWindowFuncs || querytree->hasSubLinks || querytree->cteList || querytree->rtable || @@ -3479,6 +3598,7 @@ inline_function(Oid funcid, Oid result_type, List *args, querytree->jointree->quals || querytree->groupClause || querytree->havingQual || + querytree->windowClause || querytree->distinctClause || querytree->sortClause || querytree->limitOffset || |