Commit cc5e80b8 authored by Tom Lane's avatar Tom Lane

Teach planner about some cases where a restriction clause can be

propagated inside an outer join.  In particular, given
LEFT JOIN ON (A = B) WHERE A = constant, we cannot conclude that
B = constant at the top level (B might be null instead), but we
can nonetheless put a restriction B = constant into the quals for
B's relation, since no inner-side rows not meeting that condition
can contribute to the final result.  Similarly, given
FULL JOIN USING (J) WHERE J = constant, we can't directly conclude
that either input J variable = constant, but it's OK to push such
quals into each input rel.  Per recent gripe from Kim Bisgaard.
Along the way, remove 'valid_everywhere' flag from RestrictInfo,
as on closer analysis it was not being used for anything, and was
defined backwards anyway.
parent ea1e2b94
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,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/nodes/copyfuncs.c,v 1.310 2005/06/28 05:08:56 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.311 2005/07/02 23:00:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1249,7 +1249,6 @@ _copyRestrictInfo(RestrictInfo *from) ...@@ -1249,7 +1249,6 @@ _copyRestrictInfo(RestrictInfo *from)
COPY_NODE_FIELD(clause); COPY_NODE_FIELD(clause);
COPY_SCALAR_FIELD(is_pushed_down); COPY_SCALAR_FIELD(is_pushed_down);
COPY_SCALAR_FIELD(valid_everywhere);
COPY_SCALAR_FIELD(can_join); COPY_SCALAR_FIELD(can_join);
COPY_BITMAPSET_FIELD(clause_relids); COPY_BITMAPSET_FIELD(clause_relids);
COPY_BITMAPSET_FIELD(required_relids); COPY_BITMAPSET_FIELD(required_relids);
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,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/nodes/equalfuncs.c,v 1.247 2005/06/28 05:08:57 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.248 2005/07/02 23:00:39 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -603,7 +603,6 @@ _equalRestrictInfo(RestrictInfo *a, RestrictInfo *b) ...@@ -603,7 +603,6 @@ _equalRestrictInfo(RestrictInfo *a, RestrictInfo *b)
{ {
COMPARE_NODE_FIELD(clause); COMPARE_NODE_FIELD(clause);
COMPARE_SCALAR_FIELD(is_pushed_down); COMPARE_SCALAR_FIELD(is_pushed_down);
COMPARE_SCALAR_FIELD(valid_everywhere);
COMPARE_BITMAPSET_FIELD(required_relids); COMPARE_BITMAPSET_FIELD(required_relids);
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.257 2005/06/28 05:08:57 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.258 2005/07/02 23:00:39 tgl Exp $
* *
* NOTES * NOTES
* Every node type that can appear in stored rules' parsetrees *must* * Every node type that can appear in stored rules' parsetrees *must*
...@@ -1164,9 +1164,13 @@ _outPlannerInfo(StringInfo str, PlannerInfo *node) ...@@ -1164,9 +1164,13 @@ _outPlannerInfo(StringInfo str, PlannerInfo *node)
WRITE_NODE_FIELD(parse); WRITE_NODE_FIELD(parse);
WRITE_NODE_FIELD(join_rel_list); WRITE_NODE_FIELD(join_rel_list);
WRITE_NODE_FIELD(equi_key_list); WRITE_NODE_FIELD(equi_key_list);
WRITE_NODE_FIELD(left_join_clauses);
WRITE_NODE_FIELD(right_join_clauses);
WRITE_NODE_FIELD(full_join_clauses);
WRITE_NODE_FIELD(in_info_list); WRITE_NODE_FIELD(in_info_list);
WRITE_NODE_FIELD(query_pathkeys); WRITE_NODE_FIELD(query_pathkeys);
WRITE_BOOL_FIELD(hasJoinRTEs); WRITE_BOOL_FIELD(hasJoinRTEs);
WRITE_BOOL_FIELD(hasOuterJoins);
WRITE_BOOL_FIELD(hasHavingQual); WRITE_BOOL_FIELD(hasHavingQual);
} }
...@@ -1234,7 +1238,6 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node) ...@@ -1234,7 +1238,6 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node)
/* NB: this isn't a complete set of fields */ /* NB: this isn't a complete set of fields */
WRITE_NODE_FIELD(clause); WRITE_NODE_FIELD(clause);
WRITE_BOOL_FIELD(is_pushed_down); WRITE_BOOL_FIELD(is_pushed_down);
WRITE_BOOL_FIELD(valid_everywhere);
WRITE_BOOL_FIELD(can_join); WRITE_BOOL_FIELD(can_join);
WRITE_BITMAPSET_FIELD(clause_relids); WRITE_BITMAPSET_FIELD(clause_relids);
WRITE_BITMAPSET_FIELD(required_relids); WRITE_BITMAPSET_FIELD(required_relids);
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.185 2005/06/14 04:04:30 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.186 2005/07/02 23:00:40 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1882,7 +1882,7 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups) ...@@ -1882,7 +1882,7 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
{ {
resultquals = lappend(resultquals, resultquals = lappend(resultquals,
make_restrictinfo(boolqual, make_restrictinfo(boolqual,
true, true, true,
NULL)); NULL));
continue; continue;
} }
...@@ -2132,7 +2132,7 @@ prefix_quals(Node *leftop, Oid opclass, ...@@ -2132,7 +2132,7 @@ prefix_quals(Node *leftop, Oid opclass,
elog(ERROR, "no = operator for opclass %u", opclass); elog(ERROR, "no = operator for opclass %u", opclass);
expr = make_opclause(oproid, BOOLOID, false, expr = make_opclause(oproid, BOOLOID, false,
(Expr *) leftop, (Expr *) prefix_const); (Expr *) leftop, (Expr *) prefix_const);
result = list_make1(make_restrictinfo(expr, true, true, NULL)); result = list_make1(make_restrictinfo(expr, true, NULL));
return result; return result;
} }
...@@ -2147,7 +2147,7 @@ prefix_quals(Node *leftop, Oid opclass, ...@@ -2147,7 +2147,7 @@ prefix_quals(Node *leftop, Oid opclass,
elog(ERROR, "no >= operator for opclass %u", opclass); elog(ERROR, "no >= operator for opclass %u", opclass);
expr = make_opclause(oproid, BOOLOID, false, expr = make_opclause(oproid, BOOLOID, false,
(Expr *) leftop, (Expr *) prefix_const); (Expr *) leftop, (Expr *) prefix_const);
result = list_make1(make_restrictinfo(expr, true, true, NULL)); result = list_make1(make_restrictinfo(expr, true, NULL));
/*------- /*-------
* If we can create a string larger than the prefix, we can say * If we can create a string larger than the prefix, we can say
...@@ -2163,7 +2163,7 @@ prefix_quals(Node *leftop, Oid opclass, ...@@ -2163,7 +2163,7 @@ prefix_quals(Node *leftop, Oid opclass,
elog(ERROR, "no < operator for opclass %u", opclass); elog(ERROR, "no < operator for opclass %u", opclass);
expr = make_opclause(oproid, BOOLOID, false, expr = make_opclause(oproid, BOOLOID, false,
(Expr *) leftop, (Expr *) greaterstr); (Expr *) leftop, (Expr *) greaterstr);
result = lappend(result, make_restrictinfo(expr, true, true, NULL)); result = lappend(result, make_restrictinfo(expr, true, NULL));
} }
return result; return result;
...@@ -2234,7 +2234,7 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop) ...@@ -2234,7 +2234,7 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop)
(Expr *) leftop, (Expr *) leftop,
(Expr *) makeConst(datatype, -1, opr1right, (Expr *) makeConst(datatype, -1, opr1right,
false, false)); false, false));
result = list_make1(make_restrictinfo(expr, true, true, NULL)); result = list_make1(make_restrictinfo(expr, true, NULL));
/* create clause "key <= network_scan_last( rightop )" */ /* create clause "key <= network_scan_last( rightop )" */
...@@ -2249,7 +2249,7 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop) ...@@ -2249,7 +2249,7 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop)
(Expr *) leftop, (Expr *) leftop,
(Expr *) makeConst(datatype, -1, opr2right, (Expr *) makeConst(datatype, -1, opr2right,
false, false)); false, false));
result = lappend(result, make_restrictinfo(expr, true, true, NULL)); result = lappend(result, make_restrictinfo(expr, true, NULL));
return result; return result;
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/path/orindxpath.c,v 1.72 2005/06/09 04:18:59 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/path/orindxpath.c,v 1.73 2005/07/02 23:00:40 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -90,16 +90,13 @@ create_or_index_quals(PlannerInfo *root, RelOptInfo *rel) ...@@ -90,16 +90,13 @@ create_or_index_quals(PlannerInfo *root, RelOptInfo *rel)
ListCell *i; ListCell *i;
/* /*
* Find potentially interesting OR joinclauses. We must ignore any * Find potentially interesting OR joinclauses.
* joinclauses that are not marked valid_everywhere, because they
* cannot be pushed down due to outer-join rules.
*/ */
foreach(i, rel->joininfo) foreach(i, rel->joininfo)
{ {
RestrictInfo *rinfo = (RestrictInfo *) lfirst(i); RestrictInfo *rinfo = (RestrictInfo *) lfirst(i);
if (restriction_is_or_clause(rinfo) && if (restriction_is_or_clause(rinfo))
rinfo->valid_everywhere)
{ {
/* /*
* Use the generate_bitmap_or_paths() machinery to estimate * Use the generate_bitmap_or_paths() machinery to estimate
...@@ -140,8 +137,7 @@ create_or_index_quals(PlannerInfo *root, RelOptInfo *rel) ...@@ -140,8 +137,7 @@ create_or_index_quals(PlannerInfo *root, RelOptInfo *rel)
* Convert the path's indexclauses structure to a RestrictInfo tree, * Convert the path's indexclauses structure to a RestrictInfo tree,
* and add it to the rel's restriction list. * and add it to the rel's restriction list.
*/ */
newrinfos = make_restrictinfo_from_bitmapqual((Path *) bestpath, newrinfos = make_restrictinfo_from_bitmapqual((Path *) bestpath, true);
true, true);
Assert(list_length(newrinfos) == 1); Assert(list_length(newrinfos) == 1);
or_rinfo = (RestrictInfo *) linitial(newrinfos); or_rinfo = (RestrictInfo *) linitial(newrinfos);
Assert(IsA(or_rinfo, RestrictInfo)); Assert(IsA(or_rinfo, RestrictInfo));
......
This diff is collapsed.
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.192 2005/06/10 22:25:36 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.193 2005/07/02 23:00:41 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1176,8 +1176,7 @@ create_nestloop_plan(PlannerInfo *root, ...@@ -1176,8 +1176,7 @@ create_nestloop_plan(PlannerInfo *root,
List *bitmapclauses; List *bitmapclauses;
bitmapclauses = bitmapclauses =
make_restrictinfo_from_bitmapqual(innerpath->bitmapqual, make_restrictinfo_from_bitmapqual(innerpath->bitmapqual, true);
true, true);
joinrestrictclauses = joinrestrictclauses =
select_nonredundant_join_clauses(root, select_nonredundant_join_clauses(root,
joinrestrictclauses, joinrestrictclauses,
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.107 2005/06/09 04:18:59 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.108 2005/07/02 23:00:41 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -374,8 +374,8 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, ...@@ -374,8 +374,8 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
Relids qualscope) Relids qualscope)
{ {
Relids relids; Relids relids;
bool valid_everywhere; bool maybe_equijoin;
bool can_be_equijoin; bool maybe_outer_join;
RestrictInfo *restrictinfo; RestrictInfo *restrictinfo;
RelOptInfo *rel; RelOptInfo *rel;
List *vars; List *vars;
...@@ -409,14 +409,15 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, ...@@ -409,14 +409,15 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
if (isdeduced) if (isdeduced)
{ {
/* /*
* If the qual came from implied-equality deduction, we can * If the qual came from implied-equality deduction, we always
* evaluate the qual at its natural semantic level. It is not * evaluate the qual at its natural semantic level. It is the
* affected by any outer-join rules (else we'd not have decided * responsibility of the deducer not to create any quals that
* the vars were equal). * should be delayed by outer-join rules.
*/ */
Assert(bms_equal(relids, qualscope)); Assert(bms_equal(relids, qualscope));
valid_everywhere = true; /* Needn't feed it back for more deductions */
can_be_equijoin = true; maybe_equijoin = false;
maybe_outer_join = false;
} }
else if (bms_overlap(relids, outerjoin_nonnullable)) else if (bms_overlap(relids, outerjoin_nonnullable))
{ {
...@@ -434,8 +435,14 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, ...@@ -434,8 +435,14 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
* result, so we treat it the same as an ordinary inner-join qual. * result, so we treat it the same as an ordinary inner-join qual.
*/ */
relids = qualscope; relids = qualscope;
valid_everywhere = false; /*
can_be_equijoin = false; * We can't use such a clause to deduce equijoin (the left and
* right sides might be unequal above the join because one of
* them has gone to NULL) ... but we might be able to use it
* for more limited purposes.
*/
maybe_equijoin = false;
maybe_outer_join = true;
} }
else else
{ {
...@@ -449,34 +456,25 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, ...@@ -449,34 +456,25 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
* time we are called, the outerjoinset of each baserel will show * time we are called, the outerjoinset of each baserel will show
* exactly those outer joins that are below the qual in the join * exactly those outer joins that are below the qual in the join
* tree. * tree.
*
* We also need to determine whether the qual is "valid everywhere",
* which is true if the qual mentions no variables that are
* involved in lower-level outer joins (this may be an overly
* strong test).
*/ */
Relids addrelids = NULL; Relids addrelids = NULL;
Relids tmprelids; Relids tmprelids;
int relno; int relno;
valid_everywhere = true;
tmprelids = bms_copy(relids); tmprelids = bms_copy(relids);
while ((relno = bms_first_member(tmprelids)) >= 0) while ((relno = bms_first_member(tmprelids)) >= 0)
{ {
RelOptInfo *rel = find_base_rel(root, relno); RelOptInfo *rel = find_base_rel(root, relno);
if (rel->outerjoinset != NULL) if (rel->outerjoinset != NULL)
{
addrelids = bms_add_members(addrelids, rel->outerjoinset); addrelids = bms_add_members(addrelids, rel->outerjoinset);
valid_everywhere = false;
}
} }
bms_free(tmprelids); bms_free(tmprelids);
if (bms_is_subset(addrelids, relids)) if (bms_is_subset(addrelids, relids))
{ {
/* Qual is not affected by any outer-join restriction */ /* Qual is not affected by any outer-join restriction */
can_be_equijoin = true; maybe_equijoin = true;
} }
else else
{ {
...@@ -488,9 +486,10 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, ...@@ -488,9 +486,10 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
* Because application of the qual will be delayed by outer * Because application of the qual will be delayed by outer
* join, we mustn't assume its vars are equal everywhere. * join, we mustn't assume its vars are equal everywhere.
*/ */
can_be_equijoin = false; maybe_equijoin = false;
} }
bms_free(addrelids); bms_free(addrelids);
maybe_outer_join = false;
} }
/* /*
...@@ -508,7 +507,6 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, ...@@ -508,7 +507,6 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
*/ */
restrictinfo = make_restrictinfo((Expr *) clause, restrictinfo = make_restrictinfo((Expr *) clause,
is_pushed_down, is_pushed_down,
valid_everywhere,
relids); relids);
/* /*
...@@ -533,8 +531,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, ...@@ -533,8 +531,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
* allows us to consider z and q equal after their rels are * allows us to consider z and q equal after their rels are
* joined. * joined.
*/ */
if (can_be_equijoin) check_mergejoinable(restrictinfo);
check_mergejoinable(restrictinfo);
/* /*
* If the clause was deduced from implied equality, check to * If the clause was deduced from implied equality, check to
...@@ -601,18 +598,60 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause, ...@@ -601,18 +598,60 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
} }
/* /*
* If the clause has a mergejoinable operator, and is not an * If the clause has a mergejoinable operator, we may be able to
* outer-join qualification nor bubbled up due to an outer join, then * deduce more things from it under the principle of transitivity.
* the two sides represent equivalent PathKeyItems for path keys: any *
* path that is sorted by one side will also be sorted by the other * If it is not an outer-join qualification nor bubbled up due to an outer
* (as soon as the two rels are joined, that is). Record the key * join, then the two sides represent equivalent PathKeyItems for path
* equivalence for future use. (We can skip this for a deduced * keys: any path that is sorted by one side will also be sorted by the
* clause, since the keys are already known equivalent in that case.) * other (as soon as the two rels are joined, that is). Pass such clauses
* to add_equijoined_keys.
*
* If it is a left or right outer-join qualification that relates the two
* sides of the outer join (no funny business like leftvar1 = leftvar2 +
* rightvar), we add it to root->left_join_clauses or
* root->right_join_clauses according to which side the nonnullable
* variable appears on.
*
* If it is a full outer-join qualification, we add it to
* root->full_join_clauses. (Ideally we'd discard cases that aren't
* leftvar = rightvar, as we do for left/right joins, but this routine
* doesn't have the info needed to do that; and the current usage of the
* full_join_clauses list doesn't require that, so it's not currently
* worth complicating this routine's API to make it possible.)
*/ */
if (can_be_equijoin && if (restrictinfo->mergejoinoperator != InvalidOid)
restrictinfo->mergejoinoperator != InvalidOid && {
!isdeduced) if (maybe_equijoin)
add_equijoined_keys(root, restrictinfo); add_equijoined_keys(root, restrictinfo);
else if (maybe_outer_join && restrictinfo->can_join)
{
if (bms_is_subset(restrictinfo->left_relids,
outerjoin_nonnullable) &&
!bms_overlap(restrictinfo->right_relids,
outerjoin_nonnullable))
{
/* we have outervar = innervar */
root->left_join_clauses = lappend(root->left_join_clauses,
restrictinfo);
}
else if (bms_is_subset(restrictinfo->right_relids,
outerjoin_nonnullable) &&
!bms_overlap(restrictinfo->left_relids,
outerjoin_nonnullable))
{
/* we have innervar = outervar */
root->right_join_clauses = lappend(root->right_join_clauses,
restrictinfo);
}
else if (bms_equal(outerjoin_nonnullable, qualscope))
{
/* FULL JOIN (above tests cannot match in this case) */
root->full_join_clauses = lappend(root->full_join_clauses,
restrictinfo);
}
}
}
} }
/* /*
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planmain.c,v 1.85 2005/06/10 03:32:23 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/plan/planmain.c,v 1.86 2005/07/02 23:00:41 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -121,6 +121,9 @@ query_planner(PlannerInfo *root, List *tlist, double tuple_fraction, ...@@ -121,6 +121,9 @@ query_planner(PlannerInfo *root, List *tlist, double tuple_fraction,
root->join_rel_list = NIL; root->join_rel_list = NIL;
root->join_rel_hash = NULL; root->join_rel_hash = NULL;
root->equi_key_list = NIL; root->equi_key_list = NIL;
root->left_join_clauses = NIL;
root->right_join_clauses = NIL;
root->full_join_clauses = NIL;
/* /*
* Construct RelOptInfo nodes for all base relations in query. * Construct RelOptInfo nodes for all base relations in query.
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.189 2005/06/10 02:21:04 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.190 2005/07/02 23:00:41 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -194,7 +194,6 @@ subquery_planner(Query *parse, double tuple_fraction, ...@@ -194,7 +194,6 @@ subquery_planner(Query *parse, double tuple_fraction,
int saved_planid = PlannerPlanId; int saved_planid = PlannerPlanId;
PlannerInfo *root; PlannerInfo *root;
Plan *plan; Plan *plan;
bool hasOuterJoins;
List *newHaving; List *newHaving;
List *lst; List *lst;
ListCell *l; ListCell *l;
...@@ -228,12 +227,16 @@ subquery_planner(Query *parse, double tuple_fraction, ...@@ -228,12 +227,16 @@ subquery_planner(Query *parse, double tuple_fraction,
/* /*
* Detect whether any rangetable entries are RTE_JOIN kind; if not, we * Detect whether any rangetable entries are RTE_JOIN kind; if not, we
* can avoid the expense of doing flatten_join_alias_vars(). Also * can avoid the expense of doing flatten_join_alias_vars(). Also
* check for outer joins --- if none, we can skip * check for outer joins --- if none, we can skip reduce_outer_joins()
* reduce_outer_joins(). This must be done after we have done * and some other processing. This must be done after we have done
* pull_up_subqueries, of course. * pull_up_subqueries, of course.
*
* Note: if reduce_outer_joins manages to eliminate all outer joins,
* root->hasOuterJoins is not reset currently. This is OK since its
* purpose is merely to suppress unnecessary processing in simple cases.
*/ */
root->hasJoinRTEs = false; root->hasJoinRTEs = false;
hasOuterJoins = false; root->hasOuterJoins = false;
foreach(l, parse->rtable) foreach(l, parse->rtable)
{ {
RangeTblEntry *rte = (RangeTblEntry *) lfirst(l); RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
...@@ -243,7 +246,7 @@ subquery_planner(Query *parse, double tuple_fraction, ...@@ -243,7 +246,7 @@ subquery_planner(Query *parse, double tuple_fraction,
root->hasJoinRTEs = true; root->hasJoinRTEs = true;
if (IS_OUTER_JOIN(rte->jointype)) if (IS_OUTER_JOIN(rte->jointype))
{ {
hasOuterJoins = true; root->hasOuterJoins = true;
/* Can quit scanning once we find an outer join */ /* Can quit scanning once we find an outer join */
break; break;
} }
...@@ -347,7 +350,7 @@ subquery_planner(Query *parse, double tuple_fraction, ...@@ -347,7 +350,7 @@ subquery_planner(Query *parse, double tuple_fraction,
* joins. This step is most easily done after we've done expression * joins. This step is most easily done after we've done expression
* preprocessing. * preprocessing.
*/ */
if (hasOuterJoins) if (root->hasOuterJoins)
reduce_outer_joins(root); reduce_outer_joins(root);
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.37 2005/06/09 04:19:00 tgl Exp $ * $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.38 2005/07/02 23:00:41 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -24,11 +24,9 @@ ...@@ -24,11 +24,9 @@
static RestrictInfo *make_restrictinfo_internal(Expr *clause, static RestrictInfo *make_restrictinfo_internal(Expr *clause,
Expr *orclause, Expr *orclause,
bool is_pushed_down, bool is_pushed_down,
bool valid_everywhere,
Relids required_relids); Relids required_relids);
static Expr *make_sub_restrictinfos(Expr *clause, static Expr *make_sub_restrictinfos(Expr *clause,
bool is_pushed_down, bool is_pushed_down);
bool valid_everywhere);
static RestrictInfo *join_clause_is_redundant(PlannerInfo *root, static RestrictInfo *join_clause_is_redundant(PlannerInfo *root,
RestrictInfo *rinfo, RestrictInfo *rinfo,
List *reference_list, List *reference_list,
...@@ -40,8 +38,8 @@ static RestrictInfo *join_clause_is_redundant(PlannerInfo *root, ...@@ -40,8 +38,8 @@ static RestrictInfo *join_clause_is_redundant(PlannerInfo *root,
* *
* Build a RestrictInfo node containing the given subexpression. * Build a RestrictInfo node containing the given subexpression.
* *
* The is_pushed_down and valid_everywhere flags must be supplied by the * The is_pushed_down flag must be supplied by the caller.
* caller. required_relids can be NULL, in which case it defaults to the * required_relids can be NULL, in which case it defaults to the
* actual clause contents (i.e., clause_relids). * actual clause contents (i.e., clause_relids).
* *
* We initialize fields that depend only on the given subexpression, leaving * We initialize fields that depend only on the given subexpression, leaving
...@@ -49,23 +47,19 @@ static RestrictInfo *join_clause_is_redundant(PlannerInfo *root, ...@@ -49,23 +47,19 @@ static RestrictInfo *join_clause_is_redundant(PlannerInfo *root,
* later. * later.
*/ */
RestrictInfo * RestrictInfo *
make_restrictinfo(Expr *clause, bool is_pushed_down, bool valid_everywhere, make_restrictinfo(Expr *clause, bool is_pushed_down, Relids required_relids)
Relids required_relids)
{ {
/* /*
* If it's an OR clause, build a modified copy with RestrictInfos * If it's an OR clause, build a modified copy with RestrictInfos
* inserted above each subclause of the top-level AND/OR structure. * inserted above each subclause of the top-level AND/OR structure.
*/ */
if (or_clause((Node *) clause)) if (or_clause((Node *) clause))
return (RestrictInfo *) make_sub_restrictinfos(clause, return (RestrictInfo *) make_sub_restrictinfos(clause, is_pushed_down);
is_pushed_down,
valid_everywhere);
/* Shouldn't be an AND clause, else AND/OR flattening messed up */ /* Shouldn't be an AND clause, else AND/OR flattening messed up */
Assert(!and_clause((Node *) clause)); Assert(!and_clause((Node *) clause));
return make_restrictinfo_internal(clause, NULL, return make_restrictinfo_internal(clause, NULL, is_pushed_down,
is_pushed_down, valid_everywhere,
required_relids); required_relids);
} }
...@@ -84,9 +78,7 @@ make_restrictinfo(Expr *clause, bool is_pushed_down, bool valid_everywhere, ...@@ -84,9 +78,7 @@ make_restrictinfo(Expr *clause, bool is_pushed_down, bool valid_everywhere,
* a specialized routine to allow sharing of RestrictInfos. * a specialized routine to allow sharing of RestrictInfos.
*/ */
List * List *
make_restrictinfo_from_bitmapqual(Path *bitmapqual, make_restrictinfo_from_bitmapqual(Path *bitmapqual, bool is_pushed_down)
bool is_pushed_down,
bool valid_everywhere)
{ {
List *result; List *result;
...@@ -101,8 +93,7 @@ make_restrictinfo_from_bitmapqual(Path *bitmapqual, ...@@ -101,8 +93,7 @@ make_restrictinfo_from_bitmapqual(Path *bitmapqual,
List *sublist; List *sublist;
sublist = make_restrictinfo_from_bitmapqual((Path *) lfirst(l), sublist = make_restrictinfo_from_bitmapqual((Path *) lfirst(l),
is_pushed_down, is_pushed_down);
valid_everywhere);
result = list_concat(result, sublist); result = list_concat(result, sublist);
} }
} }
...@@ -118,8 +109,7 @@ make_restrictinfo_from_bitmapqual(Path *bitmapqual, ...@@ -118,8 +109,7 @@ make_restrictinfo_from_bitmapqual(Path *bitmapqual,
List *sublist; List *sublist;
sublist = make_restrictinfo_from_bitmapqual((Path *) lfirst(l), sublist = make_restrictinfo_from_bitmapqual((Path *) lfirst(l),
is_pushed_down, is_pushed_down);
valid_everywhere);
if (sublist == NIL) if (sublist == NIL)
{ {
/* constant TRUE input yields constant TRUE OR result */ /* constant TRUE input yields constant TRUE OR result */
...@@ -137,7 +127,6 @@ make_restrictinfo_from_bitmapqual(Path *bitmapqual, ...@@ -137,7 +127,6 @@ make_restrictinfo_from_bitmapqual(Path *bitmapqual,
list_make1(make_restrictinfo_internal(make_orclause(withoutris), list_make1(make_restrictinfo_internal(make_orclause(withoutris),
make_orclause(withris), make_orclause(withris),
is_pushed_down, is_pushed_down,
valid_everywhere,
NULL)); NULL));
} }
else if (IsA(bitmapqual, IndexPath)) else if (IsA(bitmapqual, IndexPath))
...@@ -162,15 +151,13 @@ make_restrictinfo_from_bitmapqual(Path *bitmapqual, ...@@ -162,15 +151,13 @@ make_restrictinfo_from_bitmapqual(Path *bitmapqual,
*/ */
static RestrictInfo * static RestrictInfo *
make_restrictinfo_internal(Expr *clause, Expr *orclause, make_restrictinfo_internal(Expr *clause, Expr *orclause,
bool is_pushed_down, bool valid_everywhere, bool is_pushed_down, Relids required_relids)
Relids required_relids)
{ {
RestrictInfo *restrictinfo = makeNode(RestrictInfo); RestrictInfo *restrictinfo = makeNode(RestrictInfo);
restrictinfo->clause = clause; restrictinfo->clause = clause;
restrictinfo->orclause = orclause; restrictinfo->orclause = orclause;
restrictinfo->is_pushed_down = is_pushed_down; restrictinfo->is_pushed_down = is_pushed_down;
restrictinfo->valid_everywhere = valid_everywhere;
restrictinfo->can_join = false; /* may get set below */ restrictinfo->can_join = false; /* may get set below */
/* /*
...@@ -250,8 +237,7 @@ make_restrictinfo_internal(Expr *clause, Expr *orclause, ...@@ -250,8 +237,7 @@ make_restrictinfo_internal(Expr *clause, Expr *orclause,
* simple clauses are valid RestrictInfos. * simple clauses are valid RestrictInfos.
*/ */
static Expr * static Expr *
make_sub_restrictinfos(Expr *clause, bool is_pushed_down, make_sub_restrictinfos(Expr *clause, bool is_pushed_down)
bool valid_everywhere)
{ {
if (or_clause((Node *) clause)) if (or_clause((Node *) clause))
{ {
...@@ -261,12 +247,10 @@ make_sub_restrictinfos(Expr *clause, bool is_pushed_down, ...@@ -261,12 +247,10 @@ make_sub_restrictinfos(Expr *clause, bool is_pushed_down,
foreach(temp, ((BoolExpr *) clause)->args) foreach(temp, ((BoolExpr *) clause)->args)
orlist = lappend(orlist, orlist = lappend(orlist,
make_sub_restrictinfos(lfirst(temp), make_sub_restrictinfos(lfirst(temp),
is_pushed_down, is_pushed_down));
valid_everywhere));
return (Expr *) make_restrictinfo_internal(clause, return (Expr *) make_restrictinfo_internal(clause,
make_orclause(orlist), make_orclause(orlist),
is_pushed_down, is_pushed_down,
valid_everywhere,
NULL); NULL);
} }
else if (and_clause((Node *) clause)) else if (and_clause((Node *) clause))
...@@ -277,15 +261,13 @@ make_sub_restrictinfos(Expr *clause, bool is_pushed_down, ...@@ -277,15 +261,13 @@ make_sub_restrictinfos(Expr *clause, bool is_pushed_down,
foreach(temp, ((BoolExpr *) clause)->args) foreach(temp, ((BoolExpr *) clause)->args)
andlist = lappend(andlist, andlist = lappend(andlist,
make_sub_restrictinfos(lfirst(temp), make_sub_restrictinfos(lfirst(temp),
is_pushed_down, is_pushed_down));
valid_everywhere));
return make_andclause(andlist); return make_andclause(andlist);
} }
else else
return (Expr *) make_restrictinfo_internal(clause, return (Expr *) make_restrictinfo_internal(clause,
NULL, NULL,
is_pushed_down, is_pushed_down,
valid_everywhere,
NULL); NULL);
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.115 2005/06/13 23:14:49 tgl Exp $ * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.116 2005/07/02 23:00:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -87,6 +87,15 @@ typedef struct PlannerInfo ...@@ -87,6 +87,15 @@ typedef struct PlannerInfo
List *equi_key_list; /* list of lists of equijoined List *equi_key_list; /* list of lists of equijoined
* PathKeyItems */ * PathKeyItems */
List *left_join_clauses; /* list of RestrictInfos for outer join
* clauses w/nonnullable var on left */
List *right_join_clauses; /* list of RestrictInfos for outer join
* clauses w/nonnullable var on right */
List *full_join_clauses; /* list of RestrictInfos for full outer
* join clauses */
List *in_info_list; /* list of InClauseInfos */ List *in_info_list; /* list of InClauseInfos */
List *query_pathkeys; /* desired pathkeys for query_planner(), List *query_pathkeys; /* desired pathkeys for query_planner(),
...@@ -95,6 +104,7 @@ typedef struct PlannerInfo ...@@ -95,6 +104,7 @@ typedef struct PlannerInfo
double tuple_fraction; /* tuple_fraction passed to query_planner */ double tuple_fraction; /* tuple_fraction passed to query_planner */
bool hasJoinRTEs; /* true if any RTEs are RTE_JOIN kind */ bool hasJoinRTEs; /* true if any RTEs are RTE_JOIN kind */
bool hasOuterJoins; /* true if any RTEs are outer joins */
bool hasHavingQual; /* true if havingQual was non-null */ bool hasHavingQual; /* true if havingQual was non-null */
} PlannerInfo; } PlannerInfo;
...@@ -695,10 +705,6 @@ typedef struct HashPath ...@@ -695,10 +705,6 @@ typedef struct HashPath
* joined, will also have is_pushed_down set because it will get attached to * joined, will also have is_pushed_down set because it will get attached to
* some lower joinrel. * some lower joinrel.
* *
* We also store a valid_everywhere flag, which says that the clause is not
* affected by any lower-level outer join, and therefore any conditions it
* asserts can be presumed true throughout the plan tree.
*
* In general, the referenced clause might be arbitrarily complex. The * In general, the referenced clause might be arbitrarily complex. The
* kinds of clauses we can handle as indexscan quals, mergejoin clauses, * kinds of clauses we can handle as indexscan quals, mergejoin clauses,
* or hashjoin clauses are fairly limited --- the code for each kind of * or hashjoin clauses are fairly limited --- the code for each kind of
...@@ -725,8 +731,6 @@ typedef struct RestrictInfo ...@@ -725,8 +731,6 @@ typedef struct RestrictInfo
bool is_pushed_down; /* TRUE if clause was pushed down in level */ bool is_pushed_down; /* TRUE if clause was pushed down in level */
bool valid_everywhere; /* TRUE if valid on every level */
/* /*
* This flag is set true if the clause looks potentially useful as a * This flag is set true if the clause looks potentially useful as a
* merge or hash join clause, that is if it is a binary opclause with * merge or hash join clause, that is if it is a binary opclause with
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/optimizer/restrictinfo.h,v 1.31 2005/06/09 04:19:00 tgl Exp $ * $PostgreSQL: pgsql/src/include/optimizer/restrictinfo.h,v 1.32 2005/07/02 23:00:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -19,11 +19,9 @@ ...@@ -19,11 +19,9 @@
extern RestrictInfo *make_restrictinfo(Expr *clause, extern RestrictInfo *make_restrictinfo(Expr *clause,
bool is_pushed_down, bool is_pushed_down,
bool valid_everywhere,
Relids required_relids); Relids required_relids);
extern List *make_restrictinfo_from_bitmapqual(Path *bitmapqual, extern List *make_restrictinfo_from_bitmapqual(Path *bitmapqual,
bool is_pushed_down, bool is_pushed_down);
bool valid_everywhere);
extern bool restriction_is_or_clause(RestrictInfo *restrictinfo); extern bool restriction_is_or_clause(RestrictInfo *restrictinfo);
extern List *get_actual_clauses(List *restrictinfo_list); extern List *get_actual_clauses(List *restrictinfo_list);
extern void get_actual_join_clauses(List *restrictinfo_list, extern void get_actual_join_clauses(List *restrictinfo_list,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment