aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan/initsplan.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/plan/initsplan.c')
-rw-r--r--src/backend/optimizer/plan/initsplan.c228
1 files changed, 94 insertions, 134 deletions
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index 037ed3314cf..3a824d55d72 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.82 2003/01/20 18:54:52 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.83 2003/01/24 03:58:43 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -40,8 +40,6 @@ static void distribute_qual_to_rels(Query *root, Node *clause,
bool isouterjoin,
bool isdeduced,
Relids qualscope);
-static void add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
- Relids join_relids);
static void add_vars_to_targetlist(Query *root, List *vars);
static bool qual_is_redundant(Query *root, RestrictInfo *restrictinfo,
List *restrictlist);
@@ -539,7 +537,7 @@ distribute_qual_to_rels(Query *root, Node *clause,
/*
* Add clause to the join lists of all the relevant relations.
*/
- add_join_info_to_rels(root, restrictinfo, relids);
+ add_join_clause_to_rels(root, restrictinfo, relids);
/*
* Add vars used in the join clause to targetlists of their
@@ -573,78 +571,95 @@ distribute_qual_to_rels(Query *root, Node *clause,
}
/*
- * add_join_info_to_rels
- * For every relation participating in a join clause, add 'restrictinfo' to
- * the appropriate joininfo list (creating a new list and adding it to the
- * appropriate rel node if necessary).
- *
- * Note that the same copy of the restrictinfo node is linked to by all the
- * lists it is in. This allows us to exploit caching of information about
- * the restriction clause (but we must be careful that the information does
- * not depend on context).
- *
- * 'restrictinfo' describes the join clause
- * 'join_relids' is the list of relations participating in the join clause
- */
-static void
-add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
- Relids join_relids)
-{
- List *join_relid;
-
- /* For every relid, find the joininfo, and add the proper join entries */
- foreach(join_relid, join_relids)
- {
- int cur_relid = lfirsti(join_relid);
- Relids unjoined_relids = NIL;
- JoinInfo *joininfo;
- List *otherrel;
-
- /* Get the relids not equal to the current relid */
- foreach(otherrel, join_relids)
- {
- if (lfirsti(otherrel) != cur_relid)
- unjoined_relids = lappendi(unjoined_relids, lfirsti(otherrel));
- }
- Assert(unjoined_relids != NIL);
-
- /*
- * Find or make the joininfo node for this combination of rels,
- * and add the restrictinfo node to it.
- */
- joininfo = make_joininfo_node(find_base_rel(root, cur_relid),
- unjoined_relids);
- joininfo->jinfo_restrictinfo = lappend(joininfo->jinfo_restrictinfo,
- restrictinfo);
- }
-}
-
-/*
* process_implied_equality
* Check to see whether we already have a restrictinfo item that says
- * item1 = item2, and create one if not. This is a consequence of
- * transitivity of mergejoin equality: if we have mergejoinable
- * clauses A = B and B = C, we can deduce A = C (where = is an
- * appropriate mergejoinable operator).
+ * item1 = item2, and create one if not; or if delete_it is true,
+ * remove any such restrictinfo item.
+ *
+ * This processing is a consequence of transitivity of mergejoin equality:
+ * if we have mergejoinable clauses A = B and B = C, we can deduce A = C
+ * (where = is an appropriate mergejoinable operator). See path/pathkeys.c
+ * for more details.
*/
void
-process_implied_equality(Query *root, Node *item1, Node *item2,
- Oid sortop1, Oid sortop2)
+process_implied_equality(Query *root,
+ Node *item1, Node *item2,
+ Oid sortop1, Oid sortop2,
+ Relids item1_relids, Relids item2_relids,
+ bool delete_it)
{
+ Relids relids;
+ RelOptInfo *rel1;
+ List *restrictlist;
+ List *itm;
Oid ltype,
rtype;
Operator eq_operator;
Form_pg_operator pgopform;
Expr *clause;
+ /* Get list of relids referenced in the two expressions */
+ relids = set_unioni(item1_relids, item2_relids);
+
/*
- * Forget it if this equality is already recorded.
- *
- * Note: if only a single relation is involved, we may fall through
- * here and end up rejecting the equality later on in qual_is_redundant.
- * This is a tad slow but should be okay.
+ * generate_implied_equalities() shouldn't call me on two constants.
+ */
+ Assert(relids != NIL);
+
+ /*
+ * If the exprs involve a single rel, we need to look at that rel's
+ * baserestrictinfo list. If multiple rels, any one will have a
+ * joininfo node for the rest, and we can scan any of 'em.
*/
- if (exprs_known_equal(root, item1, item2))
+ rel1 = find_base_rel(root, lfirsti(relids));
+ if (lnext(relids) == NIL)
+ restrictlist = rel1->baserestrictinfo;
+ else
+ {
+ JoinInfo *joininfo = find_joininfo_node(rel1, lnext(relids));
+
+ restrictlist = joininfo ? joininfo->jinfo_restrictinfo : NIL;
+ }
+
+ /*
+ * Scan to see if equality is already known. If so, we're done in
+ * the add case, and done after removing it in the delete case.
+ */
+ foreach(itm, restrictlist)
+ {
+ RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(itm);
+ Node *left,
+ *right;
+
+ if (restrictinfo->mergejoinoperator == InvalidOid)
+ continue; /* ignore non-mergejoinable clauses */
+ /* We now know the restrictinfo clause is a binary opclause */
+ left = get_leftop(restrictinfo->clause);
+ right = get_rightop(restrictinfo->clause);
+ if ((equal(item1, left) && equal(item2, right)) ||
+ (equal(item2, left) && equal(item1, right)))
+ {
+ /* found a matching clause */
+ if (delete_it)
+ {
+ if (lnext(relids) == NIL)
+ {
+ /* delete it from local restrictinfo list */
+ rel1->baserestrictinfo = lremove(restrictinfo,
+ rel1->baserestrictinfo);
+ }
+ else
+ {
+ /* let joininfo.c do it */
+ remove_join_clause_from_rels(root, restrictinfo, relids);
+ }
+ }
+ return; /* done */
+ }
+ }
+
+ /* Didn't find it. Done if deletion requested */
+ if (delete_it)
return;
/*
@@ -692,73 +707,7 @@ process_implied_equality(Query *root, Node *item1, Node *item2,
*/
distribute_qual_to_rels(root, (Node *) clause,
true, false, true,
- pull_varnos((Node *) clause));
-}
-
-/*
- * exprs_known_equal
- * Detect whether two expressions are known equal due to equijoin clauses.
- *
- * This is not completely accurate since we avoid adding redundant restriction
- * clauses to individual base rels (see qual_is_redundant). However, after
- * the implied-equality-deduction phase, it is complete for expressions
- * involving Vars of multiple rels; that's sufficient for planned uses.
- */
-bool
-exprs_known_equal(Query *root, Node *item1, Node *item2)
-{
- List *relids;
- RelOptInfo *rel1;
- List *restrictlist;
- List *itm;
-
- /* Get list of relids referenced in the two expressions */
- relids = set_unioni(pull_varnos(item1), pull_varnos(item2));
-
- /*
- * If there are no Vars at all, say "true". This prevents
- * process_implied_equality from trying to store "const = const"
- * deductions.
- */
- if (relids == NIL)
- return true;
-
- /*
- * If the exprs involve a single rel, we need to look at that rel's
- * baserestrictinfo list. If multiple rels, any one will have a
- * joininfo node for the rest, and we can scan any of 'em.
- */
- rel1 = find_base_rel(root, lfirsti(relids));
- relids = lnext(relids);
- if (relids == NIL)
- restrictlist = rel1->baserestrictinfo;
- else
- {
- JoinInfo *joininfo = find_joininfo_node(rel1, relids);
-
- restrictlist = joininfo ? joininfo->jinfo_restrictinfo : NIL;
- }
-
- /*
- * Scan to see if equality is known.
- */
- foreach(itm, restrictlist)
- {
- RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(itm);
- Node *left,
- *right;
-
- if (restrictinfo->mergejoinoperator == InvalidOid)
- continue; /* ignore non-mergejoinable clauses */
- /* We now know the restrictinfo clause is a binary opclause */
- left = get_leftop(restrictinfo->clause);
- right = get_rightop(restrictinfo->clause);
- if ((equal(item1, left) && equal(item2, right)) ||
- (equal(item2, left) && equal(item1, right)))
- return true; /* found a matching clause */
- }
-
- return false;
+ relids);
}
/*
@@ -770,19 +719,32 @@ exprs_known_equal(Query *root, Node *item1, Node *item2)
* SELECT * FROM tab WHERE f1 = f2 AND f2 = f3;
* We need to suppress the redundant condition to avoid computing
* too-small selectivity, not to mention wasting time at execution.
+ *
+ * Note: quals of the form "var = const" are never considered redundant,
+ * only those of the form "var = var". This is needed because when we
+ * have constants in an implied-equality set, we use a different strategy
+ * that suppresses all "var = var" deductions. We must therefore keep
+ * all the "var = const" quals.
*/
static bool
qual_is_redundant(Query *root,
RestrictInfo *restrictinfo,
List *restrictlist)
{
- List *oldquals;
- List *olditem;
Node *newleft;
Node *newright;
+ List *oldquals;
+ List *olditem;
List *equalexprs;
bool someadded;
+ newleft = get_leftop(restrictinfo->clause);
+ newright = get_rightop(restrictinfo->clause);
+
+ /* Never redundant unless vars appear on both sides */
+ if (!contain_var_clause(newleft) || !contain_var_clause(newright))
+ return false;
+
/*
* Set cached pathkeys. NB: it is okay to do this now because this
* routine is only invoked while we are generating implied equalities.
@@ -822,8 +784,6 @@ qual_is_redundant(Query *root,
* we find we can reach the right-side expr of the new qual, we are
* done. We give up when we can't expand the equalexprs list any more.
*/
- newleft = get_leftop(restrictinfo->clause);
- newright = get_rightop(restrictinfo->clause);
equalexprs = makeList1(newleft);
do
{