1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-18 17:42:25 +03:00

Support window functions a la SQL:2008.

Hitoshi Harada, with some kibitzing from Heikki and Tom.
This commit is contained in:
Tom Lane
2008-12-28 18:54:01 +00:00
parent 38e9348282
commit 95b07bc7f5
92 changed files with 6720 additions and 321 deletions

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.177 2008/11/15 19:43:46 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.178 2008/12/28 18:53:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -929,10 +929,13 @@ standard_join_search(PlannerInfo *root, int levels_needed, List *initial_rels)
* 1. If the subquery has a LIMIT clause, we must not push down any quals,
* since that could change the set of rows returned.
*
* 2. If the subquery contains EXCEPT or EXCEPT ALL set ops we cannot push
* 2. If the subquery contains any window functions, we can't push quals
* into it, because that would change the results.
*
* 3. If the subquery contains EXCEPT or EXCEPT ALL set ops we cannot push
* quals into it, because that would change the results.
*
* 3. For subqueries using UNION/UNION ALL/INTERSECT/INTERSECT ALL, we can
* 4. For subqueries using UNION/UNION ALL/INTERSECT/INTERSECT ALL, we can
* push quals into each component query, but the quals can only reference
* subquery columns that suffer no type coercions in the set operation.
* Otherwise there are possible semantic gotchas. So, we check the
@ -950,6 +953,10 @@ subquery_is_pushdown_safe(Query *subquery, Query *topquery,
if (subquery->limitOffset != NULL || subquery->limitCount != NULL)
return false;
/* Check point 2 */
if (subquery->hasWindowFuncs)
return false;
/* Are we at top level, or looking at a setop component? */
if (subquery == topquery)
{
@ -1092,6 +1099,12 @@ qual_is_pushdown_safe(Query *subquery, Index rti, Node *qual,
if (contain_subplans(qual))
return false;
/*
* It would be unsafe to push down window function calls, but at least
* for the moment we could never see any in a qual anyhow.
*/
Assert(!contain_window_function(qual));
/*
* Examine all Vars used in clause; since it's a restriction clause, all
* such Vars must refer to subselect output columns.

View File

@ -54,7 +54,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.201 2008/11/22 22:47:05 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.202 2008/12/28 18:53:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -1283,6 +1283,40 @@ cost_agg(Path *path, PlannerInfo *root,
path->total_cost = total_cost;
}
/*
* cost_windowagg
* Determines and returns the cost of performing a WindowAgg plan node,
* including the cost of its input.
*
* Input is assumed already properly sorted.
*/
void
cost_windowagg(Path *path, PlannerInfo *root,
int numWindowFuncs, int numPartCols, int numOrderCols,
Cost input_startup_cost, Cost input_total_cost,
double input_tuples)
{
Cost startup_cost;
Cost total_cost;
startup_cost = input_startup_cost;
total_cost = input_total_cost;
/*
* We charge one cpu_operator_cost per window function per tuple (often a
* drastic underestimate, but without a way to gauge how many tuples the
* window function will fetch, it's hard to do better). We also charge
* cpu_operator_cost per grouping column per tuple for grouping
* comparisons, plus cpu_tuple_cost per tuple for general overhead.
*/
total_cost += cpu_operator_cost * input_tuples * numWindowFuncs;
total_cost += cpu_operator_cost * input_tuples * (numPartCols + numOrderCols);
total_cost += cpu_tuple_cost * input_tuples;
path->startup_cost = startup_cost;
path->total_cost = total_cost;
}
/*
* cost_group
* Determines and returns the cost of performing a Group plan node,
@ -2155,6 +2189,11 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
* Vars and Consts are charged zero, and so are boolean operators (AND,
* OR, NOT). Simplistic, but a lot better than no model at all.
*
* Note that Aggref and WindowFunc nodes are (and should be) treated
* like Vars --- whatever execution cost they have is absorbed into
* plan-node-specific costing. As far as expression evaluation is
* concerned they're just like Vars.
*
* Should we try to account for the possibility of short-circuit
* evaluation of AND/OR? Probably *not*, because that would make the
* results depend on the clause ordering, and we are not in any position

View File

@ -10,7 +10,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/equivclass.c,v 1.14 2008/12/01 21:06:13 tgl Exp $
* $PostgreSQL: pgsql/src/backend/optimizer/path/equivclass.c,v 1.15 2008/12/28 18:53:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -438,14 +438,16 @@ get_eclass_for_sort_expr(PlannerInfo *root,
/*
* add_eq_member doesn't check for volatile functions, set-returning
* functions, or aggregates, but such could appear in sort expressions; so
* we have to check whether its const-marking was correct.
* functions, aggregates, or window functions, but such could appear
* in sort expressions; so we have to check whether its const-marking
* was correct.
*/
if (newec->ec_has_const)
{
if (newec->ec_has_volatile ||
expression_returns_set((Node *) expr) ||
contain_agg_clause((Node *) expr))
contain_agg_clause((Node *) expr) ||
contain_window_function((Node *) expr))
{
newec->ec_has_const = false;
newem->em_is_const = false;