* Portions Copyright (c) 1994, Regents of the University of California
*
* 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 $
*
*-------------------------------------------------------------------------
*/
COPY_NODE_FIELD(clause);
COPY_SCALAR_FIELD(is_pushed_down);
- COPY_SCALAR_FIELD(valid_everywhere);
COPY_SCALAR_FIELD(can_join);
COPY_BITMAPSET_FIELD(clause_relids);
COPY_BITMAPSET_FIELD(required_relids);
* Portions Copyright (c) 1994, Regents of the University of California
*
* 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 $
*
*-------------------------------------------------------------------------
*/
{
COMPARE_NODE_FIELD(clause);
COMPARE_SCALAR_FIELD(is_pushed_down);
- COMPARE_SCALAR_FIELD(valid_everywhere);
COMPARE_BITMAPSET_FIELD(required_relids);
/*
*
*
* 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
* Every node type that can appear in stored rules' parsetrees *must*
WRITE_NODE_FIELD(parse);
WRITE_NODE_FIELD(join_rel_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(query_pathkeys);
WRITE_BOOL_FIELD(hasJoinRTEs);
+ WRITE_BOOL_FIELD(hasOuterJoins);
WRITE_BOOL_FIELD(hasHavingQual);
}
/* NB: this isn't a complete set of fields */
WRITE_NODE_FIELD(clause);
WRITE_BOOL_FIELD(is_pushed_down);
- WRITE_BOOL_FIELD(valid_everywhere);
WRITE_BOOL_FIELD(can_join);
WRITE_BITMAPSET_FIELD(clause_relids);
WRITE_BITMAPSET_FIELD(required_relids);
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
{
resultquals = lappend(resultquals,
make_restrictinfo(boolqual,
- true, true,
+ true,
NULL));
continue;
}
elog(ERROR, "no = operator for opclass %u", opclass);
expr = make_opclause(oproid, BOOLOID, false,
(Expr *) leftop, (Expr *) prefix_const);
- result = list_make1(make_restrictinfo(expr, true, true, NULL));
+ result = list_make1(make_restrictinfo(expr, true, NULL));
return result;
}
elog(ERROR, "no >= operator for opclass %u", opclass);
expr = make_opclause(oproid, BOOLOID, false,
(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
elog(ERROR, "no < operator for opclass %u", opclass);
expr = make_opclause(oproid, BOOLOID, false,
(Expr *) leftop, (Expr *) greaterstr);
- result = lappend(result, make_restrictinfo(expr, true, true, NULL));
+ result = lappend(result, make_restrictinfo(expr, true, NULL));
}
return result;
(Expr *) leftop,
(Expr *) makeConst(datatype, -1, opr1right,
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 )" */
(Expr *) leftop,
(Expr *) makeConst(datatype, -1, opr2right,
false, false));
- result = lappend(result, make_restrictinfo(expr, true, true, NULL));
+ result = lappend(result, make_restrictinfo(expr, true, NULL));
return result;
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
ListCell *i;
/*
- * Find potentially interesting OR joinclauses. We must ignore any
- * joinclauses that are not marked valid_everywhere, because they
- * cannot be pushed down due to outer-join rules.
+ * Find potentially interesting OR joinclauses.
*/
foreach(i, rel->joininfo)
{
RestrictInfo *rinfo = (RestrictInfo *) lfirst(i);
- if (restriction_is_or_clause(rinfo) &&
- rinfo->valid_everywhere)
+ if (restriction_is_or_clause(rinfo))
{
/*
* Use the generate_bitmap_or_paths() machinery to estimate
* Convert the path's indexclauses structure to a RestrictInfo tree,
* and add it to the rel's restriction list.
*/
- newrinfos = make_restrictinfo_from_bitmapqual((Path *) bestpath,
- true, true);
+ newrinfos = make_restrictinfo_from_bitmapqual((Path *) bestpath, true);
Assert(list_length(newrinfos) == 1);
or_rinfo = (RestrictInfo *) linitial(newrinfos);
Assert(IsA(or_rinfo, RestrictInfo));
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.68 2005/06/09 04:18:59 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/pathkeys.c,v 1.69 2005/07/02 23:00:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
static PathKeyItem *makePathKeyItem(Node *key, Oid sortop, bool checkType);
+static void generate_outer_join_implications(PlannerInfo *root,
+ List *equi_key_set,
+ Relids *relids);
+static void process_implied_const_eq(PlannerInfo *root,
+ List *equi_key_set, Relids *relids,
+ Node *item1, Oid sortop1,
+ Relids item1_relids,
+ bool delete_it);
static List *make_canonical_pathkey(PlannerInfo *root, PathKeyItem *item);
static Var *find_indexkey_var(PlannerInfo *root, RelOptInfo *rel,
AttrNumber varattno);
* functions; but we will never consider such an expression to be a pathkey
* at all, because check_mergejoinable() will reject it.)
*
+ * Also, when we have constants in an equi_key_list we can try to propagate
+ * the constants into outer joins; see generate_outer_join_implications
+ * for discussion.
+ *
* This routine just walks the equi_key_list to find all pairwise equalities.
* We call process_implied_equality (in plan/initsplan.c) to adjust the
* restrictinfo datastructures for each pair.
/*
* A set containing only two items cannot imply any equalities
- * beyond the one that created the set, so we can skip it.
+ * beyond the one that created the set, so we can skip it ---
+ * unless outer joins appear in the query.
*/
- if (nitems < 3)
+ if (nitems < 3 && !root->hasOuterJoins)
continue;
/*
i1++;
}
+ /*
+ * If we have constant(s) and outer joins, try to propagate the
+ * constants through outer-join quals.
+ */
+ if (have_consts && root->hasOuterJoins)
+ generate_outer_join_implications(root, curset, relids);
+
+ /*
+ * A set containing only two items cannot imply any equalities
+ * beyond the one that created the set, so we can skip it.
+ */
+ if (nitems < 3)
+ continue;
+
/*
* Match each item in the set with all that appear after it (it's
* sufficient to generate A=B, need not process B=A too).
}
}
+/*
+ * generate_outer_join_implications
+ * Generate clauses that can be deduced in outer-join situations.
+ *
+ * When we have mergejoinable clauses A = B that are outer-join clauses,
+ * we can't blindly combine them with other clauses A = C to deduce B = C,
+ * since in fact the "equality" A = B won't necessarily hold above the
+ * outer join (one of the variables might be NULL instead). Nonetheless
+ * there are cases where we can add qual clauses using transitivity.
+ *
+ * One case that we look for here is an outer-join clause OUTERVAR = INNERVAR
+ * combined with a pushed-down (valid everywhere) clause OUTERVAR = CONSTANT.
+ * It is safe and useful to push a clause INNERVAR = CONSTANT into the
+ * evaluation of the inner (nullable) relation, because any inner rows not
+ * meeting this condition will not contribute to the outer-join result anyway.
+ * (Any outer rows they could join to will be eliminated by the pushed-down
+ * clause.)
+ *
+ * Note that the above rule does not work for full outer joins, nor for
+ * pushed-down restrictions on an inner-side variable; nor is it very
+ * interesting to consider cases where the pushed-down clause involves
+ * relations entirely outside the outer join, since such clauses couldn't
+ * be pushed into the inner side's scan anyway. So the restriction to
+ * outervar = pseudoconstant is not really giving up anything.
+ *
+ * For full-join cases, we can only do something useful if it's a FULL JOIN
+ * USING and a merged column has a restriction MERGEDVAR = CONSTANT. By
+ * the time it gets here, the restriction will look like
+ * COALESCE(LEFTVAR, RIGHTVAR) = CONSTANT
+ * and we will have a join clause LEFTVAR = RIGHTVAR that we can match the
+ * COALESCE expression to. In this situation we can push LEFTVAR = CONSTANT
+ * and RIGHTVAR = CONSTANT into the input relations, since any rows not
+ * meeting these conditions cannot contribute to the join result.
+ *
+ * Again, there isn't any traction to be gained by trying to deal with
+ * clauses comparing a mergedvar to a non-pseudoconstant. So we can make
+ * use of the equi_key_lists to quickly find the interesting pushed-down
+ * clauses. The interesting outer-join clauses were accumulated for us by
+ * distribute_qual_to_rels.
+ *
+ * equi_key_set: a list of PathKeyItems that are known globally equivalent,
+ * at least one of which is a pseudoconstant.
+ * relids: an array of Relids sets showing the relation membership of each
+ * PathKeyItem in equi_key_set.
+ */
+static void
+generate_outer_join_implications(PlannerInfo *root,
+ List *equi_key_set,
+ Relids *relids)
+{
+ ListCell *l1;
+
+ /* Examine each mergejoinable outer-join clause with OUTERVAR on left */
+ foreach(l1, root->left_join_clauses)
+ {
+ RestrictInfo *rinfo = (RestrictInfo *) lfirst(l1);
+ Node *leftop = get_leftop(rinfo->clause);
+ Node *rightop = get_rightop(rinfo->clause);
+ ListCell *l2;
+
+ /* Scan to see if it matches any element of equi_key_set */
+ foreach(l2, equi_key_set)
+ {
+ PathKeyItem *item1 = (PathKeyItem *) lfirst(l2);
+
+ if (equal(leftop, item1->key) &&
+ rinfo->left_sortop == item1->sortop)
+ {
+ /*
+ * Yes, so find constant member(s) of set and generate
+ * implied INNERVAR = CONSTANT
+ */
+ process_implied_const_eq(root, equi_key_set, relids,
+ rightop,
+ rinfo->right_sortop,
+ rinfo->right_relids,
+ false);
+ /*
+ * We can remove the explicit outer join qual, too,
+ * since we now have tests forcing each of its sides
+ * to the same value.
+ */
+ process_implied_equality(root,
+ leftop,
+ rightop,
+ rinfo->left_sortop,
+ rinfo->right_sortop,
+ rinfo->left_relids,
+ rinfo->right_relids,
+ true);
+
+ /* No need to match against remaining set members */
+ break;
+ }
+ }
+ }
+
+ /* Examine each mergejoinable outer-join clause with OUTERVAR on right */
+ foreach(l1, root->right_join_clauses)
+ {
+ RestrictInfo *rinfo = (RestrictInfo *) lfirst(l1);
+ Node *leftop = get_leftop(rinfo->clause);
+ Node *rightop = get_rightop(rinfo->clause);
+ ListCell *l2;
+
+ /* Scan to see if it matches any element of equi_key_set */
+ foreach(l2, equi_key_set)
+ {
+ PathKeyItem *item1 = (PathKeyItem *) lfirst(l2);
+
+ if (equal(rightop, item1->key) &&
+ rinfo->right_sortop == item1->sortop)
+ {
+ /*
+ * Yes, so find constant member(s) of set and generate
+ * implied INNERVAR = CONSTANT
+ */
+ process_implied_const_eq(root, equi_key_set, relids,
+ leftop,
+ rinfo->left_sortop,
+ rinfo->left_relids,
+ false);
+ /*
+ * We can remove the explicit outer join qual, too,
+ * since we now have tests forcing each of its sides
+ * to the same value.
+ */
+ process_implied_equality(root,
+ leftop,
+ rightop,
+ rinfo->left_sortop,
+ rinfo->right_sortop,
+ rinfo->left_relids,
+ rinfo->right_relids,
+ true);
+
+ /* No need to match against remaining set members */
+ break;
+ }
+ }
+ }
+
+ /* Examine each mergejoinable full-join clause */
+ foreach(l1, root->full_join_clauses)
+ {
+ RestrictInfo *rinfo = (RestrictInfo *) lfirst(l1);
+ Node *leftop = get_leftop(rinfo->clause);
+ Node *rightop = get_rightop(rinfo->clause);
+ int i1 = 0;
+ ListCell *l2;
+
+ /* Scan to see if it matches any element of equi_key_set */
+ foreach(l2, equi_key_set)
+ {
+ PathKeyItem *item1 = (PathKeyItem *) lfirst(l2);
+ CoalesceExpr *cexpr = (CoalesceExpr *) item1->key;
+
+ /*
+ * Try to match a pathkey containing a COALESCE() expression
+ * to the join clause. We can assume the COALESCE() inputs
+ * are in the same order as the join clause, since both were
+ * automatically generated in the cases we care about.
+ *
+ * XXX currently this may fail to match in cross-type cases
+ * because the COALESCE will contain typecast operations while
+ * the join clause may not (if there is a cross-type mergejoin
+ * operator available for the two column types).
+ * Is it OK to strip implicit coercions from the COALESCE
+ * arguments? What of the sortops in such cases?
+ */
+ if (IsA(cexpr, CoalesceExpr) &&
+ list_length(cexpr->args) == 2 &&
+ equal(leftop, (Node *) linitial(cexpr->args)) &&
+ equal(rightop, (Node *) lsecond(cexpr->args)) &&
+ rinfo->left_sortop == item1->sortop &&
+ rinfo->right_sortop == item1->sortop)
+ {
+ /*
+ * Yes, so find constant member(s) of set and generate
+ * implied LEFTVAR = CONSTANT
+ */
+ process_implied_const_eq(root, equi_key_set, relids,
+ leftop,
+ rinfo->left_sortop,
+ rinfo->left_relids,
+ false);
+ /* ... and RIGHTVAR = CONSTANT */
+ process_implied_const_eq(root, equi_key_set, relids,
+ rightop,
+ rinfo->right_sortop,
+ rinfo->right_relids,
+ false);
+ /* ... and remove COALESCE() = CONSTANT */
+ process_implied_const_eq(root, equi_key_set, relids,
+ item1->key,
+ item1->sortop,
+ relids[i1],
+ true);
+ /*
+ * We can remove the explicit outer join qual, too,
+ * since we now have tests forcing each of its sides
+ * to the same value.
+ */
+ process_implied_equality(root,
+ leftop,
+ rightop,
+ rinfo->left_sortop,
+ rinfo->right_sortop,
+ rinfo->left_relids,
+ rinfo->right_relids,
+ true);
+
+ /* No need to match against remaining set members */
+ break;
+ }
+ i1++;
+ }
+ }
+}
+
+/*
+ * process_implied_const_eq
+ * Apply process_implied_equality with the given item and each
+ * pseudoconstant member of equi_key_set.
+ *
+ * This is just a subroutine to save some cruft in
+ * generate_outer_join_implications. equi_key_set and relids are as in
+ * generate_outer_join_implications, the other parameters as for
+ * process_implied_equality.
+ */
+static void
+process_implied_const_eq(PlannerInfo *root, List *equi_key_set, Relids *relids,
+ Node *item1, Oid sortop1, Relids item1_relids,
+ bool delete_it)
+{
+ ListCell *l;
+ bool found = false;
+ int i = 0;
+
+ foreach(l, equi_key_set)
+ {
+ PathKeyItem *item2 = (PathKeyItem *) lfirst(l);
+
+ if (bms_is_empty(relids[i]))
+ {
+ process_implied_equality(root,
+ item1, item2->key,
+ sortop1, item2->sortop,
+ item1_relids, NULL,
+ delete_it);
+ found = true;
+ }
+ i++;
+ }
+ /* Caller screwed up if no constants in list */
+ Assert(found);
+}
+
/*
* exprs_known_equal
* Detect whether two expressions are known equal due to equijoin clauses.
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
List *bitmapclauses;
bitmapclauses =
- make_restrictinfo_from_bitmapqual(innerpath->bitmapqual,
- true, true);
+ make_restrictinfo_from_bitmapqual(innerpath->bitmapqual, true);
joinrestrictclauses =
select_nonredundant_join_clauses(root,
joinrestrictclauses,
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
Relids qualscope)
{
Relids relids;
- bool valid_everywhere;
- bool can_be_equijoin;
+ bool maybe_equijoin;
+ bool maybe_outer_join;
RestrictInfo *restrictinfo;
RelOptInfo *rel;
List *vars;
if (isdeduced)
{
/*
- * If the qual came from implied-equality deduction, we can
- * evaluate the qual at its natural semantic level. It is not
- * affected by any outer-join rules (else we'd not have decided
- * the vars were equal).
+ * If the qual came from implied-equality deduction, we always
+ * evaluate the qual at its natural semantic level. It is the
+ * responsibility of the deducer not to create any quals that
+ * should be delayed by outer-join rules.
*/
Assert(bms_equal(relids, qualscope));
- valid_everywhere = true;
- can_be_equijoin = true;
+ /* Needn't feed it back for more deductions */
+ maybe_equijoin = false;
+ maybe_outer_join = false;
}
else if (bms_overlap(relids, outerjoin_nonnullable))
{
* result, so we treat it the same as an ordinary inner-join qual.
*/
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
{
* time we are called, the outerjoinset of each baserel will show
* exactly those outer joins that are below the qual in the join
* 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 tmprelids;
int relno;
- valid_everywhere = true;
tmprelids = bms_copy(relids);
while ((relno = bms_first_member(tmprelids)) >= 0)
{
RelOptInfo *rel = find_base_rel(root, relno);
if (rel->outerjoinset != NULL)
- {
addrelids = bms_add_members(addrelids, rel->outerjoinset);
- valid_everywhere = false;
- }
}
bms_free(tmprelids);
if (bms_is_subset(addrelids, relids))
{
/* Qual is not affected by any outer-join restriction */
- can_be_equijoin = true;
+ maybe_equijoin = true;
}
else
{
* Because application of the qual will be delayed by outer
* join, we mustn't assume its vars are equal everywhere.
*/
- can_be_equijoin = false;
+ maybe_equijoin = false;
}
bms_free(addrelids);
+ maybe_outer_join = false;
}
/*
*/
restrictinfo = make_restrictinfo((Expr *) clause,
is_pushed_down,
- valid_everywhere,
relids);
/*
* allows us to consider z and q equal after their rels are
* joined.
*/
- if (can_be_equijoin)
- check_mergejoinable(restrictinfo);
+ check_mergejoinable(restrictinfo);
/*
* If the clause was deduced from implied equality, check to
}
/*
- * If the clause has a mergejoinable operator, and is not an
- * outer-join qualification nor bubbled up due to an outer join, then
- * the two sides represent equivalent PathKeyItems for path keys: any
- * path that is sorted by one side will also be sorted by the other
- * (as soon as the two rels are joined, that is). Record the key
- * equivalence for future use. (We can skip this for a deduced
- * clause, since the keys are already known equivalent in that case.)
+ * If the clause has a mergejoinable operator, we may be able to
+ * deduce more things from it under the principle of transitivity.
+ *
+ * If it is not an outer-join qualification nor bubbled up due to an outer
+ * join, then the two sides represent equivalent PathKeyItems for path
+ * keys: any path that is sorted by one side will also be sorted by the
+ * 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 &&
- restrictinfo->mergejoinoperator != InvalidOid &&
- !isdeduced)
- add_equijoined_keys(root, restrictinfo);
+ if (restrictinfo->mergejoinoperator != InvalidOid)
+ {
+ if (maybe_equijoin)
+ 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);
+ }
+ }
+ }
}
/*
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
root->join_rel_list = NIL;
root->join_rel_hash = NULL;
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.
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
int saved_planid = PlannerPlanId;
PlannerInfo *root;
Plan *plan;
- bool hasOuterJoins;
List *newHaving;
List *lst;
ListCell *l;
/*
* Detect whether any rangetable entries are RTE_JOIN kind; if not, we
* can avoid the expense of doing flatten_join_alias_vars(). Also
- * check for outer joins --- if none, we can skip
- * reduce_outer_joins(). This must be done after we have done
+ * check for outer joins --- if none, we can skip reduce_outer_joins()
+ * and some other processing. This must be done after we have done
* 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;
- hasOuterJoins = false;
+ root->hasOuterJoins = false;
foreach(l, parse->rtable)
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
root->hasJoinRTEs = true;
if (IS_OUTER_JOIN(rte->jointype))
{
- hasOuterJoins = true;
+ root->hasOuterJoins = true;
/* Can quit scanning once we find an outer join */
break;
}
* joins. This step is most easily done after we've done expression
* preprocessing.
*/
- if (hasOuterJoins)
+ if (root->hasOuterJoins)
reduce_outer_joins(root);
/*
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
static RestrictInfo *make_restrictinfo_internal(Expr *clause,
Expr *orclause,
bool is_pushed_down,
- bool valid_everywhere,
Relids required_relids);
static Expr *make_sub_restrictinfos(Expr *clause,
- bool is_pushed_down,
- bool valid_everywhere);
+ bool is_pushed_down);
static RestrictInfo *join_clause_is_redundant(PlannerInfo *root,
RestrictInfo *rinfo,
List *reference_list,
*
* Build a RestrictInfo node containing the given subexpression.
*
- * The is_pushed_down and valid_everywhere flags must be supplied by the
- * caller. required_relids can be NULL, in which case it defaults to the
+ * The is_pushed_down flag must be supplied by the caller.
+ * required_relids can be NULL, in which case it defaults to the
* actual clause contents (i.e., clause_relids).
*
* We initialize fields that depend only on the given subexpression, leaving
* later.
*/
RestrictInfo *
-make_restrictinfo(Expr *clause, bool is_pushed_down, bool valid_everywhere,
- Relids required_relids)
+make_restrictinfo(Expr *clause, bool is_pushed_down, Relids required_relids)
{
/*
* If it's an OR clause, build a modified copy with RestrictInfos
* inserted above each subclause of the top-level AND/OR structure.
*/
if (or_clause((Node *) clause))
- return (RestrictInfo *) make_sub_restrictinfos(clause,
- is_pushed_down,
- valid_everywhere);
+ return (RestrictInfo *) make_sub_restrictinfos(clause, is_pushed_down);
/* Shouldn't be an AND clause, else AND/OR flattening messed up */
Assert(!and_clause((Node *) clause));
- return make_restrictinfo_internal(clause, NULL,
- is_pushed_down, valid_everywhere,
+ return make_restrictinfo_internal(clause, NULL, is_pushed_down,
required_relids);
}
* a specialized routine to allow sharing of RestrictInfos.
*/
List *
-make_restrictinfo_from_bitmapqual(Path *bitmapqual,
- bool is_pushed_down,
- bool valid_everywhere)
+make_restrictinfo_from_bitmapqual(Path *bitmapqual, bool is_pushed_down)
{
List *result;
List *sublist;
sublist = make_restrictinfo_from_bitmapqual((Path *) lfirst(l),
- is_pushed_down,
- valid_everywhere);
+ is_pushed_down);
result = list_concat(result, sublist);
}
}
List *sublist;
sublist = make_restrictinfo_from_bitmapqual((Path *) lfirst(l),
- is_pushed_down,
- valid_everywhere);
+ is_pushed_down);
if (sublist == NIL)
{
/* constant TRUE input yields constant TRUE OR result */
list_make1(make_restrictinfo_internal(make_orclause(withoutris),
make_orclause(withris),
is_pushed_down,
- valid_everywhere,
NULL));
}
else if (IsA(bitmapqual, IndexPath))
*/
static RestrictInfo *
make_restrictinfo_internal(Expr *clause, Expr *orclause,
- bool is_pushed_down, bool valid_everywhere,
- Relids required_relids)
+ bool is_pushed_down, Relids required_relids)
{
RestrictInfo *restrictinfo = makeNode(RestrictInfo);
restrictinfo->clause = clause;
restrictinfo->orclause = orclause;
restrictinfo->is_pushed_down = is_pushed_down;
- restrictinfo->valid_everywhere = valid_everywhere;
restrictinfo->can_join = false; /* may get set below */
/*
* simple clauses are valid RestrictInfos.
*/
static Expr *
-make_sub_restrictinfos(Expr *clause, bool is_pushed_down,
- bool valid_everywhere)
+make_sub_restrictinfos(Expr *clause, bool is_pushed_down)
{
if (or_clause((Node *) clause))
{
foreach(temp, ((BoolExpr *) clause)->args)
orlist = lappend(orlist,
make_sub_restrictinfos(lfirst(temp),
- is_pushed_down,
- valid_everywhere));
+ is_pushed_down));
return (Expr *) make_restrictinfo_internal(clause,
make_orclause(orlist),
is_pushed_down,
- valid_everywhere,
NULL);
}
else if (and_clause((Node *) clause))
foreach(temp, ((BoolExpr *) clause)->args)
andlist = lappend(andlist,
make_sub_restrictinfos(lfirst(temp),
- is_pushed_down,
- valid_everywhere));
+ is_pushed_down));
return make_andclause(andlist);
}
else
return (Expr *) make_restrictinfo_internal(clause,
NULL,
is_pushed_down,
- valid_everywhere,
NULL);
}
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* 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 $
*
*-------------------------------------------------------------------------
*/
List *equi_key_list; /* list of lists of equijoined
* 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 *query_pathkeys; /* desired pathkeys for query_planner(),
double tuple_fraction; /* tuple_fraction passed to query_planner */
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 */
} PlannerInfo;
* joined, will also have is_pushed_down set because it will get attached to
* 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
* kinds of clauses we can handle as indexscan quals, mergejoin clauses,
* or hashjoin clauses are fairly limited --- the code for each kind of
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
* merge or hash join clause, that is if it is a binary opclause with
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
* 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 $
*
*-------------------------------------------------------------------------
*/
extern RestrictInfo *make_restrictinfo(Expr *clause,
bool is_pushed_down,
- bool valid_everywhere,
Relids required_relids);
extern List *make_restrictinfo_from_bitmapqual(Path *bitmapqual,
- bool is_pushed_down,
- bool valid_everywhere);
+ bool is_pushed_down);
extern bool restriction_is_or_clause(RestrictInfo *restrictinfo);
extern List *get_actual_clauses(List *restrictinfo_list);
extern void get_actual_join_clauses(List *restrictinfo_list,