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:
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Reference in New Issue
Block a user