mirror of
https://github.com/postgres/postgres.git
synced 2025-05-05 09:19:17 +03:00
Fix a bug in 8.2.x that was exposed while investigating Kevin Grittner's
report of poor planning in 8.3: it's unsafe to push a constant across an outer join when the outer-join condition is delayed by lower outer joins, unless we recheck the outer-join condition at the upper outer join. 8.2.x doesn't really have the ability to tell whether this is the case or not, but fortunately it doesn't matter --- it seems most desirable to keep the join condition whether it's entirely redundant or not. However, it's usually mostly redundant, so force its selectivity to 1.0. It might be a good idea to back-patch this into 8.1 as well, but I'll refrain until/unless there's evidence that 8.1 actually fails on any cases that this would fix.
This commit is contained in:
parent
0a1e67bab3
commit
02b3f326b2
@ -11,7 +11,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/pathkeys.c,v 1.79 2006/10/04 00:29:54 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.79.2.1 2008/01/09 20:50:11 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -423,15 +423,16 @@ sub_generate_join_implications(PlannerInfo *root,
|
|||||||
false);
|
false);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can remove explicit tests of this outer-join qual, too,
|
* We used to think we could remove explicit tests of this
|
||||||
* since we now have tests forcing each of its sides to the same
|
* outer-join qual, too, since we now have tests forcing each of
|
||||||
* value.
|
* its sides to the same value. However, that fails in some
|
||||||
|
* corner cases where lower outer joins could cause one of the
|
||||||
|
* variables to go to NULL. (BUG in 8.2 through 8.2.6.)
|
||||||
|
* So now we just leave it in place, but mark it with selectivity
|
||||||
|
* 1.0 so that we don't underestimate the join size output ---
|
||||||
|
* it's mostly redundant with the constant constraints.
|
||||||
*/
|
*/
|
||||||
process_implied_equality(root,
|
rinfo->this_selec = 1.0;
|
||||||
leftop, rightop,
|
|
||||||
rinfo->left_sortop, rinfo->right_sortop,
|
|
||||||
rinfo->left_relids, rinfo->right_relids,
|
|
||||||
true);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* And recurse to see if we can deduce anything from INNERVAR =
|
* And recurse to see if we can deduce anything from INNERVAR =
|
||||||
@ -465,15 +466,16 @@ sub_generate_join_implications(PlannerInfo *root,
|
|||||||
false);
|
false);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can remove explicit tests of this outer-join qual, too,
|
* We used to think we could remove explicit tests of this
|
||||||
* since we now have tests forcing each of its sides to the same
|
* outer-join qual, too, since we now have tests forcing each of
|
||||||
* value.
|
* its sides to the same value. However, that fails in some
|
||||||
|
* corner cases where lower outer joins could cause one of the
|
||||||
|
* variables to go to NULL. (BUG in 8.2 through 8.2.6.)
|
||||||
|
* So now we just leave it in place, but mark it with selectivity
|
||||||
|
* 1.0 so that we don't underestimate the join size output ---
|
||||||
|
* it's mostly redundant with the constant constraints.
|
||||||
*/
|
*/
|
||||||
process_implied_equality(root,
|
rinfo->this_selec = 1.0;
|
||||||
leftop, rightop,
|
|
||||||
rinfo->left_sortop, rinfo->right_sortop,
|
|
||||||
rinfo->left_relids, rinfo->right_relids,
|
|
||||||
true);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* And recurse to see if we can deduce anything from INNERVAR =
|
* And recurse to see if we can deduce anything from INNERVAR =
|
||||||
@ -542,25 +544,22 @@ sub_generate_join_implications(PlannerInfo *root,
|
|||||||
rinfo->right_sortop,
|
rinfo->right_sortop,
|
||||||
rinfo->right_relids,
|
rinfo->right_relids,
|
||||||
false);
|
false);
|
||||||
/* ... and remove COALESCE() = CONSTANT */
|
|
||||||
process_implied_const_eq(root, equi_key_set, relids,
|
|
||||||
item1,
|
|
||||||
sortop1,
|
|
||||||
item1_relids,
|
|
||||||
true);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can remove explicit tests of this outer-join qual, too,
|
* We used to think we could remove explicit tests of this
|
||||||
* since we now have tests forcing each of its sides to the
|
* outer-join qual, too, since we now have tests forcing each
|
||||||
* same value.
|
* of its sides to the same value. However, that fails in
|
||||||
|
* some corner cases where lower outer joins could cause one
|
||||||
|
* of the variables to go to NULL. (BUG in 8.2 through
|
||||||
|
* 8.2.6.) So now we just leave it in place, but mark it with
|
||||||
|
* selectivity 1.0 so that we don't underestimate the join
|
||||||
|
* size output --- it's mostly redundant with the constant
|
||||||
|
* constraints.
|
||||||
|
*
|
||||||
|
* Ideally we'd do that for the COALESCE() = CONSTANT rinfo,
|
||||||
|
* too, but we don't have easy access to that here.
|
||||||
*/
|
*/
|
||||||
process_implied_equality(root,
|
rinfo->this_selec = 1.0;
|
||||||
leftop, rightop,
|
|
||||||
rinfo->left_sortop,
|
|
||||||
rinfo->right_sortop,
|
|
||||||
rinfo->left_relids,
|
|
||||||
rinfo->right_relids,
|
|
||||||
true);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* And recurse to see if we can deduce anything from LEFTVAR =
|
* And recurse to see if we can deduce anything from LEFTVAR =
|
||||||
|
@ -2290,3 +2290,34 @@ from yy
|
|||||||
301 | | | | 1
|
301 | | | | 1
|
||||||
(3 rows)
|
(3 rows)
|
||||||
|
|
||||||
|
--
|
||||||
|
-- regression test for improper pushing of constants across outer-join clauses
|
||||||
|
-- (as seen in early 8.2.x releases)
|
||||||
|
--
|
||||||
|
create temp table zt1 (f1 int primary key);
|
||||||
|
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "zt1_pkey" for table "zt1"
|
||||||
|
create temp table zt2 (f2 int primary key);
|
||||||
|
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "zt2_pkey" for table "zt2"
|
||||||
|
create temp table zt3 (f3 int primary key);
|
||||||
|
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "zt3_pkey" for table "zt3"
|
||||||
|
insert into zt1 values(53);
|
||||||
|
insert into zt2 values(53);
|
||||||
|
select * from
|
||||||
|
zt2 left join zt3 on (f2 = f3)
|
||||||
|
left join zt1 on (f3 = f1)
|
||||||
|
where f2 = 53;
|
||||||
|
f2 | f3 | f1
|
||||||
|
----+----+----
|
||||||
|
53 | |
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
create temp view zv1 as select *,'dummy'::text AS junk from zt1;
|
||||||
|
select * from
|
||||||
|
zt2 left join zt3 on (f2 = f3)
|
||||||
|
left join zv1 on (f3 = f1)
|
||||||
|
where f2 = 53;
|
||||||
|
f2 | f3 | f1 | junk
|
||||||
|
----+----+----+------
|
||||||
|
53 | | |
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
@ -2290,3 +2290,34 @@ from yy
|
|||||||
301 | | | | 1
|
301 | | | | 1
|
||||||
(3 rows)
|
(3 rows)
|
||||||
|
|
||||||
|
--
|
||||||
|
-- regression test for improper pushing of constants across outer-join clauses
|
||||||
|
-- (as seen in early 8.2.x releases)
|
||||||
|
--
|
||||||
|
create temp table zt1 (f1 int primary key);
|
||||||
|
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "zt1_pkey" for table "zt1"
|
||||||
|
create temp table zt2 (f2 int primary key);
|
||||||
|
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "zt2_pkey" for table "zt2"
|
||||||
|
create temp table zt3 (f3 int primary key);
|
||||||
|
NOTICE: CREATE TABLE / PRIMARY KEY will create implicit index "zt3_pkey" for table "zt3"
|
||||||
|
insert into zt1 values(53);
|
||||||
|
insert into zt2 values(53);
|
||||||
|
select * from
|
||||||
|
zt2 left join zt3 on (f2 = f3)
|
||||||
|
left join zt1 on (f3 = f1)
|
||||||
|
where f2 = 53;
|
||||||
|
f2 | f3 | f1
|
||||||
|
----+----+----
|
||||||
|
53 | |
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
create temp view zv1 as select *,'dummy'::text AS junk from zt1;
|
||||||
|
select * from
|
||||||
|
zt2 left join zt3 on (f2 = f3)
|
||||||
|
left join zv1 on (f3 = f1)
|
||||||
|
where f2 = 53;
|
||||||
|
f2 | f3 | f1 | junk
|
||||||
|
----+----+----+------
|
||||||
|
53 | | |
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
@ -462,3 +462,26 @@ from yy
|
|||||||
left join (SELECT * FROM yy where pkyy = 101) as yya ON yy.pkyy = yya.pkyy
|
left join (SELECT * FROM yy where pkyy = 101) as yya ON yy.pkyy = yya.pkyy
|
||||||
left join xx xxa on yya.pkxx = xxa.pkxx
|
left join xx xxa on yya.pkxx = xxa.pkxx
|
||||||
left join xx xxb on coalesce (xxa.pkxx, 1) = xxb.pkxx;
|
left join xx xxb on coalesce (xxa.pkxx, 1) = xxb.pkxx;
|
||||||
|
|
||||||
|
--
|
||||||
|
-- regression test for improper pushing of constants across outer-join clauses
|
||||||
|
-- (as seen in early 8.2.x releases)
|
||||||
|
--
|
||||||
|
|
||||||
|
create temp table zt1 (f1 int primary key);
|
||||||
|
create temp table zt2 (f2 int primary key);
|
||||||
|
create temp table zt3 (f3 int primary key);
|
||||||
|
insert into zt1 values(53);
|
||||||
|
insert into zt2 values(53);
|
||||||
|
|
||||||
|
select * from
|
||||||
|
zt2 left join zt3 on (f2 = f3)
|
||||||
|
left join zt1 on (f3 = f1)
|
||||||
|
where f2 = 53;
|
||||||
|
|
||||||
|
create temp view zv1 as select *,'dummy'::text AS junk from zt1;
|
||||||
|
|
||||||
|
select * from
|
||||||
|
zt2 left join zt3 on (f2 = f3)
|
||||||
|
left join zv1 on (f3 = f1)
|
||||||
|
where f2 = 53;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user