aboutsummaryrefslogtreecommitdiff
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.c124
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 ||