mirror of
https://github.com/postgres/postgres.git
synced 2025-07-03 20:02:46 +03:00
Repair planner bug introduced in 8.2 by ability to rearrange outer joins:
in cases where a sub-SELECT inserts a WHERE clause between two outer joins, that clause may prevent us from re-ordering the two outer joins. The code was considering only the joins' own ON-conditions in determining reordering safety, which is not good enough. Add a "delay_upper_joins" flag to OuterJoinInfo to flag that we have detected such a clause and higher-level outer joins shouldn't be permitted to commute with this one. (This might seem overly coarse, but given the current rules for OJ reordering, it's sufficient AFAICT.) The failure case is actually pretty narrow: it needs a WHERE clause within the RHS of a left join that checks the RHS of a lower left join, but is not strict for that RHS (else we'd have simplified the lower join to a plain join). Even then no failure will be manifest unless the planner chooses to rearrange the join order. Per bug report from Adam Terrey.
This commit is contained in:
@ -15,7 +15,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.353 2006/11/05 22:42:08 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.353.2.1 2007/05/22 23:24:08 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -1318,6 +1318,7 @@ _copyOuterJoinInfo(OuterJoinInfo *from)
|
||||
COPY_BITMAPSET_FIELD(min_righthand);
|
||||
COPY_SCALAR_FIELD(is_full_join);
|
||||
COPY_SCALAR_FIELD(lhs_strict);
|
||||
COPY_SCALAR_FIELD(delay_upper_joins);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.287 2006/11/05 22:42:08 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.287.2.1 2007/05/22 23:24:08 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -614,6 +614,7 @@ _equalOuterJoinInfo(OuterJoinInfo *a, OuterJoinInfo *b)
|
||||
COMPARE_BITMAPSET_FIELD(min_righthand);
|
||||
COMPARE_SCALAR_FIELD(is_full_join);
|
||||
COMPARE_SCALAR_FIELD(lhs_strict);
|
||||
COMPARE_SCALAR_FIELD(delay_upper_joins);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.285.2.1 2007/05/22 01:40:42 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.285.2.2 2007/05/22 23:24:08 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* Every node type that can appear in stored rules' parsetrees *must*
|
||||
@ -1293,6 +1293,7 @@ _outOuterJoinInfo(StringInfo str, OuterJoinInfo *node)
|
||||
WRITE_BITMAPSET_FIELD(min_righthand);
|
||||
WRITE_BOOL_FIELD(is_full_join);
|
||||
WRITE_BOOL_FIELD(lhs_strict);
|
||||
WRITE_BOOL_FIELD(delay_upper_joins);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.123.2.4 2007/02/16 20:57:26 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.123.2.5 2007/05/22 23:24:08 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -495,6 +495,9 @@ make_outerjoininfo(PlannerInfo *root,
|
||||
errmsg("SELECT FOR UPDATE/SHARE cannot be applied to the nullable side of an outer join")));
|
||||
}
|
||||
|
||||
/* this always starts out false */
|
||||
ojinfo->delay_upper_joins = false;
|
||||
|
||||
/* If it's a full join, no need to be very smart */
|
||||
ojinfo->is_full_join = is_full_join;
|
||||
if (is_full_join)
|
||||
@ -564,10 +567,21 @@ make_outerjoininfo(PlannerInfo *root,
|
||||
* lower join's RHS and the lower OJ's join condition is strict, we
|
||||
* can interchange the ordering of the two OJs, so exclude the lower
|
||||
* RHS from our min_righthand.
|
||||
*
|
||||
* Here, we have to consider that "our join condition" includes
|
||||
* any clauses that syntactically appeared above the lower OJ and
|
||||
* below ours; those are equivalent to degenerate clauses in our
|
||||
* OJ and must be treated as such. Such clauses obviously can't
|
||||
* reference our LHS, and they must be non-strict for the lower OJ's
|
||||
* RHS (else reduce_outer_joins would have reduced the lower OJ to
|
||||
* a plain join). Hence the other ways in which we handle clauses
|
||||
* within our join condition are not affected by them. The net
|
||||
* effect is therefore sufficiently represented by the
|
||||
* delay_upper_joins flag saved for us by distribute_qual_to_rels.
|
||||
*/
|
||||
if (bms_overlap(ojinfo->min_righthand, otherinfo->min_righthand) &&
|
||||
!bms_overlap(clause_relids, otherinfo->min_righthand) &&
|
||||
otherinfo->lhs_strict)
|
||||
otherinfo->lhs_strict && !otherinfo->delay_upper_joins)
|
||||
{
|
||||
ojinfo->min_righthand = bms_del_members(ojinfo->min_righthand,
|
||||
otherinfo->min_righthand);
|
||||
@ -829,6 +843,10 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
|
||||
/* we'll need another iteration */
|
||||
found_some = true;
|
||||
}
|
||||
/* set delay_upper_joins if needed */
|
||||
if (!ojinfo->is_full_join &&
|
||||
bms_overlap(relids, ojinfo->min_lefthand))
|
||||
ojinfo->delay_upper_joins = true;
|
||||
}
|
||||
}
|
||||
} while (found_some);
|
||||
|
Reference in New Issue
Block a user