mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-02-05 19:09:58 +08: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
|
||||
*
|
||||
* 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);
|
||||
|
||||
/*
|
||||
* We can remove explicit tests of this outer-join qual, too,
|
||||
* since we now have tests forcing each of its sides to the same
|
||||
* value.
|
||||
* We used to think we could remove explicit tests of this
|
||||
* outer-join qual, too, since we now have tests forcing each 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.
|
||||
*/
|
||||
process_implied_equality(root,
|
||||
leftop, rightop,
|
||||
rinfo->left_sortop, rinfo->right_sortop,
|
||||
rinfo->left_relids, rinfo->right_relids,
|
||||
true);
|
||||
rinfo->this_selec = 1.0;
|
||||
|
||||
/*
|
||||
* And recurse to see if we can deduce anything from INNERVAR =
|
||||
@ -465,15 +466,16 @@ sub_generate_join_implications(PlannerInfo *root,
|
||||
false);
|
||||
|
||||
/*
|
||||
* We can remove explicit tests of this outer-join qual, too,
|
||||
* since we now have tests forcing each of its sides to the same
|
||||
* value.
|
||||
* We used to think we could remove explicit tests of this
|
||||
* outer-join qual, too, since we now have tests forcing each 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.
|
||||
*/
|
||||
process_implied_equality(root,
|
||||
leftop, rightop,
|
||||
rinfo->left_sortop, rinfo->right_sortop,
|
||||
rinfo->left_relids, rinfo->right_relids,
|
||||
true);
|
||||
rinfo->this_selec = 1.0;
|
||||
|
||||
/*
|
||||
* 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_relids,
|
||||
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,
|
||||
* since we now have tests forcing each of its sides to the
|
||||
* same value.
|
||||
* We used to think we could remove explicit tests of this
|
||||
* outer-join qual, too, since we now have tests forcing each
|
||||
* 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,
|
||||
leftop, rightop,
|
||||
rinfo->left_sortop,
|
||||
rinfo->right_sortop,
|
||||
rinfo->left_relids,
|
||||
rinfo->right_relids,
|
||||
true);
|
||||
rinfo->this_selec = 1.0;
|
||||
|
||||
/*
|
||||
* And recurse to see if we can deduce anything from LEFTVAR =
|
||||
|
@ -2290,3 +2290,34 @@ from yy
|
||||
301 | | | | 1
|
||||
(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
|
||||
(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 xx xxa on yya.pkxx = xxa.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…
Reference in New Issue
Block a user