mirror of
https://github.com/postgres/postgres.git
synced 2025-07-28 23:42:10 +03:00
Fix a couple of planner bugs introduced by the new ability to discard
ORDER BY <constant> as redundant. One is that this means query_planner() has to canonicalize pathkeys even when the query jointree is empty; the canonicalization was always a no-op in such cases before, but no more. Also, we have to guard against thinking that a set-returning function is "constant" for this purpose. Add a couple of regression tests for these evidently under-tested cases. Per report from Greg Stark and subsequent experimentation.
This commit is contained in:
@ -10,7 +10,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/optimizer/path/equivclass.c,v 1.2 2007/01/22 20:00:39 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/optimizer/path/equivclass.c,v 1.3 2007/07/07 20:46:45 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -328,8 +328,8 @@ add_eq_member(EquivalenceClass *ec, Expr *expr, Relids relids,
|
|||||||
/*
|
/*
|
||||||
* No Vars, assume it's a pseudoconstant. This is correct for
|
* No Vars, assume it's a pseudoconstant. This is correct for
|
||||||
* entries generated from process_equivalence(), because a WHERE
|
* entries generated from process_equivalence(), because a WHERE
|
||||||
* clause can't contain aggregates and non-volatility was checked
|
* clause can't contain aggregates or SRFs, and non-volatility was
|
||||||
* before process_equivalence() ever got called. But
|
* checked before process_equivalence() ever got called. But
|
||||||
* get_eclass_for_sort_expr() has to work harder. We put the tests
|
* get_eclass_for_sort_expr() has to work harder. We put the tests
|
||||||
* there not here to save cycles in the equivalence case.
|
* there not here to save cycles in the equivalence case.
|
||||||
*/
|
*/
|
||||||
@ -428,13 +428,15 @@ get_eclass_for_sort_expr(PlannerInfo *root,
|
|||||||
false, expr_datatype);
|
false, expr_datatype);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* add_eq_member doesn't check for volatile functions or aggregates,
|
* add_eq_member doesn't check for volatile functions, set-returning
|
||||||
* but such could appear in sort expressions, so we have to check
|
* functions, or aggregates, but such could appear in sort expressions;
|
||||||
* whether its const-marking was correct.
|
* so we have to check whether its const-marking was correct.
|
||||||
*/
|
*/
|
||||||
if (newec->ec_has_const)
|
if (newec->ec_has_const)
|
||||||
{
|
{
|
||||||
if (newec->ec_has_volatile || contain_agg_clause((Node *) expr))
|
if (newec->ec_has_volatile ||
|
||||||
|
expression_returns_set((Node *) expr) ||
|
||||||
|
contain_agg_clause((Node *) expr))
|
||||||
{
|
{
|
||||||
newec->ec_has_const = false;
|
newec->ec_has_const = false;
|
||||||
newem->em_is_const = false;
|
newem->em_is_const = false;
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planmain.c,v 1.101 2007/05/04 01:13:44 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planmain.c,v 1.102 2007/07/07 20:46:45 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -106,9 +106,21 @@ query_planner(PlannerInfo *root, List *tlist,
|
|||||||
*/
|
*/
|
||||||
if (parse->jointree->fromlist == NIL)
|
if (parse->jointree->fromlist == NIL)
|
||||||
{
|
{
|
||||||
|
/* We need a trivial path result */
|
||||||
*cheapest_path = (Path *)
|
*cheapest_path = (Path *)
|
||||||
create_result_path((List *) parse->jointree->quals);
|
create_result_path((List *) parse->jointree->quals);
|
||||||
*sorted_path = NULL;
|
*sorted_path = NULL;
|
||||||
|
/*
|
||||||
|
* We still are required to canonicalize any pathkeys, in case
|
||||||
|
* it's something like "SELECT 2+2 ORDER BY 1".
|
||||||
|
*/
|
||||||
|
root->canon_pathkeys = NIL;
|
||||||
|
root->query_pathkeys = canonicalize_pathkeys(root,
|
||||||
|
root->query_pathkeys);
|
||||||
|
root->group_pathkeys = canonicalize_pathkeys(root,
|
||||||
|
root->group_pathkeys);
|
||||||
|
root->sort_pathkeys = canonicalize_pathkeys(root,
|
||||||
|
root->sort_pathkeys);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -736,3 +736,35 @@ SELECT * FROM foo ORDER BY f1 DESC NULLS LAST;
|
|||||||
|
|
||||||
(7 rows)
|
(7 rows)
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Test some corner cases that have been known to confuse the planner
|
||||||
|
--
|
||||||
|
-- ORDER BY on a constant doesn't really need any sorting
|
||||||
|
SELECT 1 AS x ORDER BY x;
|
||||||
|
x
|
||||||
|
---
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- But ORDER BY on a set-valued expression does
|
||||||
|
create function sillysrf(int) returns setof int as
|
||||||
|
'values (1),(10),(2),($1)' language sql immutable;
|
||||||
|
select sillysrf(42);
|
||||||
|
sillysrf
|
||||||
|
----------
|
||||||
|
1
|
||||||
|
10
|
||||||
|
2
|
||||||
|
42
|
||||||
|
(4 rows)
|
||||||
|
|
||||||
|
select sillysrf(-1) order by 1;
|
||||||
|
sillysrf
|
||||||
|
----------
|
||||||
|
-1
|
||||||
|
1
|
||||||
|
2
|
||||||
|
10
|
||||||
|
(4 rows)
|
||||||
|
|
||||||
|
drop function sillysrf(int);
|
||||||
|
@ -186,3 +186,19 @@ SELECT * FROM foo ORDER BY f1;
|
|||||||
SELECT * FROM foo ORDER BY f1 NULLS FIRST;
|
SELECT * FROM foo ORDER BY f1 NULLS FIRST;
|
||||||
SELECT * FROM foo ORDER BY f1 DESC;
|
SELECT * FROM foo ORDER BY f1 DESC;
|
||||||
SELECT * FROM foo ORDER BY f1 DESC NULLS LAST;
|
SELECT * FROM foo ORDER BY f1 DESC NULLS LAST;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Test some corner cases that have been known to confuse the planner
|
||||||
|
--
|
||||||
|
|
||||||
|
-- ORDER BY on a constant doesn't really need any sorting
|
||||||
|
SELECT 1 AS x ORDER BY x;
|
||||||
|
|
||||||
|
-- But ORDER BY on a set-valued expression does
|
||||||
|
create function sillysrf(int) returns setof int as
|
||||||
|
'values (1),(10),(2),($1)' language sql immutable;
|
||||||
|
|
||||||
|
select sillysrf(42);
|
||||||
|
select sillysrf(-1) order by 1;
|
||||||
|
|
||||||
|
drop function sillysrf(int);
|
||||||
|
Reference in New Issue
Block a user